1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21#include <assert.h>
22#include <stdlib.h>
23
24#include "param.h"
25#include "type.h"
26#include "value.h"
27#include "expr.h"
28
29void
30param_init_type(struct param *param, struct arg_type_info *type, int own)
31{
32	param->flavor = PARAM_FLAVOR_TYPE;
33	param->u.type.type = type;
34	param->u.type.own_type = own;
35}
36
37void
38param_init_stop(struct param *param)
39{
40	param->flavor = PARAM_FLAVOR_STOP;
41}
42
43void
44param_init_pack(struct param *param, enum param_pack_flavor ppflavor,
45		struct expr_node *args, size_t nargs, int own_args,
46		struct param_enum *(*init)(struct value *cb_args,
47					   size_t nargs,
48					   struct value_dict *arguments),
49		int (*next)(struct param_enum *context,
50			    struct arg_type_info *infop,
51			    int *insert_stop),
52		enum param_status (*stop)(struct param_enum *ctx,
53					  struct value *value),
54		void (*done)(struct param_enum *))
55{
56	param->flavor = PARAM_FLAVOR_PACK;
57	param->u.pack.args = args;
58	param->u.pack.nargs = nargs;
59	param->u.pack.own_args = own_args;
60	param->u.pack.ppflavor = ppflavor;
61	param->u.pack.init = init;
62	param->u.pack.next = next;
63	param->u.pack.stop = stop;
64	param->u.pack.done = done;
65}
66
67struct param_enum *
68param_pack_init(struct param *param, struct value_dict *fargs)
69{
70	struct value cb_args[param->u.pack.nargs];
71	size_t i;
72
73	/* For evaluation of argument expressions, we pass in this as
74	 * a "current" value.  */
75	struct arg_type_info *void_type = type_get_simple(ARGTYPE_VOID);
76	struct value void_val;
77	value_init_detached(&void_val, NULL, void_type, 0);
78
79	struct param_enum *ret = NULL;
80	for (i = 0; i < param->u.pack.nargs; ++i) {
81		if (expr_eval(&param->u.pack.args[i], &void_val,
82			      fargs, &cb_args[i]) < 0)
83			goto release;
84	}
85
86	ret = param->u.pack.init(cb_args, param->u.pack.nargs, fargs);
87
88release:
89	while (i-- > 0)
90		value_destroy(&cb_args[i]);
91	return ret;
92}
93
94int
95param_pack_next(struct param *param, struct param_enum *context,
96		struct arg_type_info *infop, int *insert_stop)
97{
98	return param->u.pack.next(context, infop, insert_stop);
99}
100
101enum param_status
102param_pack_stop(struct param *param,
103		struct param_enum *context, struct value *value)
104{
105	return param->u.pack.stop(context, value);
106}
107
108void
109param_pack_done(struct param *param, struct param_enum *context)
110{
111	return param->u.pack.done(context);
112}
113
114void
115param_destroy(struct param *param)
116{
117	if (param == NULL)
118		return;
119
120	switch (param->flavor) {
121	case PARAM_FLAVOR_TYPE:
122		if (param->u.type.own_type) {
123			type_destroy(param->u.type.type);
124			free(param->u.type.type);
125		}
126		return;
127
128	case PARAM_FLAVOR_PACK:
129		if (param->u.pack.own_args) {
130			size_t i;
131			for (i = 0; i < param->u.pack.nargs; ++i)
132				expr_destroy(&param->u.pack.args[i]);
133			free(param->u.pack.args);
134		}
135		return;
136
137	case PARAM_FLAVOR_STOP:
138		return;
139	}
140
141	assert(!"Unknown value of param flavor!");
142	abort();
143}
144