main shrub/shrubtools / proto / mdoc.c
  1#include <stdbool.h>
  2#include <alloc.h>
  3#include <buffer.h>
  4#include <ctype.h>
  5#include <str.h>
  6
  7#include "mdoc.h"
  8#include "util.h"
  9
 10static bool has_description(const struct description *);
 11static void mdoc_macro(const char *);
 12static void mdoc_text(const char *);
 13static void mdoc_textline(const char *, size_t);
 14static void mdoc_paragraphs(const struct description *, bool);
 15static void mdoc_message_signature(const struct message *);
 16static void mdoc_message_args(const struct message *);
 17static void mdoc_message_detail(const struct message *);
 18static void mdoc_enum_detail(const struct enumdef *);
 19static void mdoc_interface_detail(const struct interface *);
 20static char *mdoc_title(const char *);
 21
 22static bool
 23has_description(const struct description *desc)
 24{
 25	return (desc->summary && desc->summary[0]) ||
 26		(desc->text && desc->text[0]);
 27}
 28
 29static void
 30mdoc_macro(const char *s)
 31{
 32	buffer_puts(buffer_1, s);
 33	buffer_puts(buffer_1, "\n");
 34}
 35
 36static void
 37mdoc_text(const char *s)
 38{
 39	for (; *s; ++s) {
 40		if (*s == '\\')
 41			buffer_puts(buffer_1, "\\e");
 42		else
 43			buffer_put(buffer_1, s, 1);
 44	}
 45}
 46
 47static void
 48mdoc_textline(const char *s, size_t len)
 49{
 50	size_t i;
 51
 52	if (!s || len == 0) {
 53		buffer_puts(buffer_1, "\n");
 54		return;
 55	}
 56	if (s[0] == '.' || s[0] == '\'')
 57		buffer_puts(buffer_1, "\\&");
 58	for (i = 0; i < len; ++i) {
 59		if (s[i] == '\\')
 60			buffer_puts(buffer_1, "\\e");
 61		else
 62			buffer_put(buffer_1, s + i, 1);
 63	}
 64	buffer_puts(buffer_1, "\n");
 65}
 66
 67static void
 68mdoc_paragraphs(const struct description *desc, bool leadpp)
 69{
 70	const char *line, *next;
 71
 72	if (!desc->summary || !desc->summary[0]) {
 73		if (!desc->text || !desc->text[0])
 74			return;
 75		if (leadpp)
 76			mdoc_macro(".Pp");
 77	} else {
 78		if (leadpp)
 79			mdoc_macro(".Pp");
 80		buffer_puts(buffer_1, ".D1 ");
 81		mdoc_text(desc->summary);
 82		buffer_puts(buffer_1, "\n");
 83		if (!desc->text || !desc->text[0])
 84			return;
 85		mdoc_macro(".Pp");
 86	}
 87	line = desc->text;
 88	while (*line) {
 89		next = line + str_chr(line, '\n');
 90		if (*next == '\0')
 91			next = line + str_len(line);
 92		mdoc_textline(line, (size_t)(next - line));
 93		line = *next ? next + 1 : next;
 94	}
 95}
 96
 97static void
 98mdoc_message_signature(const struct message *msg)
 99{
100	size_t i;
101
102	buffer_puts(buffer_1, ".Fo ");
103	buffer_puts(buffer_1, msg->name);
104	buffer_puts(buffer_1, "\n");
105	for (i = 0; i < msg->nargs; ++i) {
106		const struct argument *arg = &msg->args[i];
107
108		buffer_puts(buffer_1, ".Fa \"");
109		if (arg->nullable)
110			buffer_puts(buffer_1, "?");
111		if (arg->iface && arg->iface[0] &&
112		    (str_equal(arg->type, "object") || str_equal(arg->type, "new_id")))
113			mdoc_text(arg->iface);
114		else
115			mdoc_text(arg->type);
116		buffer_puts(buffer_1, " ");
117		mdoc_text(arg->name);
118		buffer_puts(buffer_1, "\"\n");
119	}
120	buffer_puts(buffer_1, ".Fc");
121	{
122		const struct argument *creator = message_creator_arg(msg);
123
124		if (creator) {
125			buffer_puts(buffer_1, " \"creates ");
126			mdoc_text(creator->iface);
127			buffer_puts(buffer_1, "\"");
128		}
129	}
130	if (msg->destructor)
131		buffer_puts(buffer_1, " \"destructor\"");
132	buffer_puts(buffer_1, "\n");
133}
134
135static void
136mdoc_message_args(const struct message *msg)
137{
138	size_t i;
139	bool any;
140
141	any = false;
142	for (i = 0; i < msg->nargs; ++i) {
143		if (msg->args[i].summary && msg->args[i].summary[0]) {
144			any = true;
145			break;
146		}
147	}
148	if (!any)
149		return;
150	mdoc_macro(".Bl -tag -width Ds");
151	for (i = 0; i < msg->nargs; ++i) {
152		const struct argument *arg = &msg->args[i];
153
154		if (!arg->summary || !arg->summary[0])
155			continue;
156		buffer_puts(buffer_1, ".It Va ");
157		mdoc_text(arg->name);
158		buffer_puts(buffer_1, "\n");
159		mdoc_textline(arg->summary, str_len(arg->summary));
160	}
161	mdoc_macro(".El");
162}
163
164static void
165mdoc_message_detail(const struct message *msg)
166{
167	mdoc_macro(".It");
168	mdoc_message_signature(msg);
169	mdoc_paragraphs(&msg->desc, true);
170	mdoc_message_args(msg);
171}
172
173static void
174mdoc_enum_detail(const struct enumdef *en)
175{
176	size_t i;
177
178	mdoc_macro(".It");
179	buffer_puts(buffer_1, ".Sy ");
180	mdoc_text(en->name);
181	buffer_puts(buffer_1, "\n");
182	mdoc_paragraphs(&en->desc, true);
183	if (en->nentries == 0)
184		return;
185	mdoc_macro(".Bl -tag -width Ds");
186	for (i = 0; i < en->nentries; ++i) {
187		const struct enumentry *entry = &en->entries[i];
188
189		buffer_puts(buffer_1, ".It Dv ");
190		mdoc_text(entry->name);
191		buffer_puts(buffer_1, " = ");
192		mdoc_text(entry->value);
193		buffer_puts(buffer_1, "\n");
194		if (entry->summary && entry->summary[0])
195			mdoc_textline(entry->summary, str_len(entry->summary));
196		mdoc_paragraphs(&entry->desc, true);
197	}
198	mdoc_macro(".El");
199}
200
201static void
202mdoc_interface_detail(const struct interface *iface)
203{
204	size_t i;
205
206	buffer_puts(buffer_1, ".Ss ");
207	mdoc_text(iface->name);
208	buffer_puts(buffer_1, "\n");
209	buffer_puts(buffer_1, ".Sy Version:\\ ");
210	put_ulong(buffer_1, (unsigned long)iface->version);
211	buffer_puts(buffer_1, "\n");
212	mdoc_paragraphs(&iface->desc, true);
213
214	if (iface->nrequests > 0) {
215		mdoc_macro(".Pp");
216		mdoc_macro(".D1 Requests");
217		mdoc_macro(".Bl -item");
218		for (i = 0; i < iface->nrequests; ++i)
219			mdoc_message_detail(&iface->requests[i]);
220		mdoc_macro(".El");
221	}
222	if (iface->nevents > 0) {
223		mdoc_macro(".Pp");
224		mdoc_macro(".D1 Events");
225		mdoc_macro(".Bl -item");
226		for (i = 0; i < iface->nevents; ++i)
227			mdoc_message_detail(&iface->events[i]);
228		mdoc_macro(".El");
229	}
230	if (iface->nenums > 0) {
231		mdoc_macro(".Pp");
232		mdoc_macro(".D1 Enums");
233		mdoc_macro(".Bl -item");
234		for (i = 0; i < iface->nenums; ++i)
235			mdoc_enum_detail(&iface->enums[i]);
236		mdoc_macro(".El");
237	}
238}
239
240static char *
241mdoc_title(const char *name)
242{
243	size_t i, len;
244	char *title;
245
246	len = str_len(name);
247	title = copystr(name);
248	for (i = 0; i < len; ++i)
249		title[i] = (char)toupper((unsigned char)name[i]);
250	return title;
251}
252
253void
254print_protocol_mdoc(const struct protocol *proto)
255{
256	size_t i;
257	char *title;
258
259	title = mdoc_title(proto->name);
260	mdoc_macro(".\\\" generated by proto from shrubtools!!!!.");
261	mdoc_macro(".\\\" srcdump.net/shrub/shrubtools");
262	mdoc_macro(".Dd $Mdocdate$");
263	buffer_puts(buffer_1, ".Dt ");
264	buffer_puts(buffer_1, title);
265	buffer_puts(buffer_1, " 7\n");
266	mdoc_macro(".Os");
267	mdoc_macro(".Sh NAME");
268	buffer_puts(buffer_1, ".Nm ");
269	mdoc_text(proto->name);
270	buffer_puts(buffer_1, "\n");
271	mdoc_macro(".Nd protocol specification");
272	if (has_description(&proto->desc)) {
273		mdoc_macro(".Sh DESCRIPTION");
274		mdoc_paragraphs(&proto->desc, false);
275	}
276	mdoc_macro(".Sh INTERFACES");
277	for (i = 0; i < proto->nifaces; ++i)
278		mdoc_interface_detail(&proto->ifaces[i]);
279	alloc_free(title);
280	buffer_flush(buffer_1);
281}