|
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, ¶m) < 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(¶m, type, own);
|
|
Packit |
0021fb |
if (prototype_push_param(&fun, ¶m) < 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 |
}
|