main shrub/shrubtools / proto / protocol.c
  1#include <alloc.h>
  2#include <byte.h>
  3#include <str.h>
  4
  5#include "protocol.h"
  6#include "util.h"
  7
  8static void free_message(struct message *);
  9static void free_description(struct description *);
 10extern const char *argv0;
 11
 12struct interface *
 13proto_add_interface(struct protocol *proto, const char *name, int version)
 14{
 15	struct interface *iface;
 16
 17	if (proto->nifaces == proto->ifacecap) {
 18		size_t oldcap;
 19
 20		oldcap = proto->ifacecap;
 21		proto->ifacecap = proto->ifacecap ? proto->ifacecap * 2 : 8;
 22		if (!alloc_re((char **)&proto->ifaces,
 23		    oldcap * sizeof(proto->ifaces[0]),
 24		    proto->ifacecap * sizeof(proto->ifaces[0])))
 25			die_nomem();
 26	}
 27	iface = &proto->ifaces[proto->nifaces++];
 28	byte_zero(iface, sizeof(*iface));
 29	iface->name = copystr(name);
 30	iface->version = version;
 31	return iface;
 32}
 33
 34struct interface *
 35proto_find_interface(const struct protocol *proto, const char *name)
 36{
 37	size_t i;
 38
 39	for (i = 0; i < proto->nifaces; ++i) {
 40		if (str_equal(proto->ifaces[i].name, name))
 41			return &proto->ifaces[i];
 42	}
 43	return NULL;
 44}
 45
 46struct message *
 47iface_add_message(struct interface *iface, enum message_dir dir, const char *name)
 48{
 49	struct message *msg;
 50	struct message **list;
 51	size_t *nlist, *cap;
 52
 53	if (dir == MSG_REQUEST) {
 54		list = &iface->requests;
 55		nlist = &iface->nrequests;
 56		cap = &iface->requestcap;
 57	} else {
 58		list = &iface->events;
 59		nlist = &iface->nevents;
 60		cap = &iface->eventcap;
 61	}
 62	if (*nlist == *cap) {
 63		size_t oldcap;
 64
 65		oldcap = *cap;
 66		*cap = *cap ? *cap * 2 : 8;
 67		if (!alloc_re((char **)list,
 68		    oldcap * sizeof((*list)[0]),
 69		    *cap * sizeof((*list)[0])))
 70			die_nomem();
 71	}
 72	msg = &(*list)[(*nlist)++];
 73	byte_zero(msg, sizeof(*msg));
 74	msg->name = copystr(name);
 75	msg->dir = dir;
 76	msg->opcode = (int)(*nlist - 1);
 77	return msg;
 78}
 79
 80void
 81message_add_arg(struct message *msg, const char *name, const char *type, const char *iface, bool nullable)
 82{
 83	struct argument *arg;
 84
 85	if (msg->nargs == msg->argcap) {
 86		size_t oldcap;
 87
 88		oldcap = msg->argcap;
 89		msg->argcap = msg->argcap ? msg->argcap * 2 : 8;
 90		if (!alloc_re((char **)&msg->args,
 91		    oldcap * sizeof(msg->args[0]),
 92		    msg->argcap * sizeof(msg->args[0])))
 93			die_nomem();
 94	}
 95	arg = &msg->args[msg->nargs++];
 96	byte_zero(arg, sizeof(*arg));
 97	arg->name = copystr(name);
 98	arg->type = copystr(type);
 99	arg->iface = iface ? copystr(iface) : NULL;
100	arg->summary = NULL;
101	arg->nullable = nullable;
102	arg->new_id = str_equal(type, "new_id");
103}
104
105void
106iface_add_enum(struct interface *iface, const char *name)
107{
108	if (iface->nenums == iface->enumcap) {
109		size_t oldcap;
110
111		oldcap = iface->enumcap;
112		iface->enumcap = iface->enumcap ? iface->enumcap * 2 : 4;
113		if (!alloc_re((char **)&iface->enums,
114		    oldcap * sizeof(iface->enums[0]),
115		    iface->enumcap * sizeof(iface->enums[0])))
116			die_nomem();
117	}
118	byte_zero(&iface->enums[iface->nenums], sizeof(iface->enums[0]));
119	iface->enums[iface->nenums++].name = copystr(name);
120}
121
122struct enumdef *
123iface_last_enum(struct interface *iface)
124{
125	if (iface->nenums == 0)
126		return NULL;
127	return &iface->enums[iface->nenums - 1];
128}
129
130void
131enum_add_entry(struct enumdef *en, const char *name, const char *value)
132{
133	if (en->nentries == en->entrycap) {
134		size_t oldcap;
135
136		oldcap = en->entrycap;
137		en->entrycap = en->entrycap ? en->entrycap * 2 : 8;
138		if (!alloc_re((char **)&en->entries,
139		    oldcap * sizeof(en->entries[0]),
140		    en->entrycap * sizeof(en->entries[0])))
141			die_nomem();
142	}
143	byte_zero(&en->entries[en->nentries], sizeof(en->entries[0]));
144	en->entries[en->nentries].name = copystr(name);
145	en->entries[en->nentries].value = copystr(value);
146	++en->nentries;
147}
148
149struct enumentry *
150enum_last_entry(struct enumdef *en)
151{
152	if (en->nentries == 0)
153		return NULL;
154	return &en->entries[en->nentries - 1];
155}
156
157const struct argument *
158message_creator_arg(const struct message *msg)
159{
160	size_t i;
161
162	for (i = 0; i < msg->nargs; ++i) {
163		if (msg->args[i].new_id && msg->args[i].iface && msg->args[i].iface[0])
164			return &msg->args[i];
165	}
166	return NULL;
167}
168
169void
170proto_resolve(struct protocol *proto)
171{
172	size_t i, j;
173	struct interface *target;
174	const struct argument *arg;
175
176	for (i = 0; i < proto->nifaces; ++i) {
177		proto->ifaces[i].created_by_local = false;
178		proto->ifaces[i].ncreates = 0;
179	}
180	proto->total_requests = 0;
181	proto->total_events = 0;
182	proto->total_enums = 0;
183
184	for (i = 0; i < proto->nifaces; ++i) {
185		struct interface *iface = &proto->ifaces[i];
186
187		proto->total_requests += iface->nrequests;
188		proto->total_events += iface->nevents;
189		proto->total_enums += iface->nenums;
190		for (j = 0; j < iface->nrequests; ++j) {
191			arg = message_creator_arg(&iface->requests[j]);
192			if (!arg)
193				continue;
194			++iface->ncreates;
195			target = proto_find_interface(proto, arg->iface);
196			if (target)
197				target->created_by_local = true;
198		}
199	}
200}
201
202static void
203free_description(struct description *desc)
204{
205	alloc_free(desc->summary);
206	alloc_free(desc->text);
207}
208
209static void
210free_message(struct message *msg)
211{
212	size_t i;
213
214	alloc_free(msg->name);
215	free_description(&msg->desc);
216	for (i = 0; i < msg->nargs; ++i) {
217		alloc_free(msg->args[i].name);
218		alloc_free(msg->args[i].type);
219		alloc_free(msg->args[i].iface);
220		alloc_free(msg->args[i].summary);
221	}
222	alloc_free((char *)msg->args);
223}
224
225void
226proto_free(struct protocol *proto)
227{
228	size_t i, j;
229
230	alloc_free(proto->name);
231	free_description(&proto->desc);
232	for (i = 0; i < proto->nifaces; ++i) {
233		struct interface *iface = &proto->ifaces[i];
234
235		alloc_free(iface->name);
236		free_description(&iface->desc);
237		for (j = 0; j < iface->nrequests; ++j)
238			free_message(&iface->requests[j]);
239		for (j = 0; j < iface->nevents; ++j)
240			free_message(&iface->events[j]);
241		for (j = 0; j < iface->nenums; ++j)
242		{
243			size_t k;
244
245			alloc_free(iface->enums[j].name);
246			free_description(&iface->enums[j].desc);
247			for (k = 0; k < iface->enums[j].nentries; ++k) {
248				alloc_free(iface->enums[j].entries[k].name);
249				alloc_free(iface->enums[j].entries[k].value);
250				alloc_free(iface->enums[j].entries[k].summary);
251				free_description(&iface->enums[j].entries[k].desc);
252			}
253			alloc_free((char *)iface->enums[j].entries);
254		}
255		alloc_free((char *)iface->requests);
256		alloc_free((char *)iface->events);
257		alloc_free((char *)iface->enums);
258	}
259	alloc_free((char *)proto->ifaces);
260	byte_zero(proto, sizeof(*proto));
261}