wayland/src/scanner.c

2220 lines
53 KiB
C
Raw Normal View History

/*
2011-08-11 14:51:31 -04:00
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2011 Intel Corporation
* Copyright © 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "wayland-version.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
#include <limits.h>
#include <unistd.h>
#if HAVE_LIBXML
#include <libxml/parser.h>
/* Embedded wayland.dtd file */
/* static const char wayland_dtd[]; wayland.dtd */
#include "wayland.dtd.h"
#endif
/* Expat must be included after libxml as both want to declare XMLCALL; see
* the Git commit that 'git blame' for this comment points to for more. */
#include <expat.h>
#include "wayland-util.h"
#define PROGRAM_NAME "wayland-scanner"
enum side {
CLIENT,
SERVER,
};
enum visibility {
PRIVATE,
PUBLIC,
};
static int
usage(int ret)
{
fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]"
" [input_file output_file]\n", PROGRAM_NAME);
fprintf(stderr, "\n");
fprintf(stderr, "Converts XML protocol descriptions supplied on "
"stdin or input file to client\n"
"headers, server headers, or protocol marshalling code.\n\n"
"Use \"public-code\" only if the marshalling code will be public - "
"aka DSO will export it while other components will be using it.\n"
"Using \"private-code\" is strongly recommended.\n\n");
fprintf(stderr, "options:\n");
fprintf(stderr, " -h, --help display this help and exit.\n"
" -v, --version print the wayland library version that\n"
" the scanner was built against.\n"
" -c, --include-core-only include the core version of the headers,\n"
" that is e.g. wayland-client-core.h instead\n"
" of wayland-client.h.\n"
" -s, --strict exit immediately with an error if DTD\n"
" verification fails.\n");
exit(ret);
}
static int
scanner_version(int ret)
{
fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION);
exit(ret);
}
static bool
is_dtd_valid(FILE *input, const char *filename)
{
bool rc = true;
#if HAVE_LIBXML
xmlParserCtxtPtr ctx = NULL;
xmlDocPtr doc = NULL;
xmlDtdPtr dtd = NULL;
xmlValidCtxtPtr dtdctx;
xmlParserInputBufferPtr buffer;
int fd = fileno(input);
dtdctx = xmlNewValidCtxt();
ctx = xmlNewParserCtxt();
if (!ctx || !dtdctx)
abort();
buffer = xmlParserInputBufferCreateMem(wayland_dtd,
sizeof(wayland_dtd),
XML_CHAR_ENCODING_UTF8);
if (!buffer) {
fprintf(stderr, "Failed to init buffer for DTD.\n");
abort();
}
dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8);
if (!dtd) {
fprintf(stderr, "Failed to parse DTD.\n");
abort();
}
doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0);
if (!doc) {
fprintf(stderr, "Failed to read XML\n");
abort();
}
rc = xmlValidateDtd(dtdctx, doc, dtd);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctx);
xmlFreeDtd(dtd);
xmlFreeValidCtxt(dtdctx);
/* xmlIOParseDTD consumes buffer */
if (lseek(fd, 0, SEEK_SET) != 0) {
fprintf(stderr, "Failed to reset fd, output would be garbage.\n");
abort();
}
#endif
return rc;
}
#define XML_BUFFER_SIZE 4096
struct location {
const char *filename;
int line_number;
};
struct description {
char *summary;
char *text;
};
struct protocol {
char *name;
char *uppercase_name;
struct wl_list interface_list;
int type_index;
int null_run_length;
char *copyright;
struct description *description;
bool core_headers;
};
struct interface {
struct location loc;
char *name;
char *uppercase_name;
int version;
int since, deprecated_since;
struct wl_list request_list;
struct wl_list event_list;
struct wl_list enumeration_list;
struct wl_list link;
struct description *description;
};
struct message {
struct location loc;
char *name;
char *uppercase_name;
struct wl_list arg_list;
struct wl_list link;
int arg_count;
int new_id_count;
int type_index;
int all_null;
int destructor;
int since, deprecated_since;
struct description *description;
};
enum arg_type {
NEW_ID,
INT,
UNSIGNED,
FIXED,
STRING,
OBJECT,
ARRAY,
FD
};
struct arg {
char *name;
enum arg_type type;
int nullable;
char *interface_name;
struct wl_list link;
char *summary;
char *enumeration_name;
};
struct enumeration {
char *name;
char *uppercase_name;
struct wl_list entry_list;
struct wl_list link;
struct description *description;
bool bitfield;
int since;
};
struct entry {
char *name;
char *uppercase_name;
char *value;
char *summary;
int since, deprecated_since;
struct wl_list link;
struct description *description;
};
struct parse_context {
struct location loc;
2011-04-13 16:50:02 -04:00
XML_Parser parser;
struct protocol *protocol;
struct interface *interface;
struct message *message;
struct enumeration *enumeration;
struct entry *entry;
struct description *description;
char character_data[8192];
unsigned int character_data_length;
};
enum identifier_role {
STANDALONE_IDENT,
TRAILING_IDENT
};
static void *
fail_on_null(void *p)
{
if (p == NULL) {
fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
exit(EXIT_FAILURE);
}
return p;
}
static void *
zalloc(size_t s)
{
return calloc(s, 1);
}
static void *
xzalloc(size_t s)
{
return fail_on_null(zalloc(s));
}
static char *
xstrdup(const char *s)
{
return fail_on_null(strdup(s));
}
static char *
uppercase_dup(const char *src)
{
char *u;
int i;
u = xstrdup(src);
for (i = 0; u[i]; i++)
u[i] = toupper(u[i]);
u[i] = '\0';
return u;
}
static const char *indent(int n)
{
const char *whitespace[] = {
"\t\t\t\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t ",
"\t\t\t\t\t\t\t\t\t\t\t\t "
};
return whitespace[n % 8] + 12 - n / 8;
}
static void
desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
static void
desc_dump(char *desc, const char *fmt, ...)
{
va_list ap;
char buf[128], hang;
int col, i, j, k, startcol, newlines;
va_start(ap, fmt);
vsnprintf(buf, sizeof buf, fmt, ap);
va_end(ap);
for (i = 0, col = 0; buf[i] != '*'; i++) {
if (buf[i] == '\t')
col = (col + 8) & ~7;
else
col++;
}
printf("%s", buf);
if (!desc) {
printf("(none)\n");
return;
}
startcol = col;
col += strlen(&buf[i]);
if (col - startcol > 2)
hang = '\t';
else
hang = ' ';
for (i = 0; desc[i]; ) {
k = i;
newlines = 0;
while (desc[i] && isspace(desc[i])) {
if (desc[i] == '\n')
newlines++;
i++;
}
if (!desc[i])
break;
j = i;
while (desc[i] && !isspace(desc[i]))
i++;
if (newlines > 1)
printf("\n%s*", indent(startcol));
if (newlines > 1 || col + i - j > 72) {
printf("\n%s*%c", indent(startcol), hang);
col = startcol;
}
if (col > startcol && k > 0)
col += printf(" ");
col += printf("%.*s", i - j, &desc[j]);
}
putchar('\n');
}
static void __attribute__ ((noreturn))
fail(struct location *loc, const char *msg, ...)
2011-04-13 16:50:02 -04:00
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s:%d: error: ",
loc->filename, loc->line_number);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
va_end(ap);
2011-04-13 16:50:02 -04:00
exit(EXIT_FAILURE);
}
static void
warn(struct location *loc, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
fprintf(stderr, "%s:%d: warning: ",
loc->filename, loc->line_number);
vfprintf(stderr, msg, ap);
fprintf(stderr, "\n");
va_end(ap);
}
static bool
is_nullable_type(struct arg *arg)
{
switch (arg->type) {
/* Strings and objects are possibly nullable */
case STRING:
case OBJECT:
return true;
default:
return false;
}
}
static struct message *
create_message(struct location loc, const char *name)
{
struct message *message;
message = xzalloc(sizeof *message);
message->loc = loc;
message->name = xstrdup(name);
message->uppercase_name = uppercase_dup(name);
wl_list_init(&message->arg_list);
return message;
}
static void
free_arg(struct arg *arg)
{
free(arg->name);
free(arg->interface_name);
free(arg->summary);
free(arg->enumeration_name);
free(arg);
}
static struct arg *
create_arg(const char *name)
{
struct arg *arg;
arg = xzalloc(sizeof *arg);
arg->name = xstrdup(name);
return arg;
}
static bool
set_arg_type(struct arg *arg, const char *type)
{
if (strcmp(type, "int") == 0)
arg->type = INT;
else if (strcmp(type, "uint") == 0)
arg->type = UNSIGNED;
else if (strcmp(type, "fixed") == 0)
arg->type = FIXED;
else if (strcmp(type, "string") == 0)
arg->type = STRING;
else if (strcmp(type, "array") == 0)
arg->type = ARRAY;
else if (strcmp(type, "fd") == 0)
arg->type = FD;
else if (strcmp(type, "new_id") == 0)
arg->type = NEW_ID;
else if (strcmp(type, "object") == 0)
arg->type = OBJECT;
else
return false;
return true;
}
static void
free_description(struct description *desc)
{
if (!desc)
return;
free(desc->summary);
free(desc->text);
free(desc);
}
static void
free_message(struct message *message)
{
struct arg *a, *a_next;
free(message->name);
free(message->uppercase_name);
free_description(message->description);
wl_list_for_each_safe(a, a_next, &message->arg_list, link)
free_arg(a);
free(message);
}
static struct enumeration *
create_enumeration(const char *name)
{
struct enumeration *enumeration;
enumeration = xzalloc(sizeof *enumeration);
enumeration->name = xstrdup(name);
enumeration->uppercase_name = uppercase_dup(name);
enumeration->since = 1;
wl_list_init(&enumeration->entry_list);
return enumeration;
}
static struct entry *
create_entry(const char *name, const char *value)
{
struct entry *entry;
entry = xzalloc(sizeof *entry);
entry->name = xstrdup(name);
entry->uppercase_name = uppercase_dup(name);
entry->value = xstrdup(value);
return entry;
}
static void
free_entry(struct entry *entry)
{
free(entry->name);
free(entry->uppercase_name);
free(entry->value);
free(entry->summary);
free_description(entry->description);
free(entry);
}
static void
free_enumeration(struct enumeration *enumeration)
{
struct entry *e, *e_next;
free(enumeration->name);
free(enumeration->uppercase_name);
free_description(enumeration->description);
wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link)
free_entry(e);
free(enumeration);
}
static struct interface *
create_interface(struct location loc, const char *name, int version)
{
struct interface *interface;
interface = xzalloc(sizeof *interface);
interface->loc = loc;
interface->name = xstrdup(name);
interface->uppercase_name = uppercase_dup(name);
interface->version = version;
interface->since = 1;
wl_list_init(&interface->request_list);
wl_list_init(&interface->event_list);
wl_list_init(&interface->enumeration_list);
return interface;
}
static void
free_interface(struct interface *interface)
{
struct message *m, *next_m;
struct enumeration *e, *next_e;
free(interface->name);
free(interface->uppercase_name);
free_description(interface->description);
wl_list_for_each_safe(m, next_m, &interface->request_list, link)
free_message(m);
wl_list_for_each_safe(m, next_m, &interface->event_list, link)
free_message(m);
wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link)
free_enumeration(e);
free(interface);
}
/* Convert string to unsigned integer
*
* Parses a non-negative base-10 number from the given string. If the
* specified string is blank, contains non-numerical characters, is out
* of range, or results in a negative number, -1 is returned to indicate
* an error.
*
* Upon error, this routine does not modify or set errno.
*
* Returns -1 on error, or a non-negative integer on success
*/
static int
strtouint(const char *str)
{
long int ret;
char *end;
int prev_errno = errno;
errno = 0;
ret = strtol(str, &end, 10);
if (errno != 0 || end == str || *end != '\0')
return -1;
/* check range */
if (ret < 0 || ret > INT_MAX) {
return -1;
}
errno = prev_errno;
return (int)ret;
}
/* Check that the provided string will produce valid "C" identifiers.
*
* If the string will form the prefix of an identifier in the
* generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*.
*
* If the string will form the suffix of an identifier, then
* it must match [_0-9a-zA-Z]+.
*
* Unicode characters or escape sequences are not permitted,
* since not all C compilers support them.
*
* If the above conditions are not met, then fail()
*/
static void
validate_identifier(struct location *loc,
const char *str,
enum identifier_role role)
{
const char *scan;
if (!*str) {
fail(loc, "element name is empty");
}
for (scan = str; *scan; scan++) {
char c = *scan;
/* we do not use the locale-dependent `isalpha` */
bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
bool is_digit = c >= '0' && c <= '9';
bool leading_char = (scan == str) && role == STANDALONE_IDENT;
if (is_alpha || c == '_' || (!leading_char && is_digit))
continue;
if (role == TRAILING_IDENT)
fail(loc,
"'%s' is not a valid trailing identifier part", str);
else
fail(loc,
"'%s' is not a valid standalone identifier", str);
}
}
static int
version_from_since(struct parse_context *ctx, const char *since)
{
int version;
if (since != NULL) {
version = strtouint(since);
if (version == -1) {
fail(&ctx->loc, "invalid integer (%s)\n", since);
} else if (version > ctx->interface->version) {
fail(&ctx->loc, "since (%u) larger than version (%u)\n",
version, ctx->interface->version);
}
} else {
version = 1;
}
return version;
}
static int
version_from_deprecated_since(struct parse_context *ctx, const char *deprecated_since)
{
int version;
if (deprecated_since == NULL)
return 0;
version = strtouint(deprecated_since);
if (version == -1) {
fail(&ctx->loc, "invalid integer (%s)\n", deprecated_since);
} else if (version > ctx->interface->version) {
fail(&ctx->loc, "deprecated-since (%u) larger than version (%u)\n",
version, ctx->interface->version);
}
return version;
}
static void
start_element(void *data, const char *element_name, const char **atts)
{
struct parse_context *ctx = data;
struct interface *interface;
struct message *message;
struct arg *arg;
struct enumeration *enumeration;
struct entry *entry;
struct description *description = NULL;
const char *name = NULL;
const char *type = NULL;
const char *interface_name = NULL;
const char *value = NULL;
const char *summary = NULL;
const char *since = NULL;
const char *deprecated_since = NULL;
const char *allow_null = NULL;
const char *enumeration_name = NULL;
const char *bitfield = NULL;
int i, version = 0;
ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
for (i = 0; atts[i]; i += 2) {
if (strcmp(atts[i], "name") == 0)
name = atts[i + 1];
if (strcmp(atts[i], "version") == 0) {
version = strtouint(atts[i + 1]);
if (version == -1)
fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
}
if (strcmp(atts[i], "type") == 0)
type = atts[i + 1];
if (strcmp(atts[i], "value") == 0)
value = atts[i + 1];
if (strcmp(atts[i], "interface") == 0)
interface_name = atts[i + 1];
if (strcmp(atts[i], "summary") == 0)
summary = atts[i + 1];
if (strcmp(atts[i], "since") == 0)
since = atts[i + 1];
if (strcmp(atts[i], "deprecated-since") == 0)
deprecated_since = atts[i + 1];
if (strcmp(atts[i], "allow-null") == 0)
allow_null = atts[i + 1];
if (strcmp(atts[i], "enum") == 0)
enumeration_name = atts[i + 1];
if (strcmp(atts[i], "bitfield") == 0)
bitfield = atts[i + 1];
}
ctx->character_data_length = 0;
if (strcmp(element_name, "protocol") == 0) {
2011-04-13 16:50:02 -04:00
if (name == NULL)
fail(&ctx->loc, "no protocol name given");
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
ctx->protocol->name = xstrdup(name);
ctx->protocol->uppercase_name = uppercase_dup(name);
} else if (strcmp(element_name, "copyright") == 0) {
} else if (strcmp(element_name, "interface") == 0) {
2011-04-13 16:50:02 -04:00
if (name == NULL)
fail(&ctx->loc, "no interface name given");
2011-04-13 16:50:02 -04:00
if (version == 0)
fail(&ctx->loc, "no interface version given");
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
interface = create_interface(ctx->loc, name, version);
ctx->interface = interface;
wl_list_insert(ctx->protocol->interface_list.prev,
&interface->link);
} else if (strcmp(element_name, "request") == 0 ||
strcmp(element_name, "event") == 0) {
2011-04-13 16:50:02 -04:00
if (name == NULL)
fail(&ctx->loc, "no request name given");
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
message = create_message(ctx->loc, name);
if (strcmp(element_name, "request") == 0)
wl_list_insert(ctx->interface->request_list.prev,
&message->link);
else
wl_list_insert(ctx->interface->event_list.prev,
&message->link);
if (type != NULL && strcmp(type, "destructor") == 0)
message->destructor = 1;
version = version_from_since(ctx, since);
if (version < ctx->interface->since)
warn(&ctx->loc, "since version not increasing\n");
ctx->interface->since = version;
message->since = version;
version = version_from_deprecated_since(ctx, deprecated_since);
if (version > 0 && version <= message->since)
fail(&ctx->loc, "deprecated-since version (%d) smaller "
"or equal to since version (%u)\n",
version, message->since);
message->deprecated_since = version;
if (strcmp(name, "destroy") == 0 && !message->destructor)
fail(&ctx->loc, "destroy request should be destructor type");
ctx->message = message;
} else if (strcmp(element_name, "arg") == 0) {
if (name == NULL)
fail(&ctx->loc, "no argument name given");
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
arg = create_arg(name);
if (!set_arg_type(arg, type))
fail(&ctx->loc, "unknown type (%s)", type);
switch (arg->type) {
case NEW_ID:
ctx->message->new_id_count++;
/* fallthrough */
case OBJECT:
if (interface_name) {
validate_identifier(&ctx->loc,
interface_name,
STANDALONE_IDENT);
arg->interface_name = xstrdup(interface_name);
}
break;
default:
if (interface_name != NULL)
fail(&ctx->loc, "interface attribute not allowed for type %s", type);
break;
}
if (allow_null) {
if (strcmp(allow_null, "true") == 0)
arg->nullable = 1;
else if (strcmp(allow_null, "false") != 0)
fail(&ctx->loc,
"invalid value for allow-null attribute (%s)",
allow_null);
if (!is_nullable_type(arg))
fail(&ctx->loc,
"allow-null is only valid for objects, strings, and arrays");
}
if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
arg->enumeration_name = NULL;
else
arg->enumeration_name = xstrdup(enumeration_name);
if (summary)
arg->summary = xstrdup(summary);
wl_list_insert(ctx->message->arg_list.prev, &arg->link);
ctx->message->arg_count++;
} else if (strcmp(element_name, "enum") == 0) {
2011-04-13 16:50:02 -04:00
if (name == NULL)
fail(&ctx->loc, "no enum name given");
validate_identifier(&ctx->loc, name, TRAILING_IDENT);
enumeration = create_enumeration(name);
if (bitfield == NULL || strcmp(bitfield, "false") == 0)
enumeration->bitfield = false;
else if (strcmp(bitfield, "true") == 0)
enumeration->bitfield = true;
else
fail(&ctx->loc,
"invalid value (%s) for bitfield attribute (only true/false are accepted)",
bitfield);
wl_list_insert(ctx->interface->enumeration_list.prev,
&enumeration->link);
ctx->enumeration = enumeration;
} else if (strcmp(element_name, "entry") == 0) {
if (name == NULL)
fail(&ctx->loc, "no entry name given");
validate_identifier(&ctx->loc, name, TRAILING_IDENT);
entry = create_entry(name, value);
version = version_from_since(ctx, since);
if (version < ctx->enumeration->since)
warn(&ctx->loc, "since version not increasing\n");
ctx->enumeration->since = version;
entry->since = version;
version = version_from_deprecated_since(ctx, deprecated_since);
if (version > 0 && version <= entry->since)
fail(&ctx->loc, "deprecated-since version (%d) smaller "
"or equal to since version (%u)\n",
version, entry->since);
entry->deprecated_since = version;
if (summary)
entry->summary = xstrdup(summary);
else
entry->summary = NULL;
wl_list_insert(ctx->enumeration->entry_list.prev,
&entry->link);
ctx->entry = entry;
} else if (strcmp(element_name, "description") == 0) {
if (summary == NULL)
fail(&ctx->loc, "description without summary");
description = xzalloc(sizeof *description);
description->summary = xstrdup(summary);
if (ctx->message)
ctx->message->description = description;
else if (ctx->entry)
ctx->entry->description = description;
else if (ctx->enumeration)
ctx->enumeration->description = description;
else if (ctx->interface)
ctx->interface->description = description;
else
ctx->protocol->description = description;
ctx->description = description;
}
}
static struct enumeration *
find_enumeration(struct protocol *protocol,
struct interface *interface,
char *enum_attribute)
{
struct interface *i;
struct enumeration *e;
char *enum_name;
uint32_t idx = 0, j;
for (j = 0; j + 1 < strlen(enum_attribute); j++) {
if (enum_attribute[j] == '.') {
idx = j;
}
}
if (idx > 0) {
enum_name = enum_attribute + idx + 1;
wl_list_for_each(i, &protocol->interface_list, link)
if (strncmp(i->name, enum_attribute, idx) == 0)
wl_list_for_each(e, &i->enumeration_list, link)
if (strcmp(e->name, enum_name) == 0)
return e;
} else if (interface) {
enum_name = enum_attribute;
wl_list_for_each(e, &interface->enumeration_list, link)
if (strcmp(e->name, enum_name) == 0)
return e;
}
return NULL;
}
static void
verify_arguments(struct parse_context *ctx,
struct interface *interface,
struct wl_list *messages,
struct wl_list *enumerations)
{
struct message *m;
wl_list_for_each(m, messages, link) {
struct arg *a;
wl_list_for_each(a, &m->arg_list, link) {
struct enumeration *e;
if (!a->enumeration_name)
continue;
e = find_enumeration(ctx->protocol, interface,
a->enumeration_name);
switch (a->type) {
case INT:
if (e && e->bitfield)
fail(&ctx->loc,
"bitfield-style enum must only be referenced by uint");
break;
case UNSIGNED:
break;
default:
fail(&ctx->loc,
"enumeration-style argument has wrong type");
}
}
}
}
#ifndef HAVE_STRNDUP
char *
strndup(const char *s, size_t size)
{
char *r = malloc(size + 1);
strncpy(r, s, size);
r[size] = '\0';
return r;
}
#endif
static void
end_element(void *data, const XML_Char *name)
{
struct parse_context *ctx = data;
if (strcmp(name, "copyright") == 0) {
ctx->protocol->copyright =
strndup(ctx->character_data,
ctx->character_data_length);
} else if (strcmp(name, "description") == 0) {
2012-10-20 11:38:57 -04:00
ctx->description->text =
strndup(ctx->character_data,
ctx->character_data_length);
ctx->description = NULL;
} else if (strcmp(name, "request") == 0 ||
strcmp(name, "event") == 0) {
ctx->message = NULL;
} else if (strcmp(name, "enum") == 0) {
if (wl_list_empty(&ctx->enumeration->entry_list)) {
fail(&ctx->loc, "enumeration %s was empty",
ctx->enumeration->name);
}
ctx->enumeration = NULL;
} else if (strcmp(name, "entry") == 0) {
ctx->entry = NULL;
} else if (strcmp(name, "protocol") == 0) {
struct interface *i;
wl_list_for_each(i, &ctx->protocol->interface_list, link) {
verify_arguments(ctx, i, &i->request_list, &i->enumeration_list);
verify_arguments(ctx, i, &i->event_list, &i->enumeration_list);
}
}
}
static void
character_data(void *data, const XML_Char *s, int len)
{
struct parse_context *ctx = data;
if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
fprintf(stderr, "too much character data");
exit(EXIT_FAILURE);
}
memcpy(ctx->character_data + ctx->character_data_length, s, len);
ctx->character_data_length += len;
}
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
static void
format_text_to_comment(const char *text, bool standalone_comment)
{
int bol = 1, start = 0, i, length;
bool comment_started = !standalone_comment;
length = strlen(text);
for (i = 0; i <= length; i++) {
if (bol && (text[i] == ' ' || text[i] == '\t')) {
continue;
} else if (bol) {
bol = 0;
start = i;
}
if (text[i] == '\n' ||
(text[i] == '\0' && !(start == i))) {
printf("%s%s%.*s\n",
comment_started ? " *" : "/*",
i > start ? " " : "",
i - start, text + start);
bol = 1;
comment_started = true;
}
}
if (comment_started && standalone_comment)
printf(" */\n\n");
}
static void
emit_opcodes(struct wl_list *message_list, struct interface *interface)
{
struct message *m;
int opcode;
if (wl_list_empty(message_list))
return;
opcode = 0;
wl_list_for_each(m, message_list, link)
printf("#define %s_%s %d\n",
interface->uppercase_name, m->uppercase_name, opcode++);
printf("\n");
}
static void
emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
{
struct message *m;
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
wl_list_for_each(m, message_list, link) {
printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
printf("#define %s_%s_SINCE_VERSION %d\n",
interface->uppercase_name, m->uppercase_name, m->since);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
}
printf("\n");
}
static void
emit_type(struct arg *a)
{
switch (a->type) {
default:
case INT:
case FD:
2011-07-07 13:39:08 -04:00
printf("int32_t ");
break;
case NEW_ID:
case UNSIGNED:
printf("uint32_t ");
break;
case FIXED:
printf("wl_fixed_t ");
break;
case STRING:
printf("const char *");
break;
case OBJECT:
printf("struct %s *", a->interface_name);
break;
case ARRAY:
printf("struct wl_array *");
break;
}
}
static void
emit_stubs(struct wl_list *message_list, struct interface *interface)
{
struct message *m;
struct arg *a, *ret;
int has_destructor, has_destroy;
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/** @ingroup iface_%s */\n", interface->name);
printf("static inline void\n"
"%s_set_user_data(struct %s *%s, void *user_data)\n"
"{\n"
"\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
"}\n\n",
interface->name, interface->name, interface->name,
interface->name);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/** @ingroup iface_%s */\n", interface->name);
printf("static inline void *\n"
"%s_get_user_data(struct %s *%s)\n"
"{\n"
"\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
"}\n\n",
interface->name, interface->name, interface->name,
interface->name);
printf("static inline uint32_t\n"
"%s_get_version(struct %s *%s)\n"
"{\n"
"\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
"}\n\n",
interface->name, interface->name, interface->name,
interface->name);
has_destructor = 0;
has_destroy = 0;
wl_list_for_each(m, message_list, link) {
if (m->destructor)
has_destructor = 1;
if (strcmp(m->name, "destroy") == 0)
has_destroy = 1;
}
if (!has_destructor && has_destroy) {
fail(&interface->loc,
"interface '%s' has method named destroy "
"but no destructor",
interface->name);
exit(EXIT_FAILURE);
}
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
printf("/** @ingroup iface_%s */\n", interface->name);
printf("static inline void\n"
"%s_destroy(struct %s *%s)\n"
"{\n"
"\twl_proxy_destroy("
"(struct wl_proxy *) %s);\n"
"}\n\n",
interface->name, interface->name, interface->name,
interface->name);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
}
if (wl_list_empty(message_list))
return;
wl_list_for_each(m, message_list, link) {
if (m->new_id_count > 1) {
warn(&m->loc,
"request '%s::%s' has more than "
"one new_id arg, not emitting stub\n",
interface->name, m->name);
continue;
}
ret = NULL;
wl_list_for_each(a, &m->arg_list, link) {
if (a->type == NEW_ID)
ret = a;
}
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/**\n"
" * @ingroup iface_%s\n", interface->name);
if (m->description && m->description->text)
format_text_to_comment(m->description->text, false);
printf(" */\n");
if (ret && ret->interface_name == NULL)
printf("static inline void *\n");
else if (ret)
printf("static inline struct %s *\n",
ret->interface_name);
else
printf("static inline void\n");
printf("%s_%s(struct %s *%s",
interface->name, m->name,
interface->name, interface->name);
wl_list_for_each(a, &m->arg_list, link) {
if (a->type == NEW_ID && a->interface_name == NULL) {
printf(", const struct wl_interface *interface"
", uint32_t version");
continue;
} else if (a->type == NEW_ID)
continue;
printf(", ");
emit_type(a);
printf("%s", a->name);
}
printf(")\n"
"{\n");
printf("\t");
if (ret) {
printf("struct wl_proxy *%s;\n\n"
"\t%s = ", ret->name, ret->name);
}
printf("wl_proxy_marshal_flags("
"(struct wl_proxy *) %s,\n"
"\t\t\t %s_%s",
interface->name,
interface->uppercase_name,
m->uppercase_name);
if (ret) {
if (ret->interface_name) {
/* Normal factory case, an arg has type="new_id" and
* an interface is provided */
printf(", &%s_interface", ret->interface_name);
} else {
/* an arg has type ="new_id" but interface is not
* provided, such as in wl_registry.bind */
printf(", interface");
}
2013-11-14 21:29:06 -08:00
} else {
/* No args have type="new_id" */
printf(", NULL");
}
if (ret && ret->interface_name == NULL)
printf(", version");
else
printf(", wl_proxy_get_version((struct wl_proxy *) %s)",
interface->name);
printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0");
wl_list_for_each(a, &m->arg_list, link) {
2013-11-14 21:29:06 -08:00
if (a->type == NEW_ID) {
if (a->interface_name == NULL)
printf(", interface->name, version");
printf(", NULL");
} else {
printf(", %s", a->name);
}
}
printf(");\n");
if (ret && ret->interface_name == NULL)
printf("\n\treturn (void *) %s;\n", ret->name);
else if (ret)
printf("\n\treturn (struct %s *) %s;\n",
ret->interface_name, ret->name);
printf("}\n\n");
}
}
static void
emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
{
struct message *m;
struct arg *a;
/* We provide hand written functions for the display object */
if (strcmp(interface->name, "wl_display") == 0)
return;
wl_list_for_each(m, message_list, link) {
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/**\n"
" * @ingroup iface_%s\n"
" * Sends an %s event to the client owning the resource.\n",
interface->name,
m->name);
printf(" * @param resource_ The client's resource\n");
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
wl_list_for_each(a, &m->arg_list, link) {
if (a->summary)
printf(" * @param %s %s\n", a->name, a->summary);
}
printf(" */\n");
printf("static inline void\n"
"%s_send_%s(struct wl_resource *resource_",
interface->name, m->name);
wl_list_for_each(a, &m->arg_list, link) {
printf(", ");
switch (a->type) {
case NEW_ID:
case OBJECT:
printf("struct wl_resource *");
break;
default:
emit_type(a);
}
printf("%s", a->name);
}
printf(")\n"
"{\n"
"\twl_resource_post_event(resource_, %s_%s",
interface->uppercase_name, m->uppercase_name);
wl_list_for_each(a, &m->arg_list, link)
printf(", %s", a->name);
printf(");\n");
printf("}\n\n");
}
}
static void
emit_validator(struct interface *interface, struct enumeration *e)
{
struct entry *entry;
printf("#ifndef %s_%s_ENUM_IS_VALID\n",
interface->uppercase_name, e->uppercase_name);
printf("#define %s_%s_ENUM_IS_VALID\n",
interface->uppercase_name, e->uppercase_name);
printf("/**\n"
" * @ingroup iface_%s\n"
" * Validate a %s %s value.\n"
" *\n"
" * @return true on success, false on error.\n"
" * @ref %s_%s\n"
" */\n"
"static inline bool\n"
"%s_%s_is_valid(uint32_t value, uint32_t version) {\n",
interface->name, interface->name, e->name,
interface->name, e->name,
interface->name, e->name);
if (e->bitfield) {
printf(" uint32_t valid = 0;\n");
wl_list_for_each(entry, &e->entry_list, link) {
printf(" if (version >= %d)\n"
" valid |= %s_%s_%s;\n",
entry->since,
interface->uppercase_name, e->uppercase_name,
entry->uppercase_name);
}
printf(" return (value & ~valid) == 0;\n");
} else {
printf(" switch (value) {\n");
wl_list_for_each(entry, &e->entry_list, link) {
printf(" case %s%s_%s_%s:\n"
" return version >= %d;\n",
entry->value[0] == '-' ? "(uint32_t)" : "",
interface->uppercase_name, e->uppercase_name,
entry->uppercase_name, entry->since);
}
printf(" default:\n"
" return false;\n"
" }\n");
}
printf("}\n");
printf("#endif /* %s_%s_ENUM_IS_VALID */\n\n",
interface->uppercase_name, e->uppercase_name);
}
static void
emit_enumerations(struct interface *interface, bool with_validators)
{
struct enumeration *e;
struct entry *entry;
wl_list_for_each(e, &interface->enumeration_list, link) {
struct description *desc = e->description;
printf("#ifndef %s_%s_ENUM\n",
interface->uppercase_name, e->uppercase_name);
printf("#define %s_%s_ENUM\n",
interface->uppercase_name, e->uppercase_name);
if (desc) {
printf("/**\n");
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf(" * @ingroup iface_%s\n", interface->name);
format_text_to_comment(desc->summary, false);
if (desc->text)
format_text_to_comment(desc->text, false);
printf(" */\n");
}
printf("enum %s_%s {\n", interface->name, e->name);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
wl_list_for_each(entry, &e->entry_list, link) {
desc = entry->description;
if (entry->summary || entry->since > 1 || desc) {
printf("\t/**\n");
if (entry->summary)
printf("\t * %s\n", entry->summary);
if (desc) {
printf("\t * %s\n", desc->summary);
printf("\t *\n");
if (desc->text)
desc_dump(desc->text, "\t * ");
}
if (entry->since > 1)
printf("\t * @since %d\n", entry->since);
if (entry->deprecated_since > 0)
printf("\t * @deprecated Deprecated since version %d\n",
entry->deprecated_since);
printf("\t */\n");
}
printf("\t%s_%s_%s = %s,\n",
interface->uppercase_name,
e->uppercase_name,
entry->uppercase_name, entry->value);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
}
printf("};\n");
wl_list_for_each(entry, &e->entry_list, link) {
if (entry->since == 1)
continue;
printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
printf("#define %s_%s_%s_SINCE_VERSION %d\n",
interface->uppercase_name,
e->uppercase_name, entry->uppercase_name,
entry->since);
}
printf("#endif /* %s_%s_ENUM */\n\n",
interface->uppercase_name, e->uppercase_name);
if (with_validators)
emit_validator(interface, e);
}
}
static void
emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
{
struct message *m;
struct arg *a;
int n;
if (wl_list_empty(message_list))
return;
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/**\n");
printf(" * @ingroup iface_%s\n", interface->name);
printf(" * @struct %s_%s\n", interface->name,
(side == SERVER) ? "interface" : "listener");
printf(" */\n");
printf("struct %s_%s {\n", interface->name,
(side == SERVER) ? "interface" : "listener");
wl_list_for_each(m, message_list, link) {
struct description *mdesc = m->description;
printf("\t/**\n");
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
if (mdesc) {
if (mdesc->summary)
printf("\t * %s\n", mdesc->summary);
printf("\t *\n");
desc_dump(mdesc->text, "\t * ");
}
wl_list_for_each(a, &m->arg_list, link) {
if (side == SERVER && a->type == NEW_ID &&
a->interface_name == NULL)
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("\t * @param interface name of the objects interface\n"
"\t * @param version version of the objects interface\n");
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
if (a->summary)
printf("\t * @param %s %s\n", a->name,
a->summary);
}
if (m->since > 1)
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("\t * @since %d\n", m->since);
if (m->deprecated_since > 0)
printf("\t * @deprecated Deprecated since version %d\n",
m->deprecated_since);
printf("\t */\n");
printf("\tvoid (*%s)(", m->name);
n = strlen(m->name) + 17;
if (side == SERVER) {
printf("struct wl_client *client,\n"
"%sstruct wl_resource *resource",
indent(n));
} else {
printf("void *data,\n"),
printf("%sstruct %s *%s",
indent(n), interface->name, interface->name);
}
wl_list_for_each(a, &m->arg_list, link) {
printf(",\n%s", indent(n));
if (side == SERVER && a->type == OBJECT)
printf("struct wl_resource *");
else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
printf("const char *interface, uint32_t version, uint32_t ");
else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
printf("void *");
else if (side == CLIENT && a->type == NEW_ID)
printf("struct %s *", a->interface_name);
else
emit_type(a);
printf("%s", a->name);
}
printf(");\n");
}
printf("};\n\n");
if (side == CLIENT) {
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/**\n"
" * @ingroup iface_%s\n"
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
" */\n", interface->name);
printf("static inline int\n"
"%s_add_listener(struct %s *%s,\n"
"%sconst struct %s_listener *listener, void *data)\n"
"{\n"
"\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
"%s(void (**)(void)) listener, data);\n"
"}\n\n",
interface->name, interface->name, interface->name,
2011-08-09 14:31:36 +02:00
indent(14 + strlen(interface->name)),
interface->name,
interface->name,
indent(37));
}
}
static void
emit_types_forward_declarations(struct protocol *protocol,
struct wl_list *message_list,
struct wl_array *types)
{
struct message *m;
struct arg *a;
int length;
char **p;
wl_list_for_each(m, message_list, link) {
length = 0;
m->all_null = 1;
wl_list_for_each(a, &m->arg_list, link) {
length++;
switch (a->type) {
case NEW_ID:
case OBJECT:
if (!a->interface_name)
continue;
m->all_null = 0;
p = fail_on_null(wl_array_add(types, sizeof *p));
*p = a->interface_name;
break;
default:
break;
}
}
if (m->all_null && length > protocol->null_run_length)
protocol->null_run_length = length;
}
}
static int
cmp_names(const void *p1, const void *p2)
{
const char * const *s1 = p1, * const *s2 = p2;
return strcmp(*s1, *s2);
}
static const char *
get_include_name(bool core, enum side side)
{
if (side == SERVER)
return core ? "wayland-server-core.h" : "wayland-server.h";
else
return core ? "wayland-client-core.h" : "wayland-client.h";
}
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
static void
emit_mainpage_blurb(const struct protocol *protocol, enum side side)
{
struct interface *i;
printf("/**\n"
" * @page page_%s The %s protocol\n",
protocol->name, protocol->name);
if (protocol->description) {
if (protocol->description->summary) {
printf(" * %s\n"
" *\n", protocol->description->summary);
}
if (protocol->description->text) {
printf(" * @section page_desc_%s Description\n", protocol->name);
format_text_to_comment(protocol->description->text, false);
printf(" *\n");
}
}
printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
wl_list_for_each(i, &protocol->interface_list, link) {
printf(" * - @subpage page_iface_%s - %s\n",
i->name,
i->description && i->description->summary ? i->description->summary : "");
}
if (protocol->copyright) {
printf(" * @section page_copyright_%s Copyright\n",
protocol->name);
printf(" * <pre>\n");
format_text_to_comment(protocol->copyright, false);
printf(" * </pre>\n");
}
printf(" */\n");
}
static void
emit_header(struct protocol *protocol, enum side side)
{
struct interface *i, *i_next;
struct wl_array types;
const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
char **p, *prev;
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
printf("#ifndef %s_%s_PROTOCOL_H\n"
"#define %s_%s_PROTOCOL_H\n"
"\n"
"#include <stdint.h>\n"
"#include <stddef.h>\n"
"#include \"%s\"\n\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n",
protocol->uppercase_name, s,
protocol->uppercase_name, s,
get_include_name(protocol->core_headers, side));
if (side == SERVER)
printf("struct wl_client;\n"
"struct wl_resource;\n\n");
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
emit_mainpage_blurb(protocol, side);
wl_array_init(&types);
wl_list_for_each(i, &protocol->interface_list, link) {
emit_types_forward_declarations(protocol, &i->request_list, &types);
emit_types_forward_declarations(protocol, &i->event_list, &types);
}
wl_list_for_each(i, &protocol->interface_list, link) {
p = fail_on_null(wl_array_add(&types, sizeof *p));
*p = i->name;
}
if (types.size > 0)
qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
prev = NULL;
wl_array_for_each(p, &types) {
if (prev && strcmp(*p, prev) == 0)
continue;
printf("struct %s;\n", *p);
prev = *p;
}
wl_array_release(&types);
printf("\n");
wl_list_for_each(i, &protocol->interface_list, link) {
scanner: Guard interface declarations This allows to include client and server headers in the same file fixing warnings like In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:80:34: warning: redundant redeclaration of ‘zwlr_layer_shell_v1_interface’ [-Wredundant-decls] 80 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:77:34: note: previous declaration of ‘zwlr_layer_shell_v1_interface’ was here 77 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:106:34: warning: redundant redeclaration of ‘zwlr_layer_surface_v1_interface’ [-Wredundant-decls] 106 | extern const struct wl_interface zwlr_layer_surface_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:103:34: note: previous declaration of ‘zwlr_layer_surface_v1_interface’ was here 103 | extern const struct wl_interface zwlr_layer_surface_v1_interface; Signed-off-by: Guido Günther <agx@sigxcpu.org> Closes: #158
2020-04-21 12:47:56 +02:00
printf("#ifndef %s_INTERFACE\n", i->uppercase_name);
printf("#define %s_INTERFACE\n", i->uppercase_name);
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
printf("/**\n"
" * @page page_iface_%s %s\n",
i->name, i->name);
if (i->description && i->description->text) {
printf(" * @section page_iface_%s_desc Description\n",
i->name);
format_text_to_comment(i->description->text, false);
}
printf(" * @section page_iface_%s_api API\n"
" * See @ref iface_%s.\n"
" */\n",
i->name, i->name);
printf("/**\n"
" * @defgroup iface_%s The %s interface\n",
i->name, i->name);
if (i->description && i->description->text)
format_text_to_comment(i->description->text, false);
printf(" */\n");
printf("extern const struct wl_interface "
"%s_interface;\n", i->name);
scanner: Guard interface declarations This allows to include client and server headers in the same file fixing warnings like In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:80:34: warning: redundant redeclaration of ‘zwlr_layer_shell_v1_interface’ [-Wredundant-decls] 80 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:77:34: note: previous declaration of ‘zwlr_layer_shell_v1_interface’ was here 77 | extern const struct wl_interface zwlr_layer_shell_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../subprojects/wlroots/include/wlr/types/wlr_layer_shell_v1.h:16, from ../src/desktop.h:16, from ../src/server.h:13, from ../tests/testlib.c:8: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-protocol.h:106:34: warning: redundant redeclaration of ‘zwlr_layer_surface_v1_interface’ [-Wredundant-decls] 106 | extern const struct wl_interface zwlr_layer_surface_v1_interface; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from ../tests/testlib.h:8, from ../tests/testlib.c:7: tests/59830eb@@footest@sta/wlr-layer-shell-unstable-v1-client-protocol.h:103:34: note: previous declaration of ‘zwlr_layer_surface_v1_interface’ was here 103 | extern const struct wl_interface zwlr_layer_surface_v1_interface; Signed-off-by: Guido Günther <agx@sigxcpu.org> Closes: #158
2020-04-21 12:47:56 +02:00
printf("#endif\n");
}
printf("\n");
wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
emit_enumerations(i, side == SERVER);
if (side == SERVER) {
emit_structs(&i->request_list, i, side);
emit_opcodes(&i->event_list, i);
emit_opcode_versions(&i->event_list, i);
emit_opcode_versions(&i->request_list, i);
emit_event_wrappers(&i->event_list, i);
} else {
emit_structs(&i->event_list, i, side);
emit_opcodes(&i->request_list, i);
emit_opcode_versions(&i->event_list, i);
emit_opcode_versions(&i->request_list, i);
emit_stubs(&i->request_list, i);
}
free_interface(i);
}
printf("#ifdef __cplusplus\n"
"}\n"
"#endif\n"
"\n"
"#endif\n");
}
static void
emit_enum_header(struct protocol *protocol)
{
struct interface *i, *i_next;
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
printf("#ifndef %s_ENUM_PROTOCOL_H\n"
"#define %s_ENUM_PROTOCOL_H\n"
"\n"
"#ifdef __cplusplus\n"
"extern \"C\" {\n"
"#endif\n\n",
protocol->uppercase_name,
protocol->uppercase_name);
wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
emit_enumerations(i, false);
free_interface(i);
}
printf("#ifdef __cplusplus\n"
"}\n"
"#endif\n"
"\n"
"#endif\n");
}
static void
emit_null_run(struct protocol *protocol)
{
int i;
for (i = 0; i < protocol->null_run_length; i++)
printf("\tNULL,\n");
}
static void
emit_types(struct protocol *protocol, struct wl_list *message_list)
{
struct message *m;
struct arg *a;
wl_list_for_each(m, message_list, link) {
if (m->all_null) {
m->type_index = 0;
continue;
}
m->type_index =
protocol->null_run_length + protocol->type_index;
protocol->type_index += m->arg_count;
wl_list_for_each(a, &m->arg_list, link) {
switch (a->type) {
case NEW_ID:
case OBJECT:
if (a->interface_name)
printf("\t&%s_interface,\n",
a->interface_name);
else
printf("\tNULL,\n");
break;
default:
printf("\tNULL,\n");
break;
}
}
}
}
static void
emit_messages(const char *name, struct wl_list *message_list,
struct interface *interface, const char *suffix)
{
struct message *m;
struct arg *a;
if (wl_list_empty(message_list))
return;
printf("static const struct wl_message "
"%s_%s[] = {\n",
interface->name, suffix);
wl_list_for_each(m, message_list, link) {
printf("\t{ \"%s\", \"", m->name);
if (m->since > 1)
printf("%d", m->since);
wl_list_for_each(a, &m->arg_list, link) {
if (is_nullable_type(a) && a->nullable)
printf("?");
switch (a->type) {
default:
case INT:
printf("i");
break;
case NEW_ID:
if (a->interface_name == NULL)
printf("su");
printf("n");
break;
case UNSIGNED:
printf("u");
break;
case FIXED:
printf("f");
break;
case STRING:
printf("s");
break;
case OBJECT:
printf("o");
break;
case ARRAY:
printf("a");
break;
case FD:
printf("h");
break;
}
}
printf("\", %s_types + %d },\n", name, m->type_index);
}
printf("};\n\n");
}
static void
emit_code(struct protocol *protocol, enum visibility vis)
{
const char *symbol_visibility;
struct interface *i, *next;
struct wl_array types;
char **p, *prev;
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
if (protocol->copyright)
doc: generate doxygen html output from the scanner This switches the scanner to generate doxygen-compatible tags for the generated protocol headers, and hooks up the doxygen build to generate server and client-side API documentation. That documentation is now in Client/ and Server/, respectively. GENERATE_HTML is on by default and must be disabled for the xml/man targets to avoid messing up the new documentation. We disable all three three targets in the doxyfile (xml and man default to NO anyway) to make it obvious that they need to be set in the per-target instructions. Each protocol is a separate doxygen @page, with each interface a @subpage. Wayland only has one protocol, wayland-protocols will have these nested. Each protocol page has a list of interfaces and the copyright and description where available. All interfaces are grouped by doxygen @defgroup and @ingroups and appear in "Modules" in the generated output. Each interface subpage has the description and a link to the actual API doc. Function, struct and #defines are documented in doxygen style and associated with the matching interface. Note that pages and groups have fixed HTML file names and are directly linkable/bookmark-able. The @mainpage is a separate file that's included at build time. It doesn't contain much other than links to where the interesting bits are. It's a static file though that supports markdown, so we can extend it easily in the future. For doxygen we need the new options EXTRACT_ALL and OPTIMIZE_OUTPUT_FOR_C so it scans C code properly. EXTRACT_STATIC is needed since most of the protocol hooks are static. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
2016-03-01 09:26:21 +10:00
format_text_to_comment(protocol->copyright, true);
printf("#include <stdbool.h>\n"
"#include <stdlib.h>\n"
"#include <stdint.h>\n"
"#include \"wayland-util.h\"\n\n");
/* When building a shared library symbols must be exported, otherwise
* we want to have the symbols hidden. */
if (vis == PRIVATE) {
symbol_visibility = "WL_PRIVATE";
printf("#ifndef __has_attribute\n"
"# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n"
"#endif\n\n");
printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n"
"#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n"
"#else\n"
"#define WL_PRIVATE\n"
"#endif\n\n");
} else {
symbol_visibility = "WL_EXPORT";
}
wl_array_init(&types);
wl_list_for_each(i, &protocol->interface_list, link) {
emit_types_forward_declarations(protocol, &i->request_list, &types);
emit_types_forward_declarations(protocol, &i->event_list, &types);
}
if (types.size > 0)
qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
prev = NULL;
wl_array_for_each(p, &types) {
if (prev && strcmp(*p, prev) == 0)
continue;
printf("extern const struct wl_interface %s_interface;\n", *p);
prev = *p;
}
wl_array_release(&types);
printf("\n");
printf("static const struct wl_interface *%s_types[] = {\n", protocol->name);
emit_null_run(protocol);
wl_list_for_each(i, &protocol->interface_list, link) {
emit_types(protocol, &i->request_list);
emit_types(protocol, &i->event_list);
}
printf("};\n\n");
wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
emit_messages(protocol->name, &i->request_list, i, "requests");
emit_messages(protocol->name, &i->event_list, i, "events");
printf("%s const struct wl_interface "
"%s_interface = {\n"
"\t\"%s\", %d,\n",
symbol_visibility, i->name, i->name, i->version);
if (!wl_list_empty(&i->request_list))
printf("\t%d, %s_requests,\n",
wl_list_length(&i->request_list), i->name);
else
printf("\t0, NULL,\n");
if (!wl_list_empty(&i->event_list))
printf("\t%d, %s_events,\n",
wl_list_length(&i->event_list), i->name);
else
printf("\t0, NULL,\n");
printf("};\n\n");
/* we won't need it any further */
free_interface(i);
}
}
static void
free_protocol(struct protocol *protocol)
{
free(protocol->name);
free(protocol->uppercase_name);
free(protocol->copyright);
free_description(protocol->description);
}
int main(int argc, char *argv[])
{
struct parse_context ctx;
struct protocol protocol;
FILE *input = stdin;
char *input_filename = NULL;
int len;
void *buf;
bool help = false;
bool core_headers = false;
bool version = false;
bool strict = false;
bool fail = false;
int opt;
enum {
CLIENT_HEADER,
SERVER_HEADER,
ENUM_HEADER,
PRIVATE_CODE,
PUBLIC_CODE,
CODE,
} mode;
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "include-core-only", no_argument, NULL, 'c' },
{ "strict", no_argument, NULL, 's' },
{ 0, 0, NULL, 0 }
};
while (1) {
opt = getopt_long(argc, argv, "hvcs", options, NULL);
if (opt == -1)
break;
switch (opt) {
case 'h':
help = true;
break;
case 'v':
version = true;
break;
case 'c':
core_headers = true;
break;
case 's':
strict = true;
break;
default:
fail = true;
break;
}
}
argv += optind;
argc -= optind;
if (help)
usage(EXIT_SUCCESS);
else if (version)
scanner_version(EXIT_SUCCESS);
else if ((argc != 1 && argc != 3) || fail)
usage(EXIT_FAILURE);
else if (strcmp(argv[0], "help") == 0)
usage(EXIT_SUCCESS);
else if (strcmp(argv[0], "client-header") == 0)
mode = CLIENT_HEADER;
else if (strcmp(argv[0], "server-header") == 0)
mode = SERVER_HEADER;
else if (strcmp(argv[0], "enum-header") == 0)
mode = ENUM_HEADER;
else if (strcmp(argv[0], "private-code") == 0)
mode = PRIVATE_CODE;
else if (strcmp(argv[0], "public-code") == 0)
mode = PUBLIC_CODE;
else if (strcmp(argv[0], "code") == 0)
mode = CODE;
else
usage(EXIT_FAILURE);
if (argc == 3) {
input_filename = argv[1];
input = fopen(input_filename, "r");
if (input == NULL) {
fprintf(stderr, "Could not open input file: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
if (freopen(argv[2], "w", stdout) == NULL) {
fprintf(stderr, "Could not open output file: %s\n",
strerror(errno));
fclose(input);
exit(EXIT_FAILURE);
}
}
/* initialize protocol structure */
memset(&protocol, 0, sizeof protocol);
wl_list_init(&protocol.interface_list);
protocol.core_headers = core_headers;
/* initialize context */
2012-10-20 11:38:57 -04:00
memset(&ctx, 0, sizeof ctx);
ctx.protocol = &protocol;
if (input == stdin)
ctx.loc.filename = "<stdin>";
else
ctx.loc.filename = input_filename;
if (!is_dtd_valid(input, ctx.loc.filename)) {
fprintf(stderr,
"*******************************************************\n"
"* *\n"
"* WARNING: XML failed validation against built-in DTD *\n"
"* *\n"
"*******************************************************\n");
if (strict) {
fclose(input);
exit(EXIT_FAILURE);
}
}
/* create XML parser */
2011-04-13 16:50:02 -04:00
ctx.parser = XML_ParserCreate(NULL);
XML_SetUserData(ctx.parser, &ctx);
if (ctx.parser == NULL) {
fprintf(stderr, "failed to create parser\n");
fclose(input);
exit(EXIT_FAILURE);
}
XML_SetElementHandler(ctx.parser, start_element, end_element);
XML_SetCharacterDataHandler(ctx.parser, character_data);
do {
2011-04-13 16:50:02 -04:00
buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
len = fread(buf, 1, XML_BUFFER_SIZE, input);
if (len < 0) {
fprintf(stderr, "fread: %s\n", strerror(errno));
fclose(input);
exit(EXIT_FAILURE);
}
if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
fprintf(stderr,
"Error parsing XML at line %ld col %ld: %s\n",
XML_GetCurrentLineNumber(ctx.parser),
XML_GetCurrentColumnNumber(ctx.parser),
XML_ErrorString(XML_GetErrorCode(ctx.parser)));
fclose(input);
exit(EXIT_FAILURE);
}
} while (len > 0);
2011-04-13 16:50:02 -04:00
XML_ParserFree(ctx.parser);
switch (mode) {
case CLIENT_HEADER:
emit_header(&protocol, CLIENT);
break;
case SERVER_HEADER:
emit_header(&protocol, SERVER);
break;
case ENUM_HEADER:
emit_enum_header(&protocol);
break;
case PRIVATE_CODE:
emit_code(&protocol, PRIVATE);
break;
case CODE:
fprintf(stderr,
"Using \"code\" is deprecated - use "
"private-code or public-code.\n"
"See the help page for details.\n");
/* fallthrough */
case PUBLIC_CODE:
emit_code(&protocol, PUBLIC);
break;
}
free_protocol(&protocol);
fclose(input);
return 0;
}