Blame read_config_file.c

Packit 0021fb
/*
Packit 0021fb
 * This file is part of ltrace.
Packit 0021fb
 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
Packit 0021fb
 * Copyright (C) 1998,1999,2003,2007,2008,2009 Juan Cespedes
Packit 0021fb
 * Copyright (C) 2006 Ian Wienand
Packit 0021fb
 * Copyright (C) 2006 Steve Fink
Packit 0021fb
 *
Packit 0021fb
 * This program is free software; you can redistribute it and/or
Packit 0021fb
 * modify it under the terms of the GNU General Public License as
Packit 0021fb
 * published by the Free Software Foundation; either version 2 of the
Packit 0021fb
 * License, or (at your option) any later version.
Packit 0021fb
 *
Packit 0021fb
 * This program is distributed in the hope that it will be useful, but
Packit 0021fb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0021fb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0021fb
 * General Public License for more details.
Packit 0021fb
 *
Packit 0021fb
 * You should have received a copy of the GNU General Public License
Packit 0021fb
 * along with this program; if not, write to the Free Software
Packit 0021fb
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
Packit 0021fb
 * 02110-1301 USA
Packit 0021fb
 */
Packit 0021fb
Packit 0021fb
/* getline is POSIX.1-2008.  It was originally a GNU extension, and
Packit 0021fb
 * chances are uClibc still needs _GNU_SOURCE, but for now try it this
Packit 0021fb
 * way.  */
Packit 0021fb
#define _POSIX_C_SOURCE 200809L
Packit 0021fb
Packit 0021fb
#include "config.h"
Packit 0021fb
Packit 0021fb
#include <string.h>
Packit 0021fb
#include <stdlib.h>
Packit 0021fb
#include <ctype.h>
Packit 0021fb
#include <errno.h>
Packit 0021fb
#include <assert.h>
Packit 0021fb
Packit 0021fb
#include "common.h"
Packit 0021fb
#include "output.h"
Packit 0021fb
#include "expr.h"
Packit 0021fb
#include "param.h"
Packit 0021fb
#include "printf.h"
Packit 0021fb
#include "prototype.h"
Packit 0021fb
#include "zero.h"
Packit 0021fb
#include "type.h"
Packit 0021fb
#include "lens.h"
Packit 0021fb
#include "lens_default.h"
Packit 0021fb
#include "lens_enum.h"
Packit 0021fb
Packit 0021fb
/* Lifted from GCC: The ctype functions are often implemented as
Packit 0021fb
 * macros which do lookups in arrays using the parameter as the
Packit 0021fb
 * offset.  If the ctype function parameter is a char, then gcc will
Packit 0021fb
 * (appropriately) warn that a "subscript has type char".  Using a
Packit 0021fb
 * (signed) char as a subscript is bad because you may get negative
Packit 0021fb
 * offsets and thus it is not 8-bit safe.  The CTYPE_CONV macro
Packit 0021fb
 * ensures that the parameter is cast to an unsigned char when a char
Packit 0021fb
 * is passed in.  When an int is passed in, the parameter is left
Packit 0021fb
 * alone so we don't lose EOF.  */
Packit 0021fb
Packit 0021fb
#define CTYPE_CONV(CH) \
Packit 0021fb
  (sizeof(CH) == sizeof(unsigned char) ? (int)(unsigned char)(CH) : (int)(CH))
Packit 0021fb
Packit 0021fb
struct locus
Packit 0021fb
{
Packit 0021fb
	const char *filename;
Packit 0021fb
	int line_no;
Packit 0021fb
};
Packit 0021fb
Packit 0021fb
static struct arg_type_info *parse_nonpointer_type(struct protolib *plib,
Packit 0021fb
						   struct locus *loc,
Packit 0021fb
						   char **str,
Packit 0021fb
						   struct param **extra_param,
Packit 0021fb
						   size_t param_num,
Packit 0021fb
						   int *ownp, int *forwardp);
Packit 0021fb
static struct arg_type_info *parse_type(struct protolib *plib,
Packit 0021fb
					struct locus *loc,
Packit 0021fb
					char **str, struct param **extra_param,
Packit 0021fb
					size_t param_num, int *ownp,
Packit 0021fb
					int *forwardp);
Packit 0021fb
static struct arg_type_info *parse_lens(struct protolib *plib,
Packit 0021fb
					struct locus *loc,
Packit 0021fb
					char **str, struct param **extra_param,
Packit 0021fb
					size_t param_num, int *ownp,
Packit 0021fb
					int *forwardp);
Packit 0021fb
static int parse_enum(struct protolib *plib, struct locus *loc,
Packit 0021fb
		      char **str, struct arg_type_info **retp, int *ownp);
Packit 0021fb
Packit 0021fb
struct prototype *list_of_functions = NULL;
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
parse_arg_type(char **name, enum arg_type *ret)
Packit 0021fb
{
Packit 0021fb
	char *rest = NULL;
Packit 0021fb
	enum arg_type candidate;
Packit 0021fb
Packit 0021fb
#define KEYWORD(KWD, TYPE)						\
Packit 0021fb
	do {								\
Packit 0021fb
		if (strncmp(*name, KWD, sizeof(KWD) - 1) == 0) {	\
Packit 0021fb
			rest = *name + sizeof(KWD) - 1;			\
Packit 0021fb
			candidate = TYPE;				\
Packit 0021fb
			goto ok;					\
Packit 0021fb
		}							\
Packit 0021fb
	} while (0)
Packit 0021fb
Packit 0021fb
	KEYWORD("void", ARGTYPE_VOID);
Packit 0021fb
	KEYWORD("int", ARGTYPE_INT);
Packit 0021fb
	KEYWORD("uint", ARGTYPE_UINT);
Packit 0021fb
	KEYWORD("long", ARGTYPE_LONG);
Packit 0021fb
	KEYWORD("ulong", ARGTYPE_ULONG);
Packit 0021fb
	KEYWORD("char", ARGTYPE_CHAR);
Packit 0021fb
	KEYWORD("short", ARGTYPE_SHORT);
Packit 0021fb
	KEYWORD("ushort", ARGTYPE_USHORT);
Packit 0021fb
	KEYWORD("float", ARGTYPE_FLOAT);
Packit 0021fb
	KEYWORD("double", ARGTYPE_DOUBLE);
Packit 0021fb
	KEYWORD("array", ARGTYPE_ARRAY);
Packit 0021fb
	KEYWORD("struct", ARGTYPE_STRUCT);
Packit 0021fb
Packit 0021fb
	/* Misspelling of int used in ltrace.conf that we used to
Packit 0021fb
	 * ship.  */
Packit 0021fb
	KEYWORD("itn", ARGTYPE_INT);
Packit 0021fb
Packit 0021fb
	assert(rest == NULL);
Packit 0021fb
	return -1;
Packit 0021fb
Packit 0021fb
#undef KEYWORD
Packit 0021fb
Packit 0021fb
ok:
Packit 0021fb
	if (isalnum(CTYPE_CONV(*rest)) || *rest == '_')
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	*name = rest;
Packit 0021fb
	*ret = candidate;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static void
Packit 0021fb
eat_spaces(char **str) {
Packit 0021fb
	while (**str == ' ') {
Packit 0021fb
		(*str)++;
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static char *
Packit 0021fb
xstrndup(char *str, size_t len) {
Packit 0021fb
	char *ret = (char *) malloc(len + 1);
Packit 0021fb
	if (ret == NULL) {
Packit 0021fb
		report_global_error("malloc: %s", strerror(errno));
Packit 0021fb
		return NULL;
Packit 0021fb
	}
Packit 0021fb
	strncpy(ret, str, len);
Packit 0021fb
	ret[len] = 0;
Packit 0021fb
	return ret;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static char *
Packit 0021fb
parse_ident(struct locus *loc, char **str)
Packit 0021fb
{
Packit 0021fb
	char *ident = *str;
Packit 0021fb
Packit 0021fb
	if (!isalpha(CTYPE_CONV(**str)) && **str != '_') {
Packit 0021fb
		report_error(loc->filename, loc->line_no, "bad identifier");
Packit 0021fb
		return NULL;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	while (**str && (isalnum(CTYPE_CONV(**str)) || **str == '_')) {
Packit 0021fb
		++(*str);
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return xstrndup(ident, *str - ident);
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/*
Packit 0021fb
  Returns position in string at the left parenthesis which starts the
Packit 0021fb
  function's argument signature. Returns NULL on error.
Packit 0021fb
*/
Packit 0021fb
static char *
Packit 0021fb
start_of_arg_sig(char *str) {
Packit 0021fb
	char *pos;
Packit 0021fb
	int stacked = 0;
Packit 0021fb
Packit 0021fb
	if (!strlen(str))
Packit 0021fb
		return NULL;
Packit 0021fb
Packit 0021fb
	pos = &str[strlen(str)];
Packit 0021fb
	do {
Packit 0021fb
		pos--;
Packit 0021fb
		if (pos < str)
Packit 0021fb
			return NULL;
Packit 0021fb
		while ((pos > str) && (*pos != ')') && (*pos != '('))
Packit 0021fb
			pos--;
Packit 0021fb
Packit 0021fb
		if (*pos == ')')
Packit 0021fb
			stacked++;
Packit 0021fb
		else if (*pos == '(')
Packit 0021fb
			stacked--;
Packit 0021fb
		else
Packit 0021fb
			return NULL;
Packit 0021fb
Packit 0021fb
	} while (stacked > 0);
Packit 0021fb
Packit 0021fb
	return (stacked == 0) ? pos : NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
parse_int(struct locus *loc, char **str, long *ret)
Packit 0021fb
{
Packit 0021fb
	char *end;
Packit 0021fb
	long n = strtol(*str, &end, 0);
Packit 0021fb
	if (end == *str) {
Packit 0021fb
		report_error(loc->filename, loc->line_no, "bad number");
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	*str = end;
Packit 0021fb
	if (ret != NULL)
Packit 0021fb
		*ret = n;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
check_nonnegative(struct locus *loc, long l)
Packit 0021fb
{
Packit 0021fb
	if (l < 0) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "expected non-negative value, got %ld", l);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
check_int(struct locus *loc, long l)
Packit 0021fb
{
Packit 0021fb
	int i = l;
Packit 0021fb
	if ((long)i != l) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "Number too large: %ld", l);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
parse_char(struct locus *loc, char **str, char expected)
Packit 0021fb
{
Packit 0021fb
	if (**str != expected) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "expected '%c', got '%c'", expected, **str);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	++*str;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct expr_node *parse_argnum(struct locus *loc,
Packit 0021fb
				      char **str, int *ownp, int zero);
Packit 0021fb
Packit 0021fb
static struct expr_node *
Packit 0021fb
parse_zero(struct locus *loc, char **str, int *ownp)
Packit 0021fb
{
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	if (**str == '(') {
Packit 0021fb
		++*str;
Packit 0021fb
		int own;
Packit 0021fb
		struct expr_node *arg = parse_argnum(loc, str, &own, 0);
Packit 0021fb
		if (arg == NULL)
Packit 0021fb
			return NULL;
Packit 0021fb
		if (parse_char(loc, str, ')') < 0) {
Packit 0021fb
		fail:
Packit 0021fb
			expr_destroy(arg);
Packit 0021fb
			free(arg);
Packit 0021fb
			return NULL;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		struct expr_node *ret = build_zero_w_arg(arg, own);
Packit 0021fb
		if (ret == NULL)
Packit 0021fb
			goto fail;
Packit 0021fb
		*ownp = 1;
Packit 0021fb
		return ret;
Packit 0021fb
Packit 0021fb
	} else {
Packit 0021fb
		*ownp = 0;
Packit 0021fb
		return expr_node_zero();
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
wrap_in_zero(struct expr_node **nodep)
Packit 0021fb
{
Packit 0021fb
	struct expr_node *n = build_zero_w_arg(*nodep, 1);
Packit 0021fb
	if (n == NULL)
Packit 0021fb
		return -1;
Packit 0021fb
	*nodep = n;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/*
Packit 0021fb
 * Input:
Packit 0021fb
 *  argN   : The value of argument #N, counting from 1
Packit 0021fb
 *  eltN   : The value of element #N of the containing structure
Packit 0021fb
 *  retval : The return value
Packit 0021fb
 *  N      : The numeric value N
Packit 0021fb
 */
Packit 0021fb
static struct expr_node *
Packit 0021fb
parse_argnum(struct locus *loc, char **str, int *ownp, int zero)
Packit 0021fb
{
Packit 0021fb
	struct expr_node *expr = malloc(sizeof(*expr));
Packit 0021fb
	if (expr == NULL)
Packit 0021fb
		return NULL;
Packit 0021fb
Packit 0021fb
	if (isdigit(CTYPE_CONV(**str))) {
Packit 0021fb
		long l;
Packit 0021fb
		if (parse_int(loc, str, &l) < 0
Packit 0021fb
		    || check_nonnegative(loc, l) < 0
Packit 0021fb
		    || check_int(loc, l) < 0)
Packit 0021fb
			goto fail;
Packit 0021fb
Packit 0021fb
		expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0);
Packit 0021fb
Packit 0021fb
		if (zero && wrap_in_zero(&expr) < 0)
Packit 0021fb
			goto fail;
Packit 0021fb
Packit 0021fb
		*ownp = 1;
Packit 0021fb
		return expr;
Packit 0021fb
Packit 0021fb
	} else {
Packit 0021fb
		char *const name = parse_ident(loc, str);
Packit 0021fb
		if (name == NULL) {
Packit 0021fb
		fail_ident:
Packit 0021fb
			free(name);
Packit 0021fb
			goto fail;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		int is_arg = strncmp(name, "arg", 3) == 0;
Packit 0021fb
		if (is_arg || strncmp(name, "elt", 3) == 0) {
Packit 0021fb
			long l;
Packit 0021fb
			char *num = name + 3;
Packit 0021fb
			if (parse_int(loc, &num, &l) < 0
Packit 0021fb
			    || check_int(loc, l) < 0)
Packit 0021fb
				goto fail_ident;
Packit 0021fb
Packit 0021fb
			if (is_arg) {
Packit 0021fb
				if (l == 0)
Packit 0021fb
					expr_init_named(expr, "retval", 0);
Packit 0021fb
				else
Packit 0021fb
					expr_init_argno(expr, l - 1);
Packit 0021fb
			} else {
Packit 0021fb
				struct expr_node *e_up = malloc(sizeof(*e_up));
Packit 0021fb
				struct expr_node *e_ix = malloc(sizeof(*e_ix));
Packit 0021fb
				if (e_up == NULL || e_ix == NULL) {
Packit 0021fb
					free(e_up);
Packit 0021fb
					free(e_ix);
Packit 0021fb
					goto fail_ident;
Packit 0021fb
				}
Packit 0021fb
Packit 0021fb
				expr_init_up(e_up, expr_self(), 0);
Packit 0021fb
				struct arg_type_info *ti
Packit 0021fb
					= type_get_simple(ARGTYPE_LONG);
Packit 0021fb
				expr_init_const_word(e_ix, l - 1, ti, 0);
Packit 0021fb
				expr_init_index(expr, e_up, 1, e_ix, 1);
Packit 0021fb
			}
Packit 0021fb
Packit 0021fb
		} else if (strcmp(name, "retval") == 0) {
Packit 0021fb
			expr_init_named(expr, "retval", 0);
Packit 0021fb
Packit 0021fb
		} else if (strcmp(name, "zero") == 0) {
Packit 0021fb
			struct expr_node *ret
Packit 0021fb
				= parse_zero(loc, str, ownp);
Packit 0021fb
			if (ret == NULL)
Packit 0021fb
				goto fail_ident;
Packit 0021fb
			free(expr);
Packit 0021fb
			free(name);
Packit 0021fb
			return ret;
Packit 0021fb
Packit 0021fb
		} else {
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "Unknown length specifier: '%s'", name);
Packit 0021fb
			goto fail_ident;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		if (zero && wrap_in_zero(&expr) < 0)
Packit 0021fb
			goto fail_ident;
Packit 0021fb
Packit 0021fb
		free(name);
Packit 0021fb
		*ownp = 1;
Packit 0021fb
		return expr;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
fail:
Packit 0021fb
	free(expr);
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct arg_type_info *
Packit 0021fb
parse_typedef_name(struct protolib *plib, char **str)
Packit 0021fb
{
Packit 0021fb
	char *end = *str;
Packit 0021fb
	while (*end && (isalnum(CTYPE_CONV(*end)) || *end == '_'))
Packit 0021fb
		++end;
Packit 0021fb
	if (end == *str)
Packit 0021fb
		return NULL;
Packit 0021fb
Packit 0021fb
	size_t len = end - *str;
Packit 0021fb
	char buf[len + 1];
Packit 0021fb
	memcpy(buf, *str, len);
Packit 0021fb
	*str += len;
Packit 0021fb
	buf[len] = 0;
Packit 0021fb
Packit 0021fb
	struct named_type *nt = protolib_lookup_type(plib, buf, true);
Packit 0021fb
	if (nt == NULL)
Packit 0021fb
		return NULL;
Packit 0021fb
	return nt->info;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
parse_typedef(struct protolib *plib, struct locus *loc, char **str)
Packit 0021fb
{
Packit 0021fb
	(*str) += strlen("typedef");
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	char *name = parse_ident(loc, str);
Packit 0021fb
Packit 0021fb
	/* Look through the typedef list whether we already have a
Packit 0021fb
	 * forward of this type.  If we do, it must be forward
Packit 0021fb
	 * structure.  */
Packit 0021fb
	struct named_type *forward = protolib_lookup_type(plib, name, true);
Packit 0021fb
	if (forward != NULL
Packit 0021fb
	    && (forward->info->type != ARGTYPE_STRUCT
Packit 0021fb
		|| !forward->forward)) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "Redefinition of typedef '%s'", name);
Packit 0021fb
	err:
Packit 0021fb
		free(name);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	// Skip = sign
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	if (parse_char(loc, str, '=') < 0)
Packit 0021fb
		goto err;
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
Packit 0021fb
	int fwd = 0;
Packit 0021fb
	int own = 0;
Packit 0021fb
	struct arg_type_info *info
Packit 0021fb
		= parse_lens(plib, loc, str, NULL, 0, &own, &fwd);
Packit 0021fb
	if (info == NULL)
Packit 0021fb
		goto err;
Packit 0021fb
Packit 0021fb
	struct named_type this_nt;
Packit 0021fb
	named_type_init(&this_nt, info, own);
Packit 0021fb
	this_nt.forward = fwd;
Packit 0021fb
Packit 0021fb
	if (forward == NULL) {
Packit 0021fb
		if (protolib_add_named_type(plib, name, 1, &this_nt) < 0) {
Packit 0021fb
			named_type_destroy(&this_nt);
Packit 0021fb
			goto err;
Packit 0021fb
		}
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* If we are defining a forward, make sure the definition is a
Packit 0021fb
	 * structure as well.  */
Packit 0021fb
	if (this_nt.info->type != ARGTYPE_STRUCT) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "Definition of forward '%s' must be a structure.",
Packit 0021fb
			     name);
Packit 0021fb
		named_type_destroy(&this_nt);
Packit 0021fb
		goto err;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* Now move guts of the actual type over to the forward type.
Packit 0021fb
	 * We can't just move pointers around, because references to
Packit 0021fb
	 * forward must stay intact.  */
Packit 0021fb
	assert(this_nt.own_type);
Packit 0021fb
	type_destroy(forward->info);
Packit 0021fb
	*forward->info = *this_nt.info;
Packit 0021fb
	forward->forward = 0;
Packit 0021fb
	free(this_nt.info);
Packit 0021fb
	free(name);
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* Syntax: struct ( type,type,type,... ) */
Packit 0021fb
static int
Packit 0021fb
parse_struct(struct protolib *plib, struct locus *loc,
Packit 0021fb
	     char **str, struct arg_type_info *info,
Packit 0021fb
	     int *forwardp)
Packit 0021fb
{
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
Packit 0021fb
	if (**str == ';') {
Packit 0021fb
		if (forwardp == NULL) {
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "Forward struct can be declared only "
Packit 0021fb
				     "directly after a typedef.");
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		/* Forward declaration is currently handled as an
Packit 0021fb
		 * empty struct.  */
Packit 0021fb
		type_init_struct(info);
Packit 0021fb
		*forwardp = 1;
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (parse_char(loc, str, '(') < 0)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	eat_spaces(str); // Empty arg list with whitespace inside
Packit 0021fb
Packit 0021fb
	type_init_struct(info);
Packit 0021fb
Packit 0021fb
	while (1) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		if (**str == 0 || **str == ')') {
Packit 0021fb
			parse_char(loc, str, ')');
Packit 0021fb
			return 0;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		/* Field delimiter.  */
Packit 0021fb
		if (type_struct_size(info) > 0)
Packit 0021fb
			parse_char(loc, str, ',');
Packit 0021fb
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		int own;
Packit 0021fb
		struct arg_type_info *field
Packit 0021fb
			= parse_lens(plib, loc, str, NULL, 0, &own, NULL);
Packit 0021fb
		if (field == NULL || type_struct_add(info, field, own)) {
Packit 0021fb
			type_destroy(info);
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* Make a copy of INFO and set the *OWN bit if it's not already
Packit 0021fb
 * owned.  */
Packit 0021fb
static int
Packit 0021fb
unshare_type_info(struct locus *loc, struct arg_type_info **infop, int *ownp)
Packit 0021fb
{
Packit 0021fb
	if (*ownp)
Packit 0021fb
		return 0;
Packit 0021fb
Packit 0021fb
	struct arg_type_info *ninfo = malloc(sizeof(*ninfo));
Packit 0021fb
	if (ninfo == NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "malloc: %s", strerror(errno));
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	*ninfo = **infop;
Packit 0021fb
	*infop = ninfo;
Packit 0021fb
	*ownp = 1;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
parse_string(struct protolib *plib, struct locus *loc,
Packit 0021fb
	     char **str, struct arg_type_info **retp, int *ownp)
Packit 0021fb
{
Packit 0021fb
	struct arg_type_info *info = NULL;
Packit 0021fb
	struct expr_node *length;
Packit 0021fb
	int own_length;
Packit 0021fb
Packit 0021fb
	if (isdigit(CTYPE_CONV(**str))) {
Packit 0021fb
		/* string0 is string[retval], length is zero(retval)
Packit 0021fb
		 * stringN is string[argN], length is zero(argN) */
Packit 0021fb
		long l;
Packit 0021fb
		if (parse_int(loc, str, &l) < 0
Packit 0021fb
		    || check_int(loc, l) < 0)
Packit 0021fb
			return -1;
Packit 0021fb
Packit 0021fb
		struct expr_node *length_arg = malloc(sizeof(*length_arg));
Packit 0021fb
		if (length_arg == NULL)
Packit 0021fb
			return -1;
Packit 0021fb
Packit 0021fb
		if (l == 0)
Packit 0021fb
			expr_init_named(length_arg, "retval", 0);
Packit 0021fb
		else
Packit 0021fb
			expr_init_argno(length_arg, l - 1);
Packit 0021fb
Packit 0021fb
		length = build_zero_w_arg(length_arg, 1);
Packit 0021fb
		if (length == NULL) {
Packit 0021fb
			expr_destroy(length_arg);
Packit 0021fb
			free(length_arg);
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
		own_length = 1;
Packit 0021fb
Packit 0021fb
	} else {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		if (**str == '[') {
Packit 0021fb
			(*str)++;
Packit 0021fb
			eat_spaces(str);
Packit 0021fb
Packit 0021fb
			length = parse_argnum(loc, str, &own_length, 1);
Packit 0021fb
			if (length == NULL)
Packit 0021fb
				return -1;
Packit 0021fb
Packit 0021fb
			eat_spaces(str);
Packit 0021fb
			parse_char(loc, str, ']');
Packit 0021fb
Packit 0021fb
		} else if (**str == '(') {
Packit 0021fb
			/* Usage of "string" as lens.  */
Packit 0021fb
			++*str;
Packit 0021fb
Packit 0021fb
			eat_spaces(str);
Packit 0021fb
			info = parse_type(plib, loc, str, NULL, 0, ownp, NULL);
Packit 0021fb
			if (info == NULL)
Packit 0021fb
				return -1;
Packit 0021fb
Packit 0021fb
			length = NULL;
Packit 0021fb
			own_length = 0;
Packit 0021fb
Packit 0021fb
			eat_spaces(str);
Packit 0021fb
			parse_char(loc, str, ')');
Packit 0021fb
Packit 0021fb
		} else {
Packit 0021fb
			/* It was just a simple string after all.  */
Packit 0021fb
			length = expr_node_zero();
Packit 0021fb
			own_length = 0;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* String is a pointer to array of chars.  */
Packit 0021fb
	if (info == NULL) {
Packit 0021fb
		struct arg_type_info *info1 = malloc(sizeof(*info1));
Packit 0021fb
		struct arg_type_info *info2 = malloc(sizeof(*info2));
Packit 0021fb
		if (info1 == NULL || info2 == NULL) {
Packit 0021fb
			free(info1);
Packit 0021fb
			free(info2);
Packit 0021fb
		fail:
Packit 0021fb
			if (own_length) {
Packit 0021fb
				assert(length != NULL);
Packit 0021fb
				expr_destroy(length);
Packit 0021fb
				free(length);
Packit 0021fb
			}
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
		type_init_array(info2, type_get_simple(ARGTYPE_CHAR), 0,
Packit 0021fb
				length, own_length);
Packit 0021fb
		type_init_pointer(info1, info2, 1);
Packit 0021fb
Packit 0021fb
		info = info1;
Packit 0021fb
		*ownp = 1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* We'll need to set the lens, so unshare.  */
Packit 0021fb
	if (unshare_type_info(loc, &info, ownp) < 0)
Packit 0021fb
		/* If unshare_type_info failed, it must have been as a
Packit 0021fb
		 * result of cloning attempt because *OWNP was 0.
Packit 0021fb
		 * Thus we don't need to destroy INFO.  */
Packit 0021fb
		goto fail;
Packit 0021fb
Packit 0021fb
	info->lens = &string_lens;
Packit 0021fb
	info->own_lens = 0;
Packit 0021fb
Packit 0021fb
	*retp = info;
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
build_printf_pack(struct locus *loc, struct param **packp, size_t param_num)
Packit 0021fb
{
Packit 0021fb
	if (packp == NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "'format' type in unexpected context");
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	if (*packp != NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "only one 'format' type per function supported");
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	*packp = malloc(sizeof(**packp));
Packit 0021fb
	if (*packp == NULL)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	struct expr_node *node = malloc(sizeof(*node));
Packit 0021fb
	if (node == NULL) {
Packit 0021fb
		free(*packp);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	expr_init_argno(node, param_num);
Packit 0021fb
Packit 0021fb
	param_pack_init_printf(*packp, node, 1);
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* Match and consume KWD if it's next in stream, and return 0.
Packit 0021fb
 * Otherwise return negative number.  */
Packit 0021fb
static int
Packit 0021fb
try_parse_kwd(char **str, const char *kwd)
Packit 0021fb
{
Packit 0021fb
	size_t len = strlen(kwd);
Packit 0021fb
	if (strncmp(*str, kwd, len) == 0
Packit 0021fb
	    && !isalnum(CTYPE_CONV((*str)[len]))) {
Packit 0021fb
		(*str) += len;
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
	return -1;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* XXX extra_param and param_num are a kludge to get in
Packit 0021fb
 * backward-compatible support for "format" parameter type.  The
Packit 0021fb
 * latter is only valid if the former is non-NULL, which is only in
Packit 0021fb
 * top-level context.  */
Packit 0021fb
static int
Packit 0021fb
parse_alias(struct protolib *plib, struct locus *loc,
Packit 0021fb
	    char **str, struct arg_type_info **retp, int *ownp,
Packit 0021fb
	    struct param **extra_param, size_t param_num)
Packit 0021fb
{
Packit 0021fb
	/* For backward compatibility, we need to support things like
Packit 0021fb
	 * stringN (which is like string[argN], string[N], and also
Packit 0021fb
	 * bare string.  We might, in theory, replace this by
Packit 0021fb
	 * preprocessing configure file sources with M4, but for now,
Packit 0021fb
	 * "string" is syntax.  */
Packit 0021fb
	if (strncmp(*str, "string", 6) == 0) {
Packit 0021fb
		(*str) += 6;
Packit 0021fb
		return parse_string(plib, loc, str, retp, ownp);
Packit 0021fb
Packit 0021fb
	} else if (try_parse_kwd(str, "format") >= 0
Packit 0021fb
		   && extra_param != NULL) {
Packit 0021fb
		/* For backward compatibility, format is parsed as
Packit 0021fb
		 * "string", but it smuggles to the parameter list of
Packit 0021fb
		 * a function a "printf" argument pack with this
Packit 0021fb
		 * parameter as argument.  */
Packit 0021fb
		if (parse_string(plib, loc, str, retp, ownp) < 0)
Packit 0021fb
			return -1;
Packit 0021fb
Packit 0021fb
		return build_printf_pack(loc, extra_param, param_num);
Packit 0021fb
Packit 0021fb
	} else if (try_parse_kwd(str, "enum") >=0) {
Packit 0021fb
Packit 0021fb
		return parse_enum(plib, loc, str, retp, ownp);
Packit 0021fb
Packit 0021fb
	} else {
Packit 0021fb
		*retp = NULL;
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* Syntax: array ( type, N|argN ) */
Packit 0021fb
static int
Packit 0021fb
parse_array(struct protolib *plib, struct locus *loc,
Packit 0021fb
	    char **str, struct arg_type_info *info)
Packit 0021fb
{
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	if (parse_char(loc, str, '(') < 0)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	int own;
Packit 0021fb
	struct arg_type_info *elt_info
Packit 0021fb
		= parse_lens(plib, loc, str, NULL, 0, &own, NULL);
Packit 0021fb
	if (elt_info == NULL)
Packit 0021fb
		return -1;
Packit 0021fb
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	parse_char(loc, str, ',');
Packit 0021fb
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	int own_length;
Packit 0021fb
	struct expr_node *length = parse_argnum(loc, str, &own_length, 0);
Packit 0021fb
	if (length == NULL) {
Packit 0021fb
		if (own) {
Packit 0021fb
			type_destroy(elt_info);
Packit 0021fb
			free(elt_info);
Packit 0021fb
		}
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	type_init_array(info, elt_info, own, length, own_length);
Packit 0021fb
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	parse_char(loc, str, ')');
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
/* Syntax:
Packit 0021fb
 *   enum (keyname[=value],keyname[=value],... )
Packit 0021fb
 *   enum<type> (keyname[=value],keyname[=value],... )
Packit 0021fb
 */
Packit 0021fb
static int
Packit 0021fb
parse_enum(struct protolib *plib, struct locus *loc, char **str,
Packit 0021fb
	   struct arg_type_info **retp, int *ownp)
Packit 0021fb
{
Packit 0021fb
	/* Optional type argument.  */
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	if (**str == '[') {
Packit 0021fb
		parse_char(loc, str, '[');
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		*retp = parse_nonpointer_type(plib, loc, str, NULL, 0, ownp, 0);
Packit 0021fb
		if (*retp == NULL)
Packit 0021fb
			return -1;
Packit 0021fb
Packit 0021fb
		if (!type_is_integral((*retp)->type)) {
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "integral type required as enum argument");
Packit 0021fb
		fail:
Packit 0021fb
			if (*ownp) {
Packit 0021fb
				/* This also releases associated lens
Packit 0021fb
				 * if any was set so far.  */
Packit 0021fb
				type_destroy(*retp);
Packit 0021fb
				free(*retp);
Packit 0021fb
			}
Packit 0021fb
			return -1;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		if (parse_char(loc, str, ']') < 0)
Packit 0021fb
			goto fail;
Packit 0021fb
Packit 0021fb
	} else {
Packit 0021fb
		*retp = type_get_simple(ARGTYPE_INT);
Packit 0021fb
		*ownp = 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* We'll need to set the lens, so unshare.  */
Packit 0021fb
	if (unshare_type_info(loc, retp, ownp) < 0)
Packit 0021fb
		goto fail;
Packit 0021fb
Packit 0021fb
	eat_spaces(str);
Packit 0021fb
	if (parse_char(loc, str, '(') < 0)
Packit 0021fb
		goto fail;
Packit 0021fb
Packit 0021fb
	struct enum_lens *lens = malloc(sizeof(*lens));
Packit 0021fb
	if (lens == NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "malloc enum lens: %s", strerror(errno));
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	lens_init_enum(lens);
Packit 0021fb
	(*retp)->lens = &lens->super;
Packit 0021fb
	(*retp)->own_lens = 1;
Packit 0021fb
Packit 0021fb
	long last_val = 0;
Packit 0021fb
	while (1) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		if (**str == 0 || **str == ')') {
Packit 0021fb
			parse_char(loc, str, ')');
Packit 0021fb
			return 0;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		/* Field delimiter.  XXX should we support the C
Packit 0021fb
		 * syntax, where the enumeration can end in pending
Packit 0021fb
		 * comma?  */
Packit 0021fb
		if (lens_enum_size(lens) > 0)
Packit 0021fb
			parse_char(loc, str, ',');
Packit 0021fb
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		char *key = parse_ident(loc, str);
Packit 0021fb
		if (key == NULL) {
Packit 0021fb
		err:
Packit 0021fb
			free(key);
Packit 0021fb
			goto fail;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		if (**str == '=') {
Packit 0021fb
			++*str;
Packit 0021fb
			eat_spaces(str);
Packit 0021fb
			if (parse_int(loc, str, &last_val) < 0)
Packit 0021fb
				goto err;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		struct value *value = malloc(sizeof(*value));
Packit 0021fb
		if (value == NULL)
Packit 0021fb
			goto err;
Packit 0021fb
		value_init_detached(value, NULL, *retp, 0);
Packit 0021fb
		value_set_word(value, last_val);
Packit 0021fb
Packit 0021fb
		if (lens_enum_add(lens, key, 1, value, 1) < 0)
Packit 0021fb
			goto err;
Packit 0021fb
Packit 0021fb
		last_val++;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct arg_type_info *
Packit 0021fb
parse_nonpointer_type(struct protolib *plib, struct locus *loc,
Packit 0021fb
		      char **str, struct param **extra_param, size_t param_num,
Packit 0021fb
		      int *ownp, int *forwardp)
Packit 0021fb
{
Packit 0021fb
	const char *orig_str = *str;
Packit 0021fb
	enum arg_type type;
Packit 0021fb
	if (parse_arg_type(str, &type) < 0) {
Packit 0021fb
		struct arg_type_info *type;
Packit 0021fb
		if (parse_alias(plib, loc, str, &type,
Packit 0021fb
				ownp, extra_param, param_num) < 0)
Packit 0021fb
			return NULL;
Packit 0021fb
		else if (type != NULL)
Packit 0021fb
			return type;
Packit 0021fb
Packit 0021fb
		*ownp = 0;
Packit 0021fb
		if ((type = parse_typedef_name(plib, str)) == NULL)
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "unknown type around '%s'", orig_str);
Packit 0021fb
		return type;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* For some types that's all we need.  */
Packit 0021fb
	switch (type) {
Packit 0021fb
	case ARGTYPE_VOID:
Packit 0021fb
	case ARGTYPE_INT:
Packit 0021fb
	case ARGTYPE_UINT:
Packit 0021fb
	case ARGTYPE_LONG:
Packit 0021fb
	case ARGTYPE_ULONG:
Packit 0021fb
	case ARGTYPE_CHAR:
Packit 0021fb
	case ARGTYPE_SHORT:
Packit 0021fb
	case ARGTYPE_USHORT:
Packit 0021fb
	case ARGTYPE_FLOAT:
Packit 0021fb
	case ARGTYPE_DOUBLE:
Packit 0021fb
		*ownp = 0;
Packit 0021fb
		return type_get_simple(type);
Packit 0021fb
Packit 0021fb
	case ARGTYPE_ARRAY:
Packit 0021fb
	case ARGTYPE_STRUCT:
Packit 0021fb
		break;
Packit 0021fb
Packit 0021fb
	case ARGTYPE_POINTER:
Packit 0021fb
		/* Pointer syntax is not based on keyword, so we
Packit 0021fb
		 * should never get this type.  */
Packit 0021fb
		assert(type != ARGTYPE_POINTER);
Packit 0021fb
		abort();
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	struct arg_type_info *info = malloc(sizeof(*info));
Packit 0021fb
	if (info == NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "malloc: %s", strerror(errno));
Packit 0021fb
		return NULL;
Packit 0021fb
	}
Packit 0021fb
	*ownp = 1;
Packit 0021fb
Packit 0021fb
	if (type == ARGTYPE_ARRAY) {
Packit 0021fb
		if (parse_array(plib, loc, str, info) < 0) {
Packit 0021fb
		fail:
Packit 0021fb
			free(info);
Packit 0021fb
			return NULL;
Packit 0021fb
		}
Packit 0021fb
	} else {
Packit 0021fb
		assert(type == ARGTYPE_STRUCT);
Packit 0021fb
		if (parse_struct(plib, loc, str, info, forwardp) < 0)
Packit 0021fb
			goto fail;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return info;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct named_lens {
Packit 0021fb
	const char *name;
Packit 0021fb
	struct lens *lens;
Packit 0021fb
} lenses[] = {
Packit 0021fb
	{ "hide", &blind_lens },
Packit 0021fb
	{ "octal", &octal_lens },
Packit 0021fb
	{ "oct", &octal_lens },
Packit 0021fb
	{ "bitvec", &bitvect_lens },
Packit 0021fb
	{ "hex", &hex_lens },
Packit 0021fb
	{ "bool", &bool_lens },
Packit 0021fb
	{ "guess", &guess_lens },
Packit 0021fb
};
Packit 0021fb
Packit 0021fb
static struct lens *
Packit 0021fb
name2lens(char **str, int *own_lensp)
Packit 0021fb
{
Packit 0021fb
	size_t i;
Packit 0021fb
	for (i = 0; i < sizeof(lenses)/sizeof(*lenses); ++i)
Packit 0021fb
		if (try_parse_kwd(str, lenses[i].name) == 0) {
Packit 0021fb
			*own_lensp = 0;
Packit 0021fb
			return lenses[i].lens;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
	return NULL;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct arg_type_info *
Packit 0021fb
parse_type(struct protolib *plib, struct locus *loc, char **str,
Packit 0021fb
	   struct param **extra_param, size_t param_num,
Packit 0021fb
	   int *ownp, int *forwardp)
Packit 0021fb
{
Packit 0021fb
	struct arg_type_info *info
Packit 0021fb
		= parse_nonpointer_type(plib, loc, str, extra_param,
Packit 0021fb
					param_num, ownp, forwardp);
Packit 0021fb
	if (info == NULL)
Packit 0021fb
		return NULL;
Packit 0021fb
Packit 0021fb
	while (1) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		if (**str == '*') {
Packit 0021fb
			struct arg_type_info *outer = malloc(sizeof(*outer));
Packit 0021fb
			if (outer == NULL) {
Packit 0021fb
				if (*ownp) {
Packit 0021fb
					type_destroy(info);
Packit 0021fb
					free(info);
Packit 0021fb
				}
Packit 0021fb
				report_error(loc->filename, loc->line_no,
Packit 0021fb
					     "malloc: %s", strerror(errno));
Packit 0021fb
				return NULL;
Packit 0021fb
			}
Packit 0021fb
			type_init_pointer(outer, info, *ownp);
Packit 0021fb
			*ownp = 1;
Packit 0021fb
			(*str)++;
Packit 0021fb
			info = outer;
Packit 0021fb
		} else
Packit 0021fb
			break;
Packit 0021fb
	}
Packit 0021fb
	return info;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct arg_type_info *
Packit 0021fb
parse_lens(struct protolib *plib, struct locus *loc,
Packit 0021fb
	   char **str, struct param **extra_param,
Packit 0021fb
	   size_t param_num, int *ownp, int *forwardp)
Packit 0021fb
{
Packit 0021fb
	int own_lens;
Packit 0021fb
	struct lens *lens = name2lens(str, &own_lens);
Packit 0021fb
	int has_args = 1;
Packit 0021fb
	struct arg_type_info *info;
Packit 0021fb
	if (lens != NULL) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
Packit 0021fb
		/* Octal lens gets special treatment, because of
Packit 0021fb
		 * backward compatibility.  */
Packit 0021fb
		if (lens == &octal_lens && **str != '(') {
Packit 0021fb
			has_args = 0;
Packit 0021fb
			info = type_get_simple(ARGTYPE_INT);
Packit 0021fb
			*ownp = 0;
Packit 0021fb
		} else if (parse_char(loc, str, '(') < 0) {
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "expected type argument after the lens");
Packit 0021fb
			return NULL;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (has_args) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		info = parse_type(plib, loc, str, extra_param, param_num,
Packit 0021fb
				  ownp, forwardp);
Packit 0021fb
		if (info == NULL) {
Packit 0021fb
		fail:
Packit 0021fb
			if (own_lens && lens != NULL)
Packit 0021fb
				lens_destroy(lens);
Packit 0021fb
			return NULL;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (lens != NULL && has_args) {
Packit 0021fb
		eat_spaces(str);
Packit 0021fb
		parse_char(loc, str, ')');
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* We can't modify shared types.  Make a copy if we have a
Packit 0021fb
	 * lens.  */
Packit 0021fb
	if (lens != NULL && unshare_type_info(loc, &info, ownp) < 0)
Packit 0021fb
		goto fail;
Packit 0021fb
Packit 0021fb
	if (lens != NULL) {
Packit 0021fb
		info->lens = lens;
Packit 0021fb
		info->own_lens = own_lens;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return info;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
param_is_void(struct param *param)
Packit 0021fb
{
Packit 0021fb
	return param->flavor == PARAM_FLAVOR_TYPE
Packit 0021fb
		&& param->u.type.type->type == ARGTYPE_VOID;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static struct arg_type_info *
Packit 0021fb
get_hidden_int(void)
Packit 0021fb
{
Packit 0021fb
	static struct arg_type_info info, *pinfo = NULL;
Packit 0021fb
	if (pinfo != NULL)
Packit 0021fb
		return pinfo;
Packit 0021fb
Packit 0021fb
	info = *type_get_simple(ARGTYPE_INT);
Packit 0021fb
	info.lens = &blind_lens;
Packit 0021fb
	pinfo = &info;
Packit 0021fb
Packit 0021fb
	return pinfo;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static enum callback_status
Packit 0021fb
void_to_hidden_int(struct prototype *proto, struct param *param, void *data)
Packit 0021fb
{
Packit 0021fb
	struct locus *loc = data;
Packit 0021fb
	if (param_is_void(param)) {
Packit 0021fb
		report_warning(loc->filename, loc->line_no,
Packit 0021fb
			       "void parameter assumed to be 'hide(int)'");
Packit 0021fb
Packit 0021fb
		static struct arg_type_info *type = NULL;
Packit 0021fb
		if (type == NULL)
Packit 0021fb
			type = get_hidden_int();
Packit 0021fb
		param_destroy(param);
Packit 0021fb
		param_init_type(param, type, 0);
Packit 0021fb
	}
Packit 0021fb
	return CBS_CONT;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
static int
Packit 0021fb
process_line(struct protolib *plib, struct locus *loc, char *buf)
Packit 0021fb
{
Packit 0021fb
	char *str = buf;
Packit 0021fb
	char *tmp;
Packit 0021fb
Packit 0021fb
	debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
Packit 0021fb
	eat_spaces(&str);
Packit 0021fb
Packit 0021fb
	/* A comment or empty line.  */
Packit 0021fb
	if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
Packit 0021fb
		return 0;
Packit 0021fb
Packit 0021fb
	if (strncmp(str, "typedef", 7) == 0) {
Packit 0021fb
		parse_typedef(plib, loc, &str);
Packit 0021fb
		return 0;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	struct prototype fun;
Packit 0021fb
	prototype_init(&fun);
Packit 0021fb
Packit 0021fb
	char *proto_name = NULL;
Packit 0021fb
	int own;
Packit 0021fb
	fun.return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL);
Packit 0021fb
	if (fun.return_info == NULL) {
Packit 0021fb
	err:
Packit 0021fb
		debug(3, " Skipping line %d", loc->line_no);
Packit 0021fb
		prototype_destroy(&fun);
Packit 0021fb
		free(proto_name);
Packit 0021fb
		return -1;
Packit 0021fb
	}
Packit 0021fb
	fun.own_return_info = own;
Packit 0021fb
	debug(4, " return_type = %d", fun.return_info->type);
Packit 0021fb
Packit 0021fb
	eat_spaces(&str);
Packit 0021fb
	tmp = start_of_arg_sig(str);
Packit 0021fb
	if (tmp == NULL) {
Packit 0021fb
		report_error(loc->filename, loc->line_no, "syntax error");
Packit 0021fb
		goto err;
Packit 0021fb
	}
Packit 0021fb
	*tmp = '\0';
Packit 0021fb
Packit 0021fb
	proto_name = strdup(str);
Packit 0021fb
	if (proto_name == NULL) {
Packit 0021fb
	oom:
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "%s", strerror(errno));
Packit 0021fb
		goto err;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	str = tmp + 1;
Packit 0021fb
	debug(3, " name = %s", proto_name);
Packit 0021fb
Packit 0021fb
	struct param *extra_param = NULL;
Packit 0021fb
	int have_stop = 0;
Packit 0021fb
Packit 0021fb
	while (1) {
Packit 0021fb
		eat_spaces(&str);
Packit 0021fb
		if (*str == ')')
Packit 0021fb
			break;
Packit 0021fb
Packit 0021fb
		if (str[0] == '+') {
Packit 0021fb
			if (have_stop == 0) {
Packit 0021fb
				struct param param;
Packit 0021fb
				param_init_stop(¶m;;
Packit 0021fb
				if (prototype_push_param(&fun, &param) < 0)
Packit 0021fb
					goto oom;
Packit 0021fb
				have_stop = 1;
Packit 0021fb
			}
Packit 0021fb
			str++;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		int own;
Packit 0021fb
		size_t param_num = prototype_num_params(&fun) - have_stop;
Packit 0021fb
		struct arg_type_info *type
Packit 0021fb
			= parse_lens(plib, loc, &str, &extra_param,
Packit 0021fb
				     param_num, &own, NULL);
Packit 0021fb
		if (type == NULL) {
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "unknown argument type");
Packit 0021fb
			goto err;
Packit 0021fb
		}
Packit 0021fb
Packit 0021fb
		struct param param;
Packit 0021fb
		param_init_type(&param, type, own);
Packit 0021fb
		if (prototype_push_param(&fun, &param) < 0)
Packit 0021fb
			goto oom;
Packit 0021fb
Packit 0021fb
		eat_spaces(&str);
Packit 0021fb
		if (*str == ',') {
Packit 0021fb
			str++;
Packit 0021fb
			continue;
Packit 0021fb
		} else if (*str == ')') {
Packit 0021fb
			continue;
Packit 0021fb
		} else {
Packit 0021fb
			if (str[strlen(str) - 1] == '\n')
Packit 0021fb
				str[strlen(str) - 1] = '\0';
Packit 0021fb
			report_error(loc->filename, loc->line_no,
Packit 0021fb
				     "syntax error around \"%s\"", str);
Packit 0021fb
			goto err;
Packit 0021fb
		}
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	/* We used to allow void parameter as a synonym to an argument
Packit 0021fb
	 * that shouldn't be displayed.  But backends really need to
Packit 0021fb
	 * know the exact type that they are dealing with.  The proper
Packit 0021fb
	 * way to do this these days is to use the hide lens.
Packit 0021fb
	 *
Packit 0021fb
	 * So if there are any voids in the parameter list, show a
Packit 0021fb
	 * warning and assume that they are ints.  If there's a sole
Packit 0021fb
	 * void, assume the function doesn't take any arguments.  The
Packit 0021fb
	 * latter is conservative, we can drop the argument
Packit 0021fb
	 * altogether, instead of fetching and then not showing it,
Packit 0021fb
	 * without breaking any observable behavior.  */
Packit 0021fb
	if (prototype_num_params(&fun) == 1
Packit 0021fb
	    && param_is_void(prototype_get_nth_param(&fun, 0))) {
Packit 0021fb
		if (0)
Packit 0021fb
			/* Don't show this warning.  Pre-0.7.0
Packit 0021fb
			 * ltrace.conf often used this idiom.  This
Packit 0021fb
			 * should be postponed until much later, when
Packit 0021fb
			 * extant uses are likely gone.  */
Packit 0021fb
			report_warning(loc->filename, loc->line_no,
Packit 0021fb
				       "sole void parameter ignored");
Packit 0021fb
		prototype_destroy_nth_param(&fun, 0);
Packit 0021fb
	} else {
Packit 0021fb
		prototype_each_param(&fun, NULL, void_to_hidden_int, loc);
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (extra_param != NULL) {
Packit 0021fb
		prototype_push_param(&fun, extra_param);
Packit 0021fb
		free(extra_param);
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	if (protolib_add_prototype(plib, proto_name, 1, &fun) < 0) {
Packit 0021fb
		report_error(loc->filename, loc->line_no,
Packit 0021fb
			     "couldn't add prototype: %s",
Packit 0021fb
			     strerror(errno));
Packit 0021fb
		goto err;
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	return 0;
Packit 0021fb
}
Packit 0021fb
Packit 0021fb
int
Packit 0021fb
read_config_file(FILE *stream, const char *path, struct protolib *plib)
Packit 0021fb
{
Packit 0021fb
	debug(DEBUG_FUNCTION, "Reading config file `%s'...", path);
Packit 0021fb
Packit 0021fb
	struct locus loc = { path, 0 };
Packit 0021fb
	char *line = NULL;
Packit 0021fb
	size_t len = 0;
Packit 0021fb
	while (getline(&line, &len, stream) >= 0) {
Packit 0021fb
		loc.line_no++;
Packit 0021fb
		process_line(plib, &loc, line);
Packit 0021fb
	}
Packit 0021fb
Packit 0021fb
	free(line);
Packit 0021fb
	return 0;
Packit 0021fb
}