2010-08-03 09:26:44 -04:00
|
|
|
/*
|
2011-08-11 14:51:31 -04:00
|
|
|
* Copyright © 2008-2011 Kristian Høgsberg
|
|
|
|
|
* Copyright © 2011 Intel Corporation
|
2015-07-30 15:07:20 +02:00
|
|
|
* Copyright © 2015 Red Hat, Inc.
|
2010-08-03 09:26:44 -04:00
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* 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:
|
2010-08-03 09:26:44 -04:00
|
|
|
*
|
2015-06-10 10:54:15 -07:00
|
|
|
* 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.
|
2010-08-03 09:26:44 -04:00
|
|
|
*/
|
|
|
|
|
|
2016-05-05 17:27:57 +02:00
|
|
|
#include "wayland-version.h"
|
2015-11-10 09:53:08 +10:00
|
|
|
|
2014-10-03 14:39:59 -05:00
|
|
|
#include <stdbool.h>
|
2010-08-03 09:26:44 -04:00
|
|
|
#include <stdio.h>
|
2012-05-07 23:41:48 -04:00
|
|
|
#include <stdarg.h>
|
2016-07-18 12:42:25 -05:00
|
|
|
#include <stdint.h>
|
2010-08-03 09:26:44 -04:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <ctype.h>
|
2015-04-29 16:46:51 +03:00
|
|
|
#include <getopt.h>
|
2015-07-30 16:42:00 +02:00
|
|
|
#include <limits.h>
|
2015-11-10 09:53:08 +10:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#if HAVE_LIBXML
|
|
|
|
|
#include <libxml/parser.h>
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2020-12-15 20:35:25 +01:00
|
|
|
/* Embedded wayland.dtd file */
|
|
|
|
|
/* static const char wayland_dtd[]; wayland.dtd */
|
|
|
|
|
#include "wayland.dtd.h"
|
2016-02-29 14:59:51 +02:00
|
|
|
#endif
|
|
|
|
|
|
2018-08-28 23:59:35 +01:00
|
|
|
/* 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>
|
|
|
|
|
|
2016-02-29 14:59:51 +02:00
|
|
|
#include "wayland-util.h"
|
2015-11-10 09:53:08 +10:00
|
|
|
|
2016-06-07 10:19:39 -05:00
|
|
|
#define PROGRAM_NAME "wayland-scanner"
|
|
|
|
|
|
2014-08-08 18:22:47 -04:00
|
|
|
enum side {
|
|
|
|
|
CLIENT,
|
|
|
|
|
SERVER,
|
|
|
|
|
};
|
|
|
|
|
|
2018-02-16 16:22:30 +00:00
|
|
|
enum visibility {
|
|
|
|
|
PRIVATE,
|
|
|
|
|
PUBLIC,
|
|
|
|
|
};
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static int
|
|
|
|
|
usage(int ret)
|
|
|
|
|
{
|
2023-05-03 12:18:07 +02:00
|
|
|
fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]"
|
2016-06-06 10:58:56 -07:00
|
|
|
" [input_file output_file]\n", PROGRAM_NAME);
|
2013-08-07 11:05:58 +10:00
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
fprintf(stderr, "Converts XML protocol descriptions supplied on "
|
2015-03-02 16:08:00 +02:00
|
|
|
"stdin or input file to client\n"
|
2018-02-16 16:22:30 +00:00
|
|
|
"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");
|
2015-04-29 16:46:51 +03:00
|
|
|
fprintf(stderr, "options:\n");
|
|
|
|
|
fprintf(stderr, " -h, --help display this help and exit.\n"
|
2016-05-05 17:27:57 +02:00
|
|
|
" -v, --version print the wayland library version that\n"
|
|
|
|
|
" the scanner was built against.\n"
|
2017-07-26 14:56:18 +01:00
|
|
|
" -c, --include-core-only include the core version of the headers,\n"
|
|
|
|
|
" that is e.g. wayland-client-core.h instead\n"
|
2017-10-11 17:31:33 +08:00
|
|
|
" of wayland-client.h.\n"
|
|
|
|
|
" -s, --strict exit immediately with an error if DTD\n"
|
|
|
|
|
" verification fails.\n");
|
2010-08-03 09:26:44 -04:00
|
|
|
exit(ret);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-05 17:27:57 +02:00
|
|
|
static int
|
|
|
|
|
scanner_version(int ret)
|
|
|
|
|
{
|
2016-06-06 10:58:56 -07:00
|
|
|
fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION);
|
2016-05-05 17:27:57 +02:00
|
|
|
exit(ret);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-10 09:53:08 +10:00
|
|
|
static bool
|
2016-01-25 17:28:06 +08:00
|
|
|
is_dtd_valid(FILE *input, const char *filename)
|
2015-11-10 09:53:08 +10:00
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
|
2020-12-15 20:35:25 +01:00
|
|
|
buffer = xmlParserInputBufferCreateMem(wayland_dtd,
|
|
|
|
|
sizeof(wayland_dtd),
|
2015-11-10 09:53:08 +10:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-25 17:28:06 +08:00
|
|
|
doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0);
|
2015-11-10 09:53:08 +10:00
|
|
|
if (!doc) {
|
|
|
|
|
fprintf(stderr, "Failed to read XML\n");
|
|
|
|
|
abort();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = xmlValidateDtd(dtdctx, doc, dtd);
|
|
|
|
|
xmlFreeDoc(doc);
|
|
|
|
|
xmlFreeParserCtxt(ctx);
|
2018-08-24 16:32:42 +01:00
|
|
|
xmlFreeDtd(dtd);
|
2015-11-10 09:53:08 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
#define XML_BUFFER_SIZE 4096
|
|
|
|
|
|
2013-11-15 14:21:11 -08:00
|
|
|
struct location {
|
|
|
|
|
const char *filename;
|
|
|
|
|
int line_number;
|
|
|
|
|
};
|
|
|
|
|
|
2012-01-19 14:13:36 -08:00
|
|
|
struct description {
|
|
|
|
|
char *summary;
|
|
|
|
|
char *text;
|
|
|
|
|
};
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
struct protocol {
|
2010-09-14 15:52:43 -04:00
|
|
|
char *name;
|
|
|
|
|
char *uppercase_name;
|
2010-08-03 09:26:44 -04:00
|
|
|
struct wl_list interface_list;
|
2011-07-12 13:22:25 -04:00
|
|
|
int type_index;
|
|
|
|
|
int null_run_length;
|
2011-07-25 18:14:20 -07:00
|
|
|
char *copyright;
|
2012-01-19 14:13:36 -08:00
|
|
|
struct description *description;
|
2015-04-29 16:46:51 +03:00
|
|
|
bool core_headers;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
};
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
struct interface {
|
2013-11-15 14:37:55 -08:00
|
|
|
struct location loc;
|
2010-08-03 09:26:44 -04:00
|
|
|
char *name;
|
|
|
|
|
char *uppercase_name;
|
|
|
|
|
int version;
|
2023-07-19 12:50:34 +02:00
|
|
|
int since, deprecated_since;
|
2010-08-03 09:26:44 -04:00
|
|
|
struct wl_list request_list;
|
|
|
|
|
struct wl_list event_list;
|
2011-01-21 21:57:55 -05:00
|
|
|
struct wl_list enumeration_list;
|
2010-08-03 09:26:44 -04:00
|
|
|
struct wl_list link;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
struct description *description;
|
2010-08-03 09:26:44 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct message {
|
2013-11-15 14:37:55 -08:00
|
|
|
struct location loc;
|
2010-08-03 09:26:44 -04:00
|
|
|
char *name;
|
|
|
|
|
char *uppercase_name;
|
|
|
|
|
struct wl_list arg_list;
|
|
|
|
|
struct wl_list link;
|
2011-07-12 13:22:25 -04:00
|
|
|
int arg_count;
|
2013-11-15 13:26:03 -08:00
|
|
|
int new_id_count;
|
2011-07-12 13:22:25 -04:00
|
|
|
int type_index;
|
|
|
|
|
int all_null;
|
2010-09-02 20:22:42 -04:00
|
|
|
int destructor;
|
2023-07-19 12:50:34 +02:00
|
|
|
int since, deprecated_since;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
struct description *description;
|
2010-08-03 09:26:44 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum arg_type {
|
|
|
|
|
NEW_ID,
|
|
|
|
|
INT,
|
|
|
|
|
UNSIGNED,
|
2012-05-08 17:17:25 +01:00
|
|
|
FIXED,
|
2010-08-03 09:26:44 -04:00
|
|
|
STRING,
|
|
|
|
|
OBJECT,
|
2010-08-26 21:49:44 -04:00
|
|
|
ARRAY,
|
|
|
|
|
FD
|
2010-08-03 09:26:44 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct arg {
|
|
|
|
|
char *name;
|
|
|
|
|
enum arg_type type;
|
2012-07-02 20:03:30 +10:00
|
|
|
int nullable;
|
2010-08-09 21:25:50 -04:00
|
|
|
char *interface_name;
|
2010-08-03 09:26:44 -04:00
|
|
|
struct wl_list link;
|
2012-01-19 14:13:36 -08:00
|
|
|
char *summary;
|
2015-10-26 19:39:52 +00:00
|
|
|
char *enumeration_name;
|
2010-08-03 09:26:44 -04:00
|
|
|
};
|
|
|
|
|
|
2011-01-21 21:57:55 -05:00
|
|
|
struct enumeration {
|
|
|
|
|
char *name;
|
|
|
|
|
char *uppercase_name;
|
|
|
|
|
struct wl_list entry_list;
|
|
|
|
|
struct wl_list link;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
struct description *description;
|
2015-10-26 19:39:52 +00:00
|
|
|
bool bitfield;
|
2017-01-24 09:56:38 +10:00
|
|
|
int since;
|
2011-01-21 21:57:55 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct entry {
|
|
|
|
|
char *name;
|
|
|
|
|
char *uppercase_name;
|
|
|
|
|
char *value;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
char *summary;
|
2023-07-19 12:50:34 +02:00
|
|
|
int since, deprecated_since;
|
2011-01-21 21:57:55 -05:00
|
|
|
struct wl_list link;
|
2021-06-03 00:10:21 +01:00
|
|
|
struct description *description;
|
2011-01-21 21:57:55 -05:00
|
|
|
};
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
struct parse_context {
|
2013-11-15 14:21:11 -08:00
|
|
|
struct location loc;
|
2011-04-13 16:50:02 -04:00
|
|
|
XML_Parser parser;
|
2010-08-03 09:26:44 -04:00
|
|
|
struct protocol *protocol;
|
|
|
|
|
struct interface *interface;
|
|
|
|
|
struct message *message;
|
2011-01-21 21:57:55 -05:00
|
|
|
struct enumeration *enumeration;
|
2021-06-03 00:10:21 +01:00
|
|
|
struct entry *entry;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
struct description *description;
|
2011-07-25 18:14:20 -07:00
|
|
|
char character_data[8192];
|
2012-03-23 14:00:32 +02:00
|
|
|
unsigned int character_data_length;
|
2010-08-03 09:26:44 -04:00
|
|
|
};
|
|
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
enum identifier_role {
|
|
|
|
|
STANDALONE_IDENT,
|
|
|
|
|
TRAILING_IDENT
|
|
|
|
|
};
|
|
|
|
|
|
2013-07-13 00:35:21 -04:00
|
|
|
static void *
|
|
|
|
|
fail_on_null(void *p)
|
|
|
|
|
{
|
|
|
|
|
if (p == NULL) {
|
2016-06-06 10:58:56 -07:00
|
|
|
fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
|
2013-07-13 00:35:21 -04:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *
|
2015-07-30 15:07:22 +02:00
|
|
|
zalloc(size_t s)
|
2013-07-13 00:35:21 -04:00
|
|
|
{
|
2015-07-30 15:07:22 +02:00
|
|
|
return calloc(s, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
|
xzalloc(size_t s)
|
|
|
|
|
{
|
|
|
|
|
return fail_on_null(zalloc(s));
|
2013-07-13 00:35:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
xstrdup(const char *s)
|
|
|
|
|
{
|
|
|
|
|
return fail_on_null(strdup(s));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static char *
|
|
|
|
|
uppercase_dup(const char *src)
|
|
|
|
|
{
|
|
|
|
|
char *u;
|
|
|
|
|
int i;
|
|
|
|
|
|
2013-07-13 00:35:21 -04:00
|
|
|
u = xstrdup(src);
|
2010-08-03 09:26:44 -04:00
|
|
|
for (i = 0; u[i]; i++)
|
|
|
|
|
u[i] = toupper(u[i]);
|
|
|
|
|
u[i] = '\0';
|
|
|
|
|
|
|
|
|
|
return u;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 22:23:05 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-15 00:49:13 +02:00
|
|
|
static void
|
2014-11-27 20:50:14 +05:30
|
|
|
desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
|
2012-10-15 00:49:13 +02:00
|
|
|
|
2012-01-19 14:13:36 -08:00
|
|
|
static void
|
2012-10-15 00:49:11 +02:00
|
|
|
desc_dump(char *desc, const char *fmt, ...)
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
{
|
2012-05-07 23:41:48 -04:00
|
|
|
va_list ap;
|
2012-10-15 00:49:11 +02:00
|
|
|
char buf[128], hang;
|
2012-10-21 22:24:33 -04:00
|
|
|
int col, i, j, k, startcol, newlines;
|
2012-05-07 23:41:48 -04:00
|
|
|
|
|
|
|
|
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);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
2012-05-07 23:41:48 -04:00
|
|
|
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;
|
2012-10-21 22:24:33 -04:00
|
|
|
newlines = 0;
|
|
|
|
|
while (desc[i] && isspace(desc[i])) {
|
|
|
|
|
if (desc[i] == '\n')
|
|
|
|
|
newlines++;
|
2012-05-07 23:41:48 -04:00
|
|
|
i++;
|
2012-10-21 22:24:33 -04:00
|
|
|
}
|
2012-05-07 23:41:48 -04:00
|
|
|
if (!desc[i])
|
|
|
|
|
break;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
2012-05-07 22:43:56 -04:00
|
|
|
j = i;
|
2012-05-07 23:41:48 -04:00
|
|
|
while (desc[i] && !isspace(desc[i]))
|
2012-05-07 22:43:56 -04:00
|
|
|
i++;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
2012-10-21 22:24:33 -04:00
|
|
|
if (newlines > 1)
|
|
|
|
|
printf("\n%s*", indent(startcol));
|
|
|
|
|
if (newlines > 1 || col + i - j > 72) {
|
2012-05-07 23:41:48 -04:00
|
|
|
printf("\n%s*%c", indent(startcol), hang);
|
2012-01-19 14:13:36 -08:00
|
|
|
col = startcol;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
}
|
2012-05-07 22:43:56 -04:00
|
|
|
|
2012-05-07 23:41:48 -04:00
|
|
|
if (col > startcol && k > 0)
|
|
|
|
|
col += printf(" ");
|
|
|
|
|
col += printf("%.*s", i - j, &desc[j]);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
}
|
2012-05-07 23:41:48 -04:00
|
|
|
putchar('\n');
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
}
|
|
|
|
|
|
2018-08-27 22:26:37 +01:00
|
|
|
static void __attribute__ ((noreturn))
|
2013-11-15 14:29:40 -08:00
|
|
|
fail(struct location *loc, const char *msg, ...)
|
2011-04-13 16:50:02 -04:00
|
|
|
{
|
2013-11-15 14:29:40 -08: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);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 14:37:55 -08:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-03 14:39:59 -05:00
|
|
|
static bool
|
2012-07-02 20:03:30 +10:00
|
|
|
is_nullable_type(struct arg *arg)
|
|
|
|
|
{
|
|
|
|
|
switch (arg->type) {
|
2022-07-12 09:12:33 -07:00
|
|
|
/* Strings and objects are possibly nullable */
|
2012-07-02 20:03:30 +10:00
|
|
|
case STRING:
|
|
|
|
|
case OBJECT:
|
2014-10-03 14:39:59 -05:00
|
|
|
return true;
|
2012-07-02 20:03:30 +10:00
|
|
|
default:
|
2014-10-03 14:39:59 -05:00
|
|
|
return false;
|
2012-07-02 20:03:30 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:20 +02:00
|
|
|
static struct message *
|
|
|
|
|
create_message(struct location loc, const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct message *message;
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
message = xzalloc(sizeof *message);
|
2015-07-30 15:07:20 +02:00
|
|
|
message->loc = loc;
|
|
|
|
|
message->name = xstrdup(name);
|
|
|
|
|
message->uppercase_name = uppercase_dup(name);
|
|
|
|
|
wl_list_init(&message->arg_list);
|
|
|
|
|
|
|
|
|
|
return message;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
static void
|
|
|
|
|
free_arg(struct arg *arg)
|
|
|
|
|
{
|
|
|
|
|
free(arg->name);
|
|
|
|
|
free(arg->interface_name);
|
|
|
|
|
free(arg->summary);
|
2018-08-24 16:32:42 +01:00
|
|
|
free(arg->enumeration_name);
|
2015-07-30 15:07:21 +02:00
|
|
|
free(arg);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:20 +02:00
|
|
|
static struct arg *
|
|
|
|
|
create_arg(const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct arg *arg;
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
arg = xzalloc(sizeof *arg);
|
2015-07-30 15:07:20 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:20 +02:00
|
|
|
static struct enumeration *
|
|
|
|
|
create_enumeration(const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct enumeration *enumeration;
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
enumeration = xzalloc(sizeof *enumeration);
|
2015-07-30 15:07:20 +02:00
|
|
|
enumeration->name = xstrdup(name);
|
|
|
|
|
enumeration->uppercase_name = uppercase_dup(name);
|
2017-01-24 09:56:38 +10:00
|
|
|
enumeration->since = 1;
|
2015-07-30 15:07:20 +02:00
|
|
|
|
|
|
|
|
wl_list_init(&enumeration->entry_list);
|
|
|
|
|
|
|
|
|
|
return enumeration;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct entry *
|
|
|
|
|
create_entry(const char *name, const char *value)
|
|
|
|
|
{
|
|
|
|
|
struct entry *entry;
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
entry = xzalloc(sizeof *entry);
|
2015-07-30 15:07:20 +02:00
|
|
|
entry->name = xstrdup(name);
|
|
|
|
|
entry->uppercase_name = uppercase_dup(name);
|
|
|
|
|
entry->value = xstrdup(value);
|
|
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
static void
|
|
|
|
|
free_entry(struct entry *entry)
|
|
|
|
|
{
|
|
|
|
|
free(entry->name);
|
|
|
|
|
free(entry->uppercase_name);
|
|
|
|
|
free(entry->value);
|
|
|
|
|
free(entry->summary);
|
2021-06-03 00:10:21 +01:00
|
|
|
free_description(entry->description);
|
2015-07-30 15:07:21 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:20 +02:00
|
|
|
static struct interface *
|
|
|
|
|
create_interface(struct location loc, const char *name, int version)
|
|
|
|
|
{
|
|
|
|
|
struct interface *interface;
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
interface = xzalloc(sizeof *interface);
|
2015-07-30 15:07:20 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-08 16:51:16 -07:00
|
|
|
/* 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.
|
|
|
|
|
*
|
2016-09-07 06:25:27 -07:00
|
|
|
* Returns -1 on error, or a non-negative integer on success
|
2016-07-08 16:51:16 -07:00
|
|
|
*/
|
2015-07-30 16:42:00 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
/* 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-24 09:56:37 +10:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-19 12:50:34 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
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;
|
2011-01-21 21:57:55 -05:00
|
|
|
struct enumeration *enumeration;
|
|
|
|
|
struct entry *entry;
|
2015-07-30 15:07:22 +02:00
|
|
|
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;
|
2023-07-19 12:50:34 +02:00
|
|
|
const char *deprecated_since = NULL;
|
2015-07-30 15:07:22 +02:00
|
|
|
const char *allow_null = NULL;
|
2015-10-26 19:39:52 +00:00
|
|
|
const char *enumeration_name = NULL;
|
|
|
|
|
const char *bitfield = NULL;
|
2015-07-30 15:07:22 +02:00
|
|
|
int i, version = 0;
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2013-11-15 14:21:11 -08:00
|
|
|
ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
|
2010-08-03 09:26:44 -04:00
|
|
|
for (i = 0; atts[i]; i += 2) {
|
|
|
|
|
if (strcmp(atts[i], "name") == 0)
|
|
|
|
|
name = atts[i + 1];
|
2015-11-04 12:40:54 +08:00
|
|
|
if (strcmp(atts[i], "version") == 0) {
|
2015-07-30 16:42:00 +02:00
|
|
|
version = strtouint(atts[i + 1]);
|
|
|
|
|
if (version == -1)
|
|
|
|
|
fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
|
2015-11-04 12:40:54 +08:00
|
|
|
}
|
2010-08-03 09:26:44 -04:00
|
|
|
if (strcmp(atts[i], "type") == 0)
|
|
|
|
|
type = atts[i + 1];
|
2011-01-21 21:57:55 -05:00
|
|
|
if (strcmp(atts[i], "value") == 0)
|
|
|
|
|
value = atts[i + 1];
|
2010-08-09 21:25:50 -04:00
|
|
|
if (strcmp(atts[i], "interface") == 0)
|
|
|
|
|
interface_name = atts[i + 1];
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
if (strcmp(atts[i], "summary") == 0)
|
|
|
|
|
summary = atts[i + 1];
|
2012-03-05 10:31:53 -05:00
|
|
|
if (strcmp(atts[i], "since") == 0)
|
|
|
|
|
since = atts[i + 1];
|
2023-07-19 12:50:34 +02:00
|
|
|
if (strcmp(atts[i], "deprecated-since") == 0)
|
|
|
|
|
deprecated_since = atts[i + 1];
|
2012-07-02 20:03:30 +10:00
|
|
|
if (strcmp(atts[i], "allow-null") == 0)
|
|
|
|
|
allow_null = atts[i + 1];
|
2015-10-26 19:39:52 +00:00
|
|
|
if (strcmp(atts[i], "enum") == 0)
|
|
|
|
|
enumeration_name = atts[i + 1];
|
|
|
|
|
if (strcmp(atts[i], "bitfield") == 0)
|
|
|
|
|
bitfield = atts[i + 1];
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
2011-07-25 18:14:20 -07:00
|
|
|
ctx->character_data_length = 0;
|
2010-09-14 15:52:43 -04:00
|
|
|
if (strcmp(element_name, "protocol") == 0) {
|
2011-04-13 16:50:02 -04:00
|
|
|
if (name == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no protocol name given");
|
2010-09-14 15:52:43 -04:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
|
2013-07-13 00:35:21 -04:00
|
|
|
ctx->protocol->name = xstrdup(name);
|
2010-09-14 15:52:43 -04:00
|
|
|
ctx->protocol->uppercase_name = uppercase_dup(name);
|
2011-07-25 18:14:20 -07:00
|
|
|
} else if (strcmp(element_name, "copyright") == 0) {
|
2015-05-15 17:12:41 +02:00
|
|
|
|
2010-09-14 15:52:43 -04:00
|
|
|
} else if (strcmp(element_name, "interface") == 0) {
|
2011-04-13 16:50:02 -04:00
|
|
|
if (name == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no interface name given");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2011-04-13 16:50:02 -04:00
|
|
|
if (version == 0)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no interface version given");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
|
2015-07-30 15:07:20 +02:00
|
|
|
interface = create_interface(ctx->loc, name, version);
|
|
|
|
|
ctx->interface = interface;
|
2010-08-03 09:26:44 -04:00
|
|
|
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)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no request name given");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
|
2015-07-30 15:07:20 +02:00
|
|
|
message = create_message(ctx->loc, name);
|
2010-08-03 09:26:44 -04:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2010-09-02 20:22:42 -04:00
|
|
|
if (type != NULL && strcmp(type, "destructor") == 0)
|
|
|
|
|
message->destructor = 1;
|
|
|
|
|
|
2017-01-24 09:56:37 +10:00
|
|
|
version = version_from_since(ctx, since);
|
2014-05-08 23:39:47 +02:00
|
|
|
if (version < ctx->interface->since)
|
2014-05-12 15:17:52 -07:00
|
|
|
warn(&ctx->loc, "since version not increasing\n");
|
2014-05-08 23:39:47 +02:00
|
|
|
ctx->interface->since = version;
|
|
|
|
|
message->since = version;
|
2012-03-05 10:31:53 -05:00
|
|
|
|
2023-07-19 12:50:34 +02:00
|
|
|
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;
|
|
|
|
|
|
2011-05-04 15:51:47 -04:00
|
|
|
if (strcmp(name, "destroy") == 0 && !message->destructor)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "destroy request should be destructor type");
|
2011-05-04 15:51:47 -04:00
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
ctx->message = message;
|
|
|
|
|
} else if (strcmp(element_name, "arg") == 0) {
|
2012-10-12 11:28:25 +02:00
|
|
|
if (name == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no argument name given");
|
2012-10-12 11:28:25 +02:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
|
2015-07-30 15:07:20 +02:00
|
|
|
arg = create_arg(name);
|
|
|
|
|
if (!set_arg_type(arg, type))
|
2013-11-15 14:29:40 -08:00
|
|
|
fail(&ctx->loc, "unknown type (%s)", type);
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2011-10-24 16:04:09 -04:00
|
|
|
switch (arg->type) {
|
|
|
|
|
case NEW_ID:
|
2013-11-15 13:26:03 -08:00
|
|
|
ctx->message->new_id_count++;
|
2017-03-17 17:35:38 +00:00
|
|
|
/* fallthrough */
|
2011-10-24 16:04:09 -04:00
|
|
|
case OBJECT:
|
2019-04-13 17:30:46 -04:00
|
|
|
if (interface_name) {
|
|
|
|
|
validate_identifier(&ctx->loc,
|
|
|
|
|
interface_name,
|
|
|
|
|
STANDALONE_IDENT);
|
2013-07-13 00:35:21 -04:00
|
|
|
arg->interface_name = xstrdup(interface_name);
|
2019-04-13 17:30:46 -04:00
|
|
|
}
|
2011-10-24 16:04:09 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (interface_name != NULL)
|
2013-11-15 14:29:40 -08:00
|
|
|
fail(&ctx->loc, "interface attribute not allowed for type %s", type);
|
2011-10-24 16:04:09 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
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);
|
2012-07-02 20:03:30 +10:00
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
if (!is_nullable_type(arg))
|
|
|
|
|
fail(&ctx->loc,
|
|
|
|
|
"allow-null is only valid for objects, strings, and arrays");
|
|
|
|
|
}
|
2012-07-02 20:03:30 +10:00
|
|
|
|
2015-10-26 19:39:52 +00:00
|
|
|
if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
|
|
|
|
|
arg->enumeration_name = NULL;
|
|
|
|
|
else
|
|
|
|
|
arg->enumeration_name = xstrdup(enumeration_name);
|
|
|
|
|
|
2012-01-19 14:13:36 -08:00
|
|
|
if (summary)
|
2013-07-13 00:35:21 -04:00
|
|
|
arg->summary = xstrdup(summary);
|
2012-01-19 14:13:36 -08:00
|
|
|
|
2011-01-21 21:57:55 -05:00
|
|
|
wl_list_insert(ctx->message->arg_list.prev, &arg->link);
|
2011-07-12 13:22:25 -04:00
|
|
|
ctx->message->arg_count++;
|
2011-01-21 21:57:55 -05:00
|
|
|
} else if (strcmp(element_name, "enum") == 0) {
|
2011-04-13 16:50:02 -04:00
|
|
|
if (name == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no enum name given");
|
2011-01-21 21:57:55 -05:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, TRAILING_IDENT);
|
2015-07-30 15:07:20 +02:00
|
|
|
enumeration = create_enumeration(name);
|
2015-10-26 19:39:52 +00:00
|
|
|
|
|
|
|
|
if (bitfield == NULL || strcmp(bitfield, "false") == 0)
|
|
|
|
|
enumeration->bitfield = false;
|
|
|
|
|
else if (strcmp(bitfield, "true") == 0)
|
|
|
|
|
enumeration->bitfield = true;
|
|
|
|
|
else
|
|
|
|
|
fail(&ctx->loc,
|
2015-12-05 12:39:12 +00:00
|
|
|
"invalid value (%s) for bitfield attribute (only true/false are accepted)",
|
|
|
|
|
bitfield);
|
2015-10-26 19:39:52 +00:00
|
|
|
|
2011-01-21 21:57:55 -05:00
|
|
|
wl_list_insert(ctx->interface->enumeration_list.prev,
|
|
|
|
|
&enumeration->link);
|
|
|
|
|
|
|
|
|
|
ctx->enumeration = enumeration;
|
|
|
|
|
} else if (strcmp(element_name, "entry") == 0) {
|
2011-10-31 11:21:38 -04:00
|
|
|
if (name == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "no entry name given");
|
2011-10-31 11:21:38 -04:00
|
|
|
|
2019-04-13 17:30:46 -04:00
|
|
|
validate_identifier(&ctx->loc, name, TRAILING_IDENT);
|
2015-07-30 15:07:20 +02:00
|
|
|
entry = create_entry(name, value);
|
2017-01-24 09:56:38 +10:00
|
|
|
|
2023-07-19 12:50:34 +02:00
|
|
|
version = version_from_since(ctx, since);
|
2017-01-24 09:56:38 +10:00
|
|
|
if (version < ctx->enumeration->since)
|
|
|
|
|
warn(&ctx->loc, "since version not increasing\n");
|
|
|
|
|
ctx->enumeration->since = version;
|
|
|
|
|
entry->since = version;
|
2015-07-30 15:07:20 +02:00
|
|
|
|
2023-07-19 12:50:34 +02:00
|
|
|
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;
|
|
|
|
|
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
if (summary)
|
2013-07-13 00:35:21 -04:00
|
|
|
entry->summary = xstrdup(summary);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
else
|
|
|
|
|
entry->summary = NULL;
|
2011-01-21 21:57:55 -05:00
|
|
|
wl_list_insert(ctx->enumeration->entry_list.prev,
|
|
|
|
|
&entry->link);
|
2021-06-03 00:10:21 +01:00
|
|
|
ctx->entry = entry;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
} else if (strcmp(element_name, "description") == 0) {
|
|
|
|
|
if (summary == NULL)
|
2013-11-15 14:21:11 -08:00
|
|
|
fail(&ctx->loc, "description without summary");
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
description = xzalloc(sizeof *description);
|
2013-07-13 00:35:21 -04:00
|
|
|
description->summary = xstrdup(summary);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
|
|
|
|
if (ctx->message)
|
|
|
|
|
ctx->message->description = description;
|
2021-06-03 00:10:21 +01:00
|
|
|
else if (ctx->entry)
|
|
|
|
|
ctx->entry->description = description;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
else if (ctx->enumeration)
|
|
|
|
|
ctx->enumeration->description = description;
|
|
|
|
|
else if (ctx->interface)
|
|
|
|
|
ctx->interface->description = description;
|
|
|
|
|
else
|
2012-01-19 14:13:36 -08:00
|
|
|
ctx->protocol->description = description;
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
ctx->description = description;
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-05 12:39:12 +00:00
|
|
|
static struct enumeration *
|
|
|
|
|
find_enumeration(struct protocol *protocol,
|
|
|
|
|
struct interface *interface,
|
|
|
|
|
char *enum_attribute)
|
|
|
|
|
{
|
|
|
|
|
struct interface *i;
|
|
|
|
|
struct enumeration *e;
|
|
|
|
|
char *enum_name;
|
2016-07-15 16:23:48 -07:00
|
|
|
uint32_t idx = 0, j;
|
2015-12-05 12:39:12 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-26 19:39:52 +00:00
|
|
|
static void
|
2015-12-05 12:39:12 +00:00
|
|
|
verify_arguments(struct parse_context *ctx,
|
|
|
|
|
struct interface *interface,
|
|
|
|
|
struct wl_list *messages,
|
|
|
|
|
struct wl_list *enumerations)
|
2015-10-26 19:39:52 +00:00
|
|
|
{
|
|
|
|
|
struct message *m;
|
|
|
|
|
wl_list_for_each(m, messages, link) {
|
|
|
|
|
struct arg *a;
|
|
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
2015-12-05 12:39:12 +00:00
|
|
|
struct enumeration *e;
|
2015-10-26 19:39:52 +00:00
|
|
|
|
|
|
|
|
if (!a->enumeration_name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
2015-12-05 12:39:12 +00:00
|
|
|
e = find_enumeration(ctx->protocol, interface,
|
|
|
|
|
a->enumeration_name);
|
|
|
|
|
|
2015-10-26 19:39:52 +00:00
|
|
|
switch (a->type) {
|
|
|
|
|
case INT:
|
2018-05-25 17:24:41 -04:00
|
|
|
if (e && e->bitfield)
|
2015-10-26 19:39:52 +00:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 21:03:23 -05:00
|
|
|
#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
|
|
|
|
|
|
2011-07-25 18:14:20 -07:00
|
|
|
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);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
} 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);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
ctx->description = NULL;
|
|
|
|
|
} else if (strcmp(name, "request") == 0 ||
|
|
|
|
|
strcmp(name, "event") == 0) {
|
|
|
|
|
ctx->message = NULL;
|
|
|
|
|
} else if (strcmp(name, "enum") == 0) {
|
2015-03-19 16:56:23 +08:00
|
|
|
if (wl_list_empty(&ctx->enumeration->entry_list)) {
|
|
|
|
|
fail(&ctx->loc, "enumeration %s was empty",
|
|
|
|
|
ctx->enumeration->name);
|
|
|
|
|
}
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
ctx->enumeration = NULL;
|
2021-06-03 00:10:21 +01:00
|
|
|
} else if (strcmp(name, "entry") == 0) {
|
|
|
|
|
ctx->entry = NULL;
|
2015-12-05 12:39:12 +00:00
|
|
|
} else if (strcmp(name, "protocol") == 0) {
|
|
|
|
|
struct interface *i;
|
2015-10-26 19:39:52 +00:00
|
|
|
|
2015-12-05 12:39:12 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2011-07-25 18:14:20 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
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)
|
2016-05-24 13:55:12 -06:00
|
|
|
printf("#define %s_%s %d\n",
|
2010-08-03 09:26:44 -04:00
|
|
|
interface->uppercase_name, m->uppercase_name, opcode++);
|
|
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-08 23:39:49 +02:00
|
|
|
static void
|
|
|
|
|
emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
|
|
|
|
|
{
|
|
|
|
|
struct message *m;
|
|
|
|
|
|
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);
|
2016-05-24 13:55:12 -06:00
|
|
|
printf("#define %s_%s_SINCE_VERSION %d\n",
|
2014-05-08 23:39:49 +02:00
|
|
|
interface->uppercase_name, m->uppercase_name, m->since);
|
2016-03-01 09:26:21 +10:00
|
|
|
}
|
2014-05-08 23:39:49 +02:00
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
static void
|
|
|
|
|
emit_type(struct arg *a)
|
|
|
|
|
{
|
|
|
|
|
switch (a->type) {
|
|
|
|
|
default:
|
|
|
|
|
case INT:
|
2010-08-26 21:49:44 -04:00
|
|
|
case FD:
|
2011-07-07 13:39:08 -04:00
|
|
|
printf("int32_t ");
|
2010-08-09 21:25:50 -04:00
|
|
|
break;
|
|
|
|
|
case NEW_ID:
|
|
|
|
|
case UNSIGNED:
|
|
|
|
|
printf("uint32_t ");
|
|
|
|
|
break;
|
2012-05-08 17:17:25 +01:00
|
|
|
case FIXED:
|
|
|
|
|
printf("wl_fixed_t ");
|
|
|
|
|
break;
|
2010-08-09 21:25:50 -04:00
|
|
|
case STRING:
|
|
|
|
|
printf("const char *");
|
|
|
|
|
break;
|
|
|
|
|
case OBJECT:
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("struct %s *", a->interface_name);
|
2010-08-09 21:25:50 -04:00
|
|
|
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;
|
2010-09-02 20:22:42 -04:00
|
|
|
int has_destructor, has_destroy;
|
2010-08-09 21:25:50 -04:00
|
|
|
|
2016-03-01 09:26:21 +10:00
|
|
|
printf("/** @ingroup iface_%s */\n", interface->name);
|
2010-08-17 21:23:10 -04:00
|
|
|
printf("static inline void\n"
|
2011-04-18 10:24:11 -04:00
|
|
|
"%s_set_user_data(struct %s *%s, void *user_data)\n"
|
2010-08-17 21:23:10 -04:00
|
|
|
"{\n"
|
|
|
|
|
"\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
|
|
|
|
|
"}\n\n",
|
|
|
|
|
interface->name, interface->name, interface->name,
|
|
|
|
|
interface->name);
|
|
|
|
|
|
2016-03-01 09:26:21 +10:00
|
|
|
printf("/** @ingroup iface_%s */\n", interface->name);
|
2010-08-17 21:23:10 -04:00
|
|
|
printf("static inline void *\n"
|
2011-04-18 10:24:11 -04:00
|
|
|
"%s_get_user_data(struct %s *%s)\n"
|
2010-08-17 21:23:10 -04:00
|
|
|
"{\n"
|
|
|
|
|
"\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
|
|
|
|
|
"}\n\n",
|
|
|
|
|
interface->name, interface->name, interface->name,
|
|
|
|
|
interface->name);
|
|
|
|
|
|
2015-11-12 13:53:15 -06:00
|
|
|
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);
|
|
|
|
|
|
2010-09-02 20:22:42 -04:00
|
|
|
has_destructor = 0;
|
|
|
|
|
has_destroy = 0;
|
|
|
|
|
wl_list_for_each(m, message_list, link) {
|
|
|
|
|
if (m->destructor)
|
|
|
|
|
has_destructor = 1;
|
2013-02-25 16:01:38 -05:00
|
|
|
if (strcmp(m->name, "destroy") == 0)
|
2010-09-02 20:22:42 -04:00
|
|
|
has_destroy = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!has_destructor && has_destroy) {
|
2013-11-15 14:37:55 -08:00
|
|
|
fail(&interface->loc,
|
|
|
|
|
"interface '%s' has method named destroy "
|
|
|
|
|
"but no destructor",
|
|
|
|
|
interface->name);
|
2010-09-02 20:22:42 -04:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-01 09:26:21 +10:00
|
|
|
if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
|
|
|
|
|
printf("/** @ingroup iface_%s */\n", interface->name);
|
2010-09-02 20:22:42 -04:00
|
|
|
printf("static inline void\n"
|
2011-04-18 10:24:11 -04:00
|
|
|
"%s_destroy(struct %s *%s)\n"
|
2010-09-02 20:22:42 -04:00
|
|
|
"{\n"
|
|
|
|
|
"\twl_proxy_destroy("
|
|
|
|
|
"(struct wl_proxy *) %s);\n"
|
|
|
|
|
"}\n\n",
|
|
|
|
|
interface->name, interface->name, interface->name,
|
|
|
|
|
interface->name);
|
2016-03-01 09:26:21 +10:00
|
|
|
}
|
2010-09-02 20:22:42 -04:00
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
if (wl_list_empty(message_list))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(m, message_list, link) {
|
2013-11-15 13:26:03 -08:00
|
|
|
if (m->new_id_count > 1) {
|
2013-11-15 14:37:55 -08:00
|
|
|
warn(&m->loc,
|
|
|
|
|
"request '%s::%s' has more than "
|
|
|
|
|
"one new_id arg, not emitting stub\n",
|
|
|
|
|
interface->name, m->name);
|
2013-11-15 13:26:03 -08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
ret = NULL;
|
|
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
|
|
|
|
if (a->type == NEW_ID)
|
|
|
|
|
ret = a;
|
|
|
|
|
}
|
|
|
|
|
|
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");
|
2012-10-08 13:21:55 -04:00
|
|
|
if (ret && ret->interface_name == NULL)
|
|
|
|
|
printf("static inline void *\n");
|
|
|
|
|
else if (ret)
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("static inline struct %s *\n",
|
2010-08-09 21:25:50 -04:00
|
|
|
ret->interface_name);
|
|
|
|
|
else
|
|
|
|
|
printf("static inline void\n");
|
|
|
|
|
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("%s_%s(struct %s *%s",
|
2010-08-09 21:25:50 -04:00
|
|
|
interface->name, m->name,
|
|
|
|
|
interface->name, interface->name);
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
2012-10-08 13:21:55 -04:00
|
|
|
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)
|
2010-08-09 21:25:50 -04:00
|
|
|
continue;
|
|
|
|
|
printf(", ");
|
|
|
|
|
emit_type(a);
|
|
|
|
|
printf("%s", a->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf(")\n"
|
|
|
|
|
"{\n");
|
2021-07-21 16:32:36 -05:00
|
|
|
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");
|
|
|
|
|
}
|
client: Introduce functions to allocate and marshal proxies atomically
The server requires clients to only allocate one ID ahead of the previously
highest ID in order to keep the ID range tight. Failure to do so will
make the server close the client connection. However, the way we allocate
new IDs is racy. The generated code looks like:
new_proxy = wl_proxy_create(...);
wl_proxy_marshal(proxy, ... new_proxy, ...);
If two threads do this at the same time, there's a chance that thread A
will allocate a proxy, then get pre-empted by thread B which then allocates
a proxy and then passes it to wl_proxy_marshal(). The ID for thread As
proxy will be one higher that the currently highest ID, but the ID for
thread Bs proxy will be two higher. But since thread B prempted thread A
before it could send its new ID, B will send its new ID first, the server
will see the ID from thread Bs proxy first, and will reject it.
We fix this by introducing wl_proxy_marshal_constructor(). This
function is identical to wl_proxy_marshal(), except that it will
allocate a wl_proxy for NEW_ID arguments and send it, all under the
display mutex. By introducing a new function, we maintain backwards
compatibility with older code from the generator, and make sure that
the new generated code has an explicit dependency on a new enough
libwayland-client.so.
A virtual Wayland merit badge goes to Kalle Vahlman, who tracked this
down and analyzed the issue.
Reported-by: Kalle Vahlman <kalle.vahlman@movial.com>
2013-11-14 21:29:06 -08:00
|
|
|
} else {
|
2015-11-12 13:53:15 -06:00
|
|
|
/* No args have type="new_id" */
|
2021-07-21 16:32:36 -05:00
|
|
|
printf(", NULL");
|
2012-10-08 13:21:55 -04:00
|
|
|
}
|
2010-08-09 21:25:50 -04:00
|
|
|
|
2021-07-21 16:32:36 -05:00
|
|
|
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");
|
|
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
client: Introduce functions to allocate and marshal proxies atomically
The server requires clients to only allocate one ID ahead of the previously
highest ID in order to keep the ID range tight. Failure to do so will
make the server close the client connection. However, the way we allocate
new IDs is racy. The generated code looks like:
new_proxy = wl_proxy_create(...);
wl_proxy_marshal(proxy, ... new_proxy, ...);
If two threads do this at the same time, there's a chance that thread A
will allocate a proxy, then get pre-empted by thread B which then allocates
a proxy and then passes it to wl_proxy_marshal(). The ID for thread As
proxy will be one higher that the currently highest ID, but the ID for
thread Bs proxy will be two higher. But since thread B prempted thread A
before it could send its new ID, B will send its new ID first, the server
will see the ID from thread Bs proxy first, and will reject it.
We fix this by introducing wl_proxy_marshal_constructor(). This
function is identical to wl_proxy_marshal(), except that it will
allocate a wl_proxy for NEW_ID arguments and send it, all under the
display mutex. By introducing a new function, we maintain backwards
compatibility with older code from the generator, and make sure that
the new generated code has an explicit dependency on a new enough
libwayland-client.so.
A virtual Wayland merit badge goes to Kalle Vahlman, who tracked this
down and analyzed the issue.
Reported-by: Kalle Vahlman <kalle.vahlman@movial.com>
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);
|
|
|
|
|
}
|
2010-08-09 21:25:50 -04:00
|
|
|
}
|
|
|
|
|
printf(");\n");
|
|
|
|
|
|
2012-10-08 13:21:55 -04:00
|
|
|
if (ret && ret->interface_name == NULL)
|
|
|
|
|
printf("\n\treturn (void *) %s;\n", ret->name);
|
|
|
|
|
else if (ret)
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("\n\treturn (struct %s *) %s;\n",
|
2010-08-09 21:25:50 -04:00
|
|
|
ret->interface_name, ret->name);
|
|
|
|
|
|
|
|
|
|
printf("}\n\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-02 15:16:33 +02:00
|
|
|
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) {
|
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);
|
2016-03-31 18:55:54 -05:00
|
|
|
printf(" * @param resource_ The client's resource\n");
|
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");
|
2012-03-02 15:16:33 +02:00
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-07 18:21:30 +02:00
|
|
|
static void
|
|
|
|
|
emit_validator(struct interface *interface, struct enumeration *e)
|
|
|
|
|
{
|
|
|
|
|
struct entry *entry;
|
|
|
|
|
|
2025-02-23 23:38:15 +01:00
|
|
|
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);
|
|
|
|
|
|
2024-07-07 18:21:30 +02:00
|
|
|
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"
|
2024-07-07 18:39:51 +02:00
|
|
|
"%s_%s_is_valid(uint32_t value, uint32_t version) {\n",
|
2024-07-07 18:21:30 +02:00
|
|
|
interface->name, interface->name, e->name,
|
|
|
|
|
interface->name, e->name,
|
|
|
|
|
interface->name, e->name);
|
2024-07-07 18:39:51 +02:00
|
|
|
|
|
|
|
|
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");
|
2024-07-07 18:21:30 +02:00
|
|
|
}
|
2024-07-07 18:39:51 +02:00
|
|
|
printf("}\n");
|
2025-02-23 23:38:15 +01:00
|
|
|
|
|
|
|
|
printf("#endif /* %s_%s_ENUM_IS_VALID */\n\n",
|
|
|
|
|
interface->uppercase_name, e->uppercase_name);
|
2024-07-07 18:21:30 +02:00
|
|
|
}
|
|
|
|
|
|
2011-01-21 21:57:55 -05:00
|
|
|
static void
|
2022-09-17 10:53:56 +02:00
|
|
|
emit_enumerations(struct interface *interface, bool with_validators)
|
2011-01-21 21:57:55 -05:00
|
|
|
{
|
|
|
|
|
struct enumeration *e;
|
|
|
|
|
struct entry *entry;
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(e, &interface->enumeration_list, link) {
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
struct description *desc = e->description;
|
|
|
|
|
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("#ifndef %s_%s_ENUM\n",
|
2011-01-23 12:21:15 +01:00
|
|
|
interface->uppercase_name, e->uppercase_name);
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("#define %s_%s_ENUM\n",
|
2011-01-23 12:21:15 +01:00
|
|
|
interface->uppercase_name, e->uppercase_name);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
|
|
|
|
|
if (desc) {
|
2012-05-07 23:41:48 -04:00
|
|
|
printf("/**\n");
|
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);
|
scanner: Support documentation elements
On Wed, 18 Jan 2012 12:29:37 -0800
"Kristensen, Kristian H" <kristian.h.kristensen@intel.com> wrote:
> Yeah, that looks good. I was thinking of a separate <description> tag
> to avoid stuffing too much into an attribute.
How does this look? It adds a summary attribute to atomic elements,
and a <description> tag with a summary for others. Spits out enum
documentation like this:
/**
* wl_display_error - global error values
* @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
* @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the specified interface
* @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
*
* These errors are global and can be emitted in response to any server request.
*/
enum wl_display_error {
WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
WL_DISPLAY_ERROR_INVALID_METHOD = 1,
WL_DISPLAY_ERROR_NO_MEMORY = 2,
};
and structure documentation like this:
/**
* wl_display - core global object
* @bind: bind an object to the display
* @sync: (none)
*
* The core global object. This is a special singleton object. It is used for
* internal wayland protocol features.
*/
struct wl_display_interface {
void (*bind)(struct wl_client *client,
struct wl_resource *resource,
uint32_t name,
const char *interface,
uint32_t version,
uint32_t id);
void (*sync)(struct wl_client *client,
struct wl_resource *resource,
uint32_t callback);
};
2012-01-18 14:09:47 -08:00
|
|
|
printf(" */\n");
|
|
|
|
|
}
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("enum %s_%s {\n", interface->name, e->name);
|
2016-03-01 09:26:21 +10:00
|
|
|
wl_list_for_each(entry, &e->entry_list, link) {
|
2021-06-03 00:10:21 +01:00
|
|
|
desc = entry->description;
|
|
|
|
|
if (entry->summary || entry->since > 1 || desc) {
|
2017-01-24 09:56:38 +10:00
|
|
|
printf("\t/**\n");
|
|
|
|
|
if (entry->summary)
|
|
|
|
|
printf("\t * %s\n", entry->summary);
|
2021-06-03 00:10:21 +01:00
|
|
|
if (desc) {
|
|
|
|
|
printf("\t * %s\n", desc->summary);
|
|
|
|
|
printf("\t *\n");
|
|
|
|
|
if (desc->text)
|
|
|
|
|
desc_dump(desc->text, "\t * ");
|
|
|
|
|
}
|
2017-01-24 09:56:38 +10:00
|
|
|
if (entry->since > 1)
|
|
|
|
|
printf("\t * @since %d\n", entry->since);
|
2023-07-19 12:50:34 +02:00
|
|
|
if (entry->deprecated_since > 0)
|
|
|
|
|
printf("\t * @deprecated Deprecated since version %d\n",
|
|
|
|
|
entry->deprecated_since);
|
2017-01-24 09:56:38 +10:00
|
|
|
printf("\t */\n");
|
|
|
|
|
}
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("\t%s_%s_%s = %s,\n",
|
2011-01-21 21:57:55 -05:00
|
|
|
interface->uppercase_name,
|
|
|
|
|
e->uppercase_name,
|
|
|
|
|
entry->uppercase_name, entry->value);
|
2016-03-01 09:26:21 +10:00
|
|
|
}
|
2011-01-23 12:21:15 +01:00
|
|
|
printf("};\n");
|
2017-01-24 09:56:38 +10:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("#endif /* %s_%s_ENUM */\n\n",
|
2011-01-23 12:21:15 +01:00
|
|
|
interface->uppercase_name, e->uppercase_name);
|
2025-02-23 23:38:15 +01:00
|
|
|
|
|
|
|
|
if (with_validators)
|
|
|
|
|
emit_validator(interface, e);
|
2011-01-21 21:57:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static void
|
2014-08-08 18:22:48 -04:00
|
|
|
emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
|
2010-08-03 09:26:44 -04:00
|
|
|
{
|
|
|
|
|
struct message *m;
|
|
|
|
|
struct arg *a;
|
2014-08-08 18:22:48 -04:00
|
|
|
int n;
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
if (wl_list_empty(message_list))
|
|
|
|
|
return;
|
|
|
|
|
|
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");
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("struct %s_%s {\n", interface->name,
|
2014-08-08 18:22:48 -04:00
|
|
|
(side == SERVER) ? "interface" : "listener");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
|
|
|
|
wl_list_for_each(m, message_list, link) {
|
2012-01-19 14:13:36 -08:00
|
|
|
struct description *mdesc = m->description;
|
|
|
|
|
|
|
|
|
|
printf("\t/**\n");
|
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 * ");
|
|
|
|
|
}
|
2012-01-19 14:13:36 -08:00
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
2014-08-08 18:22:48 -04:00
|
|
|
if (side == SERVER && a->type == NEW_ID &&
|
2012-10-08 13:21:55 -04:00
|
|
|
a->interface_name == NULL)
|
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");
|
2012-10-08 13:21:55 -04:00
|
|
|
|
2016-03-01 09:26:21 +10:00
|
|
|
if (a->summary)
|
|
|
|
|
printf("\t * @param %s %s\n", a->name,
|
|
|
|
|
a->summary);
|
2012-01-19 14:13:36 -08:00
|
|
|
}
|
2023-07-19 12:50:34 +02:00
|
|
|
if (m->since > 1)
|
2016-03-01 09:26:21 +10:00
|
|
|
printf("\t * @since %d\n", m->since);
|
2023-07-19 12:50:34 +02:00
|
|
|
if (m->deprecated_since > 0)
|
|
|
|
|
printf("\t * @deprecated Deprecated since version %d\n",
|
|
|
|
|
m->deprecated_since);
|
2012-01-24 18:30:13 +02:00
|
|
|
printf("\t */\n");
|
2010-08-03 09:26:44 -04:00
|
|
|
printf("\tvoid (*%s)(", m->name);
|
|
|
|
|
|
2010-08-10 10:53:44 -04:00
|
|
|
n = strlen(m->name) + 17;
|
2014-08-08 18:22:48 -04:00
|
|
|
if (side == SERVER) {
|
2010-08-10 10:53:44 -04:00
|
|
|
printf("struct wl_client *client,\n"
|
2011-08-18 17:53:50 -04:00
|
|
|
"%sstruct wl_resource *resource",
|
|
|
|
|
indent(n));
|
2010-08-03 09:26:44 -04:00
|
|
|
} else {
|
2010-08-10 10:53:44 -04:00
|
|
|
printf("void *data,\n"),
|
2011-04-18 10:24:11 -04:00
|
|
|
printf("%sstruct %s *%s",
|
2010-08-10 10:53:44 -04:00
|
|
|
indent(n), interface->name, interface->name);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
2010-08-10 10:53:44 -04:00
|
|
|
printf(",\n%s", indent(n));
|
|
|
|
|
|
2014-08-08 18:22:48 -04:00
|
|
|
if (side == SERVER && a->type == OBJECT)
|
2011-08-27 12:05:09 -04:00
|
|
|
printf("struct wl_resource *");
|
2014-08-08 18:22:48 -04:00
|
|
|
else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
|
2012-10-08 13:21:55 -04:00
|
|
|
printf("const char *interface, uint32_t version, uint32_t ");
|
2014-08-08 18:22:48 -04:00
|
|
|
else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
|
2013-06-27 20:09:18 -05:00
|
|
|
printf("void *");
|
2012-10-08 13:21:55 -04:00
|
|
|
|
2014-08-08 18:22:48 -04:00
|
|
|
else if (side == CLIENT && a->type == NEW_ID)
|
2012-06-28 22:01:58 -04:00
|
|
|
printf("struct %s *", a->interface_name);
|
2011-08-27 12:05:09 -04:00
|
|
|
else
|
|
|
|
|
emit_type(a);
|
|
|
|
|
|
2010-08-10 10:53:44 -04:00
|
|
|
printf("%s", a->name);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf(");\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("};\n\n");
|
2010-08-10 10:53:44 -04:00
|
|
|
|
2014-08-08 18:22:48 -04:00
|
|
|
if (side == CLIENT) {
|
2016-03-01 09:26:21 +10:00
|
|
|
printf("/**\n"
|
2016-05-16 23:18:06 -07:00
|
|
|
" * @ingroup iface_%s\n"
|
2016-03-01 09:26:21 +10:00
|
|
|
" */\n", interface->name);
|
2010-08-10 10:53:44 -04:00
|
|
|
printf("static inline int\n"
|
2011-04-18 10:24:11 -04:00
|
|
|
"%s_add_listener(struct %s *%s,\n"
|
|
|
|
|
"%sconst struct %s_listener *listener, void *data)\n"
|
2010-08-10 10:53:44 -04:00
|
|
|
"{\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)),
|
2010-08-10 10:53:44 -04:00
|
|
|
interface->name,
|
|
|
|
|
interface->name,
|
|
|
|
|
indent(37));
|
|
|
|
|
}
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
2015-04-29 16:46:51 +03:00
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static void
|
2014-08-08 18:22:47 -04:00
|
|
|
emit_header(struct protocol *protocol, enum side side)
|
2010-08-03 09:26:44 -04:00
|
|
|
{
|
2015-07-30 15:07:21 +02:00
|
|
|
struct interface *i, *i_next;
|
2015-04-29 16:46:51 +03:00
|
|
|
struct wl_array types;
|
2014-08-08 18:22:47 -04:00
|
|
|
const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
|
2015-04-29 16:46:51 +03:00
|
|
|
char **p, *prev;
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2016-06-06 10:58:56 -07:00
|
|
|
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
|
2016-05-05 17:27:57 +02:00
|
|
|
|
2011-07-25 18:14:20 -07:00
|
|
|
printf("#ifndef %s_%s_PROTOCOL_H\n"
|
2010-09-14 15:52:43 -04:00
|
|
|
"#define %s_%s_PROTOCOL_H\n"
|
2010-08-03 09:26:44 -04:00
|
|
|
"\n"
|
2016-04-17 12:29:22 +01:00
|
|
|
"#include <stdint.h>\n"
|
|
|
|
|
"#include <stddef.h>\n"
|
|
|
|
|
"#include \"%s\"\n\n"
|
2010-08-03 09:26:44 -04:00
|
|
|
"#ifdef __cplusplus\n"
|
|
|
|
|
"extern \"C\" {\n"
|
2016-05-19 20:31:16 -06:00
|
|
|
"#endif\n\n",
|
2010-09-14 15:52:43 -04:00
|
|
|
protocol->uppercase_name, s,
|
2012-07-05 16:31:29 +12:00
|
|
|
protocol->uppercase_name, s,
|
2015-04-29 16:46:51 +03:00
|
|
|
get_include_name(protocol->core_headers, side));
|
2016-05-19 20:31:16 -06:00
|
|
|
if (side == SERVER)
|
|
|
|
|
printf("struct wl_client;\n"
|
|
|
|
|
"struct wl_resource;\n\n");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2016-03-01 09:26:21 +10:00
|
|
|
emit_mainpage_blurb(protocol, side);
|
|
|
|
|
|
2015-04-29 16:46:51 +03:00
|
|
|
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);
|
|
|
|
|
}
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
wl_list_for_each(i, &protocol->interface_list, link) {
|
2015-04-29 16:46:51 +03:00
|
|
|
p = fail_on_null(wl_array_add(&types, sizeof *p));
|
|
|
|
|
*p = i->name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-23 07:58:13 +10:00
|
|
|
if (types.size > 0)
|
|
|
|
|
qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
|
|
|
|
|
|
2015-04-29 16:46:51 +03:00
|
|
|
prev = NULL;
|
|
|
|
|
wl_array_for_each(p, &types) {
|
|
|
|
|
if (prev && strcmp(*p, prev) == 0)
|
|
|
|
|
continue;
|
|
|
|
|
printf("struct %s;\n", *p);
|
|
|
|
|
prev = *p;
|
|
|
|
|
}
|
2015-05-28 19:30:33 +03:00
|
|
|
wl_array_release(&types);
|
2015-04-29 16:46:51 +03:00
|
|
|
printf("\n");
|
|
|
|
|
|
2015-05-28 19:30:33 +03:00
|
|
|
wl_list_for_each(i, &protocol->interface_list, link) {
|
2020-04-21 12:47:56 +02:00
|
|
|
printf("#ifndef %s_INTERFACE\n", i->uppercase_name);
|
|
|
|
|
printf("#define %s_INTERFACE\n", i->uppercase_name);
|
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");
|
2010-08-09 21:25:50 -04:00
|
|
|
printf("extern const struct wl_interface "
|
2015-05-28 19:30:33 +03:00
|
|
|
"%s_interface;\n", i->name);
|
2020-04-21 12:47:56 +02:00
|
|
|
printf("#endif\n");
|
2010-08-09 21:25:50 -04:00
|
|
|
}
|
2015-04-29 16:46:51 +03:00
|
|
|
|
2010-08-09 21:25:50 -04:00
|
|
|
printf("\n");
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2022-09-17 10:53:56 +02:00
|
|
|
emit_enumerations(i, side == SERVER);
|
2011-01-21 21:57:55 -05:00
|
|
|
|
2014-08-08 18:22:47 -04:00
|
|
|
if (side == SERVER) {
|
2014-08-08 18:22:48 -04:00
|
|
|
emit_structs(&i->request_list, i, side);
|
2010-08-03 09:26:44 -04:00
|
|
|
emit_opcodes(&i->event_list, i);
|
2014-05-08 23:39:49 +02:00
|
|
|
emit_opcode_versions(&i->event_list, i);
|
2016-07-05 20:41:50 +02:00
|
|
|
emit_opcode_versions(&i->request_list, i);
|
2012-03-02 15:16:33 +02:00
|
|
|
emit_event_wrappers(&i->event_list, i);
|
2010-08-03 09:26:44 -04:00
|
|
|
} else {
|
2014-08-08 18:22:48 -04:00
|
|
|
emit_structs(&i->event_list, i, side);
|
2010-08-03 09:26:44 -04:00
|
|
|
emit_opcodes(&i->request_list, i);
|
2016-07-05 20:41:50 +02:00
|
|
|
emit_opcode_versions(&i->event_list, i);
|
2015-10-08 11:00:54 +08:00
|
|
|
emit_opcode_versions(&i->request_list, i);
|
2010-08-09 21:25:50 -04:00
|
|
|
emit_stubs(&i->request_list, i);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
2015-07-30 15:07:21 +02:00
|
|
|
|
|
|
|
|
free_interface(i);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("#ifdef __cplusplus\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"#endif\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"#endif\n");
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-03 12:18:07 +02:00
|
|
|
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) {
|
2022-09-17 10:53:56 +02:00
|
|
|
emit_enumerations(i, false);
|
2023-05-03 12:18:07 +02:00
|
|
|
|
|
|
|
|
free_interface(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("#ifdef __cplusplus\n"
|
|
|
|
|
"}\n"
|
|
|
|
|
"#endif\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"#endif\n");
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-12 13:22:25 -04:00
|
|
|
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:
|
2012-10-08 13:21:55 -04:00
|
|
|
if (a->interface_name)
|
2011-07-12 13:22:25 -04:00
|
|
|
printf("\t&%s_interface,\n",
|
|
|
|
|
a->interface_name);
|
|
|
|
|
else
|
|
|
|
|
printf("\tNULL,\n");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("\tNULL,\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static void
|
2019-05-11 09:53:01 -05:00
|
|
|
emit_messages(const char *name, struct wl_list *message_list,
|
2010-08-03 09:26:44 -04:00
|
|
|
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);
|
2013-06-27 20:09:19 -05:00
|
|
|
|
|
|
|
|
if (m->since > 1)
|
|
|
|
|
printf("%d", m->since);
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
wl_list_for_each(a, &m->arg_list, link) {
|
2012-07-02 20:03:30 +10:00
|
|
|
if (is_nullable_type(a) && a->nullable)
|
|
|
|
|
printf("?");
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
switch (a->type) {
|
|
|
|
|
default:
|
|
|
|
|
case INT:
|
|
|
|
|
printf("i");
|
|
|
|
|
break;
|
|
|
|
|
case NEW_ID:
|
2012-10-08 13:21:55 -04:00
|
|
|
if (a->interface_name == NULL)
|
|
|
|
|
printf("su");
|
2010-08-03 09:26:44 -04:00
|
|
|
printf("n");
|
|
|
|
|
break;
|
|
|
|
|
case UNSIGNED:
|
|
|
|
|
printf("u");
|
|
|
|
|
break;
|
2012-05-08 17:17:25 +01:00
|
|
|
case FIXED:
|
|
|
|
|
printf("f");
|
|
|
|
|
break;
|
2010-08-03 09:26:44 -04:00
|
|
|
case STRING:
|
|
|
|
|
printf("s");
|
|
|
|
|
break;
|
|
|
|
|
case OBJECT:
|
|
|
|
|
printf("o");
|
|
|
|
|
break;
|
|
|
|
|
case ARRAY:
|
|
|
|
|
printf("a");
|
|
|
|
|
break;
|
2010-08-26 21:49:44 -04:00
|
|
|
case FD:
|
|
|
|
|
printf("h");
|
|
|
|
|
break;
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
}
|
2019-05-11 09:53:01 -05:00
|
|
|
printf("\", %s_types + %d },\n", name, m->type_index);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("};\n\n");
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-16 16:22:30 +00:00
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
static void
|
2018-02-16 16:22:30 +00:00
|
|
|
emit_code(struct protocol *protocol, enum visibility vis)
|
2010-08-03 09:26:44 -04:00
|
|
|
{
|
2018-02-16 16:22:30 +00:00
|
|
|
const char *symbol_visibility;
|
2015-07-30 15:07:21 +02:00
|
|
|
struct interface *i, *next;
|
2014-04-03 15:57:54 -07:00
|
|
|
struct wl_array types;
|
|
|
|
|
char **p, *prev;
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2016-06-06 10:58:56 -07:00
|
|
|
printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
|
2016-05-05 17:27:57 +02:00
|
|
|
|
2011-07-25 18:14:20 -07:00
|
|
|
if (protocol->copyright)
|
2016-03-01 09:26:21 +10:00
|
|
|
format_text_to_comment(protocol->copyright, true);
|
2011-07-25 18:14:20 -07:00
|
|
|
|
2022-09-17 10:53:56 +02:00
|
|
|
printf("#include <stdbool.h>\n"
|
|
|
|
|
"#include <stdlib.h>\n"
|
2010-08-03 09:26:44 -04:00
|
|
|
"#include <stdint.h>\n"
|
2011-07-25 18:14:20 -07:00
|
|
|
"#include \"wayland-util.h\"\n\n");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2018-02-16 16:22:30 +00:00
|
|
|
/* When building a shared library symbols must be exported, otherwise
|
|
|
|
|
* we want to have the symbols hidden. */
|
|
|
|
|
if (vis == PRIVATE) {
|
|
|
|
|
symbol_visibility = "WL_PRIVATE";
|
2018-02-16 16:22:32 +00:00
|
|
|
printf("#ifndef __has_attribute\n"
|
|
|
|
|
"# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */\n"
|
|
|
|
|
"#endif\n\n");
|
|
|
|
|
|
2018-02-23 16:23:15 -06:00
|
|
|
printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n"
|
2018-02-16 16:22:30 +00:00
|
|
|
"#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n"
|
|
|
|
|
"#else\n"
|
|
|
|
|
"#define WL_PRIVATE\n"
|
|
|
|
|
"#endif\n\n");
|
|
|
|
|
} else {
|
|
|
|
|
symbol_visibility = "WL_EXPORT";
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-03 15:57:54 -07:00
|
|
|
wl_array_init(&types);
|
2011-07-12 13:22:25 -04:00
|
|
|
wl_list_for_each(i, &protocol->interface_list, link) {
|
2014-04-03 15:57:54 -07:00
|
|
|
emit_types_forward_declarations(protocol, &i->request_list, &types);
|
|
|
|
|
emit_types_forward_declarations(protocol, &i->event_list, &types);
|
|
|
|
|
}
|
2022-09-23 07:58:13 +10:00
|
|
|
|
|
|
|
|
if (types.size > 0)
|
|
|
|
|
qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
|
|
|
|
|
|
2014-04-03 15:57:54 -07:00
|
|
|
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;
|
2011-07-12 13:22:25 -04:00
|
|
|
}
|
2014-04-03 15:57:54 -07:00
|
|
|
wl_array_release(&types);
|
|
|
|
|
printf("\n");
|
2011-07-12 13:22:25 -04:00
|
|
|
|
2019-05-11 09:53:01 -05:00
|
|
|
printf("static const struct wl_interface *%s_types[] = {\n", protocol->name);
|
2011-07-12 13:22:25 -04:00
|
|
|
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");
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2019-05-11 09:53:01 -05:00
|
|
|
emit_messages(protocol->name, &i->request_list, i, "requests");
|
|
|
|
|
emit_messages(protocol->name, &i->event_list, i, "events");
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2018-02-16 16:22:30 +00:00
|
|
|
printf("%s const struct wl_interface "
|
2011-04-18 10:24:11 -04:00
|
|
|
"%s_interface = {\n"
|
2010-08-03 09:26:44 -04:00
|
|
|
"\t\"%s\", %d,\n",
|
2018-02-16 16:22:30 +00:00
|
|
|
symbol_visibility, i->name, i->name, i->version);
|
2010-08-03 09:26:44 -04:00
|
|
|
|
|
|
|
|
if (!wl_list_empty(&i->request_list))
|
2012-10-19 17:08:38 -04:00
|
|
|
printf("\t%d, %s_requests,\n",
|
2013-02-25 17:12:51 +02:00
|
|
|
wl_list_length(&i->request_list), i->name);
|
2010-08-03 09:26:44 -04:00
|
|
|
else
|
|
|
|
|
printf("\t0, NULL,\n");
|
|
|
|
|
|
|
|
|
|
if (!wl_list_empty(&i->event_list))
|
2012-10-19 17:08:38 -04:00
|
|
|
printf("\t%d, %s_events,\n",
|
2013-02-25 17:12:51 +02:00
|
|
|
wl_list_length(&i->event_list), i->name);
|
2010-08-03 09:26:44 -04:00
|
|
|
else
|
|
|
|
|
printf("\t0, NULL,\n");
|
|
|
|
|
|
|
|
|
|
printf("};\n\n");
|
2015-07-30 15:07:21 +02:00
|
|
|
|
|
|
|
|
/* we won't need it any further */
|
|
|
|
|
free_interface(i);
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
static void
|
|
|
|
|
free_protocol(struct protocol *protocol)
|
|
|
|
|
{
|
|
|
|
|
free(protocol->name);
|
|
|
|
|
free(protocol->uppercase_name);
|
|
|
|
|
free(protocol->copyright);
|
|
|
|
|
free_description(protocol->description);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
struct parse_context ctx;
|
|
|
|
|
struct protocol protocol;
|
2015-03-02 16:08:00 +02:00
|
|
|
FILE *input = stdin;
|
2016-01-25 17:28:06 +08:00
|
|
|
char *input_filename = NULL;
|
2010-08-03 09:26:44 -04:00
|
|
|
int len;
|
|
|
|
|
void *buf;
|
2016-05-05 17:27:57 +02:00
|
|
|
bool help = false;
|
|
|
|
|
bool core_headers = false;
|
|
|
|
|
bool version = false;
|
2017-10-11 17:31:33 +08:00
|
|
|
bool strict = false;
|
2015-04-29 16:46:51 +03:00
|
|
|
bool fail = false;
|
2015-04-30 15:28:35 +03:00
|
|
|
int opt;
|
2013-08-07 11:05:57 +10:00
|
|
|
enum {
|
|
|
|
|
CLIENT_HEADER,
|
|
|
|
|
SERVER_HEADER,
|
2023-05-03 12:18:07 +02:00
|
|
|
ENUM_HEADER,
|
2018-02-16 16:22:30 +00:00
|
|
|
PRIVATE_CODE,
|
|
|
|
|
PUBLIC_CODE,
|
2013-08-07 11:05:57 +10:00
|
|
|
CODE,
|
|
|
|
|
} mode;
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2015-04-29 16:46:51 +03:00
|
|
|
static const struct option options[] = {
|
2015-04-30 15:28:35 +03:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
2016-05-05 17:27:57 +02:00
|
|
|
{ "version", no_argument, NULL, 'v' },
|
2015-04-30 15:28:35 +03:00
|
|
|
{ "include-core-only", no_argument, NULL, 'c' },
|
2017-10-11 17:31:33 +08:00
|
|
|
{ "strict", no_argument, NULL, 's' },
|
2015-04-30 15:28:35 +03:00
|
|
|
{ 0, 0, NULL, 0 }
|
2015-04-29 16:46:51 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2017-10-11 17:31:33 +08:00
|
|
|
opt = getopt_long(argc, argv, "hvcs", options, NULL);
|
2015-04-29 16:46:51 +03:00
|
|
|
|
|
|
|
|
if (opt == -1)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
switch (opt) {
|
2015-04-30 15:28:35 +03:00
|
|
|
case 'h':
|
|
|
|
|
help = true;
|
|
|
|
|
break;
|
2016-05-05 17:27:57 +02:00
|
|
|
case 'v':
|
|
|
|
|
version = true;
|
|
|
|
|
break;
|
2015-04-30 15:28:35 +03:00
|
|
|
case 'c':
|
|
|
|
|
core_headers = true;
|
|
|
|
|
break;
|
2017-10-11 17:31:33 +08:00
|
|
|
case 's':
|
|
|
|
|
strict = true;
|
|
|
|
|
break;
|
2015-04-30 15:28:35 +03:00
|
|
|
default:
|
|
|
|
|
fail = true;
|
|
|
|
|
break;
|
2015-04-29 16:46:51 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
argv += optind;
|
|
|
|
|
argc -= optind;
|
|
|
|
|
|
|
|
|
|
if (help)
|
|
|
|
|
usage(EXIT_SUCCESS);
|
2016-05-05 17:27:57 +02:00
|
|
|
else if (version)
|
|
|
|
|
scanner_version(EXIT_SUCCESS);
|
2015-04-29 16:46:51 +03:00
|
|
|
else if ((argc != 1 && argc != 3) || fail)
|
2010-08-03 09:26:44 -04:00
|
|
|
usage(EXIT_FAILURE);
|
2015-04-29 16:46:51 +03:00
|
|
|
else if (strcmp(argv[0], "help") == 0)
|
2013-08-07 11:05:57 +10:00
|
|
|
usage(EXIT_SUCCESS);
|
2015-04-29 16:46:51 +03:00
|
|
|
else if (strcmp(argv[0], "client-header") == 0)
|
2013-08-07 11:05:57 +10:00
|
|
|
mode = CLIENT_HEADER;
|
2015-04-29 16:46:51 +03:00
|
|
|
else if (strcmp(argv[0], "server-header") == 0)
|
2013-08-07 11:05:57 +10:00
|
|
|
mode = SERVER_HEADER;
|
2023-05-03 12:18:07 +02:00
|
|
|
else if (strcmp(argv[0], "enum-header") == 0)
|
|
|
|
|
mode = ENUM_HEADER;
|
2018-02-16 16:22:30 +00:00
|
|
|
else if (strcmp(argv[0], "private-code") == 0)
|
|
|
|
|
mode = PRIVATE_CODE;
|
|
|
|
|
else if (strcmp(argv[0], "public-code") == 0)
|
|
|
|
|
mode = PUBLIC_CODE;
|
2015-04-29 16:46:51 +03:00
|
|
|
else if (strcmp(argv[0], "code") == 0)
|
2013-08-07 11:05:57 +10:00
|
|
|
mode = CODE;
|
2013-10-07 21:36:31 -07:00
|
|
|
else
|
|
|
|
|
usage(EXIT_FAILURE);
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2015-04-29 16:46:51 +03:00
|
|
|
if (argc == 3) {
|
2016-01-25 17:28:06 +08:00
|
|
|
input_filename = argv[1];
|
|
|
|
|
input = fopen(input_filename, "r");
|
2015-03-02 16:08:00 +02:00
|
|
|
if (input == NULL) {
|
|
|
|
|
fprintf(stderr, "Could not open input file: %s\n",
|
|
|
|
|
strerror(errno));
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
2015-04-29 16:46:51 +03:00
|
|
|
if (freopen(argv[2], "w", stdout) == NULL) {
|
2015-03-02 16:08:00 +02:00
|
|
|
fprintf(stderr, "Could not open output file: %s\n",
|
|
|
|
|
strerror(errno));
|
2015-10-01 18:13:29 -07:00
|
|
|
fclose(input);
|
2015-03-02 16:08:00 +02:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
/* initialize protocol structure */
|
|
|
|
|
memset(&protocol, 0, sizeof protocol);
|
2010-08-03 09:26:44 -04:00
|
|
|
wl_list_init(&protocol.interface_list);
|
2015-04-29 16:46:51 +03:00
|
|
|
protocol.core_headers = core_headers;
|
2015-07-30 15:07:22 +02:00
|
|
|
|
|
|
|
|
/* initialize context */
|
2012-10-20 11:38:57 -04:00
|
|
|
memset(&ctx, 0, sizeof ctx);
|
2010-08-03 09:26:44 -04:00
|
|
|
ctx.protocol = &protocol;
|
2016-01-25 17:28:06 +08:00
|
|
|
if (input == stdin)
|
|
|
|
|
ctx.loc.filename = "<stdin>";
|
|
|
|
|
else
|
|
|
|
|
ctx.loc.filename = input_filename;
|
2015-07-30 15:07:22 +02:00
|
|
|
|
2016-01-25 17:28:06 +08:00
|
|
|
if (!is_dtd_valid(input, ctx.loc.filename)) {
|
2015-11-10 09:53:08 +10:00
|
|
|
fprintf(stderr,
|
|
|
|
|
"*******************************************************\n"
|
|
|
|
|
"* *\n"
|
|
|
|
|
"* WARNING: XML failed validation against built-in DTD *\n"
|
|
|
|
|
"* *\n"
|
|
|
|
|
"*******************************************************\n");
|
2017-10-11 17:31:33 +08:00
|
|
|
if (strict) {
|
|
|
|
|
fclose(input);
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
2015-11-10 09:53:08 +10:00
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:22 +02:00
|
|
|
/* 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) {
|
2010-08-03 09:26:44 -04:00
|
|
|
fprintf(stderr, "failed to create parser\n");
|
2015-10-01 18:13:29 -07:00
|
|
|
fclose(input);
|
2010-08-03 09:26:44 -04:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-25 18:14:20 -07:00
|
|
|
XML_SetElementHandler(ctx.parser, start_element, end_element);
|
|
|
|
|
XML_SetCharacterDataHandler(ctx.parser, character_data);
|
|
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
do {
|
2011-04-13 16:50:02 -04:00
|
|
|
buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
|
2015-03-02 16:08:00 +02:00
|
|
|
len = fread(buf, 1, XML_BUFFER_SIZE, input);
|
2010-08-03 09:26:44 -04:00
|
|
|
if (len < 0) {
|
2019-04-26 22:40:18 +02:00
|
|
|
fprintf(stderr, "fread: %s\n", strerror(errno));
|
2015-10-01 18:13:29 -07:00
|
|
|
fclose(input);
|
2010-08-03 09:26:44 -04:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
2014-09-22 22:11:18 +02:00
|
|
|
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)));
|
2015-10-01 18:13:29 -07:00
|
|
|
fclose(input);
|
2014-09-22 22:11:18 +02:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
2010-08-03 09:26:44 -04:00
|
|
|
} while (len > 0);
|
|
|
|
|
|
2011-04-13 16:50:02 -04:00
|
|
|
XML_ParserFree(ctx.parser);
|
2010-08-03 09:26:44 -04:00
|
|
|
|
2013-10-07 21:36:31 -07:00
|
|
|
switch (mode) {
|
2013-08-07 11:05:57 +10:00
|
|
|
case CLIENT_HEADER:
|
2014-08-08 18:22:47 -04:00
|
|
|
emit_header(&protocol, CLIENT);
|
2013-08-07 11:05:57 +10:00
|
|
|
break;
|
|
|
|
|
case SERVER_HEADER:
|
2014-08-08 18:22:47 -04:00
|
|
|
emit_header(&protocol, SERVER);
|
2013-08-07 11:05:57 +10:00
|
|
|
break;
|
2023-05-03 12:18:07 +02:00
|
|
|
case ENUM_HEADER:
|
|
|
|
|
emit_enum_header(&protocol);
|
|
|
|
|
break;
|
2018-02-16 16:22:30 +00:00
|
|
|
case PRIVATE_CODE:
|
|
|
|
|
emit_code(&protocol, PRIVATE);
|
|
|
|
|
break;
|
2013-08-07 11:05:57 +10:00
|
|
|
case CODE:
|
2018-02-16 16:22:30 +00:00
|
|
|
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);
|
2013-08-07 11:05:57 +10:00
|
|
|
break;
|
2010-08-03 09:26:44 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-30 15:07:21 +02:00
|
|
|
free_protocol(&protocol);
|
2015-10-01 18:13:29 -07:00
|
|
|
fclose(input);
|
2015-07-30 15:07:21 +02:00
|
|
|
|
2010-08-03 09:26:44 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|