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}