mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			1139 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1139 lines
		
	
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright © 2008-2011 Kristian Høgsberg
 | 
						|
 * Copyright © 2011 Intel Corporation
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, distribute, and sell this software and its
 | 
						|
 * documentation for any purpose is hereby granted without fee, provided that
 | 
						|
 * the above copyright notice appear in all copies and that both that copyright
 | 
						|
 * notice and this permission notice appear in supporting documentation, and
 | 
						|
 * that the name of the copyright holders not be used in advertising or
 | 
						|
 * publicity pertaining to distribution of the software without specific,
 | 
						|
 * written prior permission.  The copyright holders make no representations
 | 
						|
 * about the suitability of this software for any purpose.  It is provided "as
 | 
						|
 * is" without express or implied warranty.
 | 
						|
 *
 | 
						|
 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | 
						|
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | 
						|
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | 
						|
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
						|
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | 
						|
 * OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <string.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <expat.h>
 | 
						|
 | 
						|
#include "wayland-util.h"
 | 
						|
 | 
						|
static int
 | 
						|
usage(int ret)
 | 
						|
{
 | 
						|
	fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");
 | 
						|
	exit(ret);
 | 
						|
}
 | 
						|
 | 
						|
#define XML_BUFFER_SIZE 4096
 | 
						|
 | 
						|
struct description {
 | 
						|
	char *summary;
 | 
						|
	char *text;
 | 
						|
};
 | 
						|
 | 
						|
struct protocol {
 | 
						|
	char *name;
 | 
						|
	char *uppercase_name;
 | 
						|
	struct wl_list interface_list;
 | 
						|
	int type_index;
 | 
						|
	int null_run_length;
 | 
						|
	char *copyright;
 | 
						|
	struct description *description;
 | 
						|
};
 | 
						|
 | 
						|
struct interface {
 | 
						|
	char *name;
 | 
						|
	char *uppercase_name;
 | 
						|
	int version;
 | 
						|
	int since;
 | 
						|
	struct wl_list request_list;
 | 
						|
	struct wl_list event_list;
 | 
						|
	struct wl_list enumeration_list;
 | 
						|
	struct wl_list link;
 | 
						|
	struct description *description;
 | 
						|
};
 | 
						|
 | 
						|
struct message {
 | 
						|
	char *name;
 | 
						|
	char *uppercase_name;
 | 
						|
	struct wl_list arg_list;
 | 
						|
	struct wl_list link;
 | 
						|
	int arg_count;
 | 
						|
	int type_index;
 | 
						|
	int all_null;
 | 
						|
	int destructor;
 | 
						|
	int since;
 | 
						|
	struct description *description;
 | 
						|
};
 | 
						|
 | 
						|
enum arg_type {
 | 
						|
	NEW_ID,
 | 
						|
	INT,
 | 
						|
	UNSIGNED,
 | 
						|
	FIXED,
 | 
						|
	STRING,
 | 
						|
	OBJECT,
 | 
						|
	ARRAY,
 | 
						|
	FD
 | 
						|
};
 | 
						|
 | 
						|
struct arg {
 | 
						|
	char *name;
 | 
						|
	enum arg_type type;
 | 
						|
	int nullable;
 | 
						|
	char *interface_name;
 | 
						|
	struct wl_list link;
 | 
						|
	char *summary;
 | 
						|
};
 | 
						|
 | 
						|
struct enumeration {
 | 
						|
	char *name;
 | 
						|
	char *uppercase_name;
 | 
						|
	struct wl_list entry_list;
 | 
						|
	struct wl_list link;
 | 
						|
	struct description *description;
 | 
						|
};
 | 
						|
 | 
						|
struct entry {
 | 
						|
	char *name;
 | 
						|
	char *uppercase_name;
 | 
						|
	char *value;
 | 
						|
	char *summary;
 | 
						|
	struct wl_list link;
 | 
						|
};
 | 
						|
 | 
						|
struct parse_context {
 | 
						|
	const char *filename;
 | 
						|
	XML_Parser parser;
 | 
						|
	struct protocol *protocol;
 | 
						|
	struct interface *interface;
 | 
						|
	struct message *message;
 | 
						|
	struct enumeration *enumeration;
 | 
						|
	struct description *description;
 | 
						|
	char character_data[8192];
 | 
						|
	unsigned int character_data_length;
 | 
						|
};
 | 
						|
 | 
						|
static char *
 | 
						|
uppercase_dup(const char *src)
 | 
						|
{
 | 
						|
	char *u;
 | 
						|
	int i;
 | 
						|
 | 
						|
	u = strdup(src);
 | 
						|
	for (i = 0; u[i]; i++)
 | 
						|
		u[i] = toupper(u[i]);
 | 
						|
	u[i] = '\0';
 | 
						|
 | 
						|
	return u;
 | 
						|
}
 | 
						|
 | 
						|
static const char *indent(int n)
 | 
						|
{
 | 
						|
	const char *whitespace[] = {
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t  ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t   ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t    ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t     ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t      ",
 | 
						|
		"\t\t\t\t\t\t\t\t\t\t\t\t       "
 | 
						|
	};
 | 
						|
 | 
						|
	return whitespace[n % 8] + 12 - n / 8;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
desc_dump(const char *fmt, ...)
 | 
						|
{
 | 
						|
	va_list ap;
 | 
						|
	char buf[128], *desc, hang;
 | 
						|
	int col, i, j, k, startcol;
 | 
						|
 | 
						|
	va_start(ap, fmt);
 | 
						|
	vsnprintf(buf, sizeof buf, fmt, ap);
 | 
						|
	desc = va_arg(ap, char *);
 | 
						|
	va_end(ap);
 | 
						|
 | 
						|
	for (i = 0, col = 0; buf[i] != '*'; i++) {
 | 
						|
		if (buf[i] == '\t')
 | 
						|
			col = (col + 8) & ~7;
 | 
						|
		else
 | 
						|
			col++;
 | 
						|
	}
 | 
						|
 | 
						|
	printf("%s", buf);
 | 
						|
 | 
						|
	if (!desc) {
 | 
						|
		printf("(none)\n");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	startcol = col;
 | 
						|
	col += strlen(&buf[i]);
 | 
						|
	if (col - startcol > 2)
 | 
						|
		hang = '\t';
 | 
						|
	else
 | 
						|
		hang = ' ';
 | 
						|
 | 
						|
	for (i = 0; desc[i]; ) {
 | 
						|
		k = i;
 | 
						|
		while (desc[i] && isspace(desc[i]))
 | 
						|
			i++;
 | 
						|
		if (!desc[i])
 | 
						|
			break;
 | 
						|
 | 
						|
		j = i;
 | 
						|
		while (desc[i] && !isspace(desc[i]))
 | 
						|
			i++;
 | 
						|
 | 
						|
		if (col + i - j > 72) {
 | 
						|
			printf("\n%s*%c", indent(startcol), hang);
 | 
						|
			col = startcol;
 | 
						|
		}
 | 
						|
 | 
						|
		if (col > startcol && k > 0)
 | 
						|
			col += printf(" ");
 | 
						|
		col += printf("%.*s", i - j, &desc[j]);
 | 
						|
	}
 | 
						|
	putchar('\n');
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fail(struct parse_context *ctx, const char *msg)
 | 
						|
{
 | 
						|
	fprintf(stderr, "%s:%ld: %s\n",
 | 
						|
		ctx->filename, XML_GetCurrentLineNumber(ctx->parser), msg);
 | 
						|
	exit(EXIT_FAILURE);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
is_nullable_type(struct arg *arg)
 | 
						|
{
 | 
						|
	switch (arg->type) {
 | 
						|
	/* Strings, objects, and arrays are possibly nullable */
 | 
						|
	case STRING:
 | 
						|
	case OBJECT:
 | 
						|
	case ARRAY:
 | 
						|
		return 1;
 | 
						|
	default:
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
start_element(void *data, const char *element_name, const char **atts)
 | 
						|
{
 | 
						|
	struct parse_context *ctx = data;
 | 
						|
	struct interface *interface;
 | 
						|
	struct message *message;
 | 
						|
	struct arg *arg;
 | 
						|
	struct enumeration *enumeration;
 | 
						|
	struct entry *entry;
 | 
						|
	struct description *description;
 | 
						|
	const char *name, *type, *interface_name, *value, *summary, *since;
 | 
						|
	const char *allow_null;
 | 
						|
	char *end;
 | 
						|
	int i, version;
 | 
						|
 | 
						|
	name = NULL;
 | 
						|
	type = NULL;
 | 
						|
	version = 0;
 | 
						|
	interface_name = NULL;
 | 
						|
	value = NULL;
 | 
						|
	summary = NULL;
 | 
						|
	description = NULL;
 | 
						|
	since = NULL;
 | 
						|
	allow_null = NULL;
 | 
						|
	for (i = 0; atts[i]; i += 2) {
 | 
						|
		if (strcmp(atts[i], "name") == 0)
 | 
						|
			name = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "version") == 0)
 | 
						|
			version = atoi(atts[i + 1]);
 | 
						|
		if (strcmp(atts[i], "type") == 0)
 | 
						|
			type = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "value") == 0)
 | 
						|
			value = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "interface") == 0)
 | 
						|
			interface_name = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "summary") == 0)
 | 
						|
			summary = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "since") == 0)
 | 
						|
			since = atts[i + 1];
 | 
						|
		if (strcmp(atts[i], "allow-null") == 0)
 | 
						|
			allow_null = atts[i + 1];
 | 
						|
	}
 | 
						|
 | 
						|
	ctx->character_data_length = 0;
 | 
						|
	if (strcmp(element_name, "protocol") == 0) {
 | 
						|
		if (name == NULL)
 | 
						|
			fail(ctx, "no protocol name given");
 | 
						|
 | 
						|
		ctx->protocol->name = strdup(name);
 | 
						|
		ctx->protocol->uppercase_name = uppercase_dup(name);
 | 
						|
		ctx->protocol->description = NULL;
 | 
						|
	} else if (strcmp(element_name, "copyright") == 0) {
 | 
						|
		
 | 
						|
	} else if (strcmp(element_name, "interface") == 0) {
 | 
						|
		if (name == NULL)
 | 
						|
			fail(ctx, "no interface name given");
 | 
						|
 | 
						|
		if (version == 0)
 | 
						|
			fail(ctx, "no interface version given");
 | 
						|
 | 
						|
		interface = malloc(sizeof *interface);
 | 
						|
		interface->name = strdup(name);
 | 
						|
		interface->uppercase_name = uppercase_dup(name);
 | 
						|
		interface->version = version;
 | 
						|
		interface->description = NULL;
 | 
						|
		interface->since = 1;
 | 
						|
		wl_list_init(&interface->request_list);
 | 
						|
		wl_list_init(&interface->event_list);
 | 
						|
		wl_list_init(&interface->enumeration_list);
 | 
						|
		wl_list_insert(ctx->protocol->interface_list.prev,
 | 
						|
			       &interface->link);
 | 
						|
		ctx->interface = interface;
 | 
						|
	} else if (strcmp(element_name, "request") == 0 ||
 | 
						|
		   strcmp(element_name, "event") == 0) {
 | 
						|
		if (name == NULL)
 | 
						|
			fail(ctx, "no request name given");
 | 
						|
 | 
						|
		message = malloc(sizeof *message);
 | 
						|
		message->name = strdup(name);
 | 
						|
		message->uppercase_name = uppercase_dup(name);
 | 
						|
		wl_list_init(&message->arg_list);
 | 
						|
		message->arg_count = 0;
 | 
						|
		message->description = NULL;
 | 
						|
 | 
						|
		if (strcmp(element_name, "request") == 0)
 | 
						|
			wl_list_insert(ctx->interface->request_list.prev,
 | 
						|
				       &message->link);
 | 
						|
		else
 | 
						|
			wl_list_insert(ctx->interface->event_list.prev,
 | 
						|
				       &message->link);
 | 
						|
 | 
						|
		if (type != NULL && strcmp(type, "destructor") == 0)
 | 
						|
			message->destructor = 1;
 | 
						|
		else
 | 
						|
			message->destructor = 0;
 | 
						|
 | 
						|
		if (since != NULL) {
 | 
						|
			version = strtol(since, &end, 0);
 | 
						|
			if (errno == EINVAL || end == since || *end != '\0')
 | 
						|
				fail(ctx, "invalid integer\n");
 | 
						|
			if (version <= ctx->interface->since)
 | 
						|
				fail(ctx, "since version not increasing\n");
 | 
						|
			ctx->interface->since = version;
 | 
						|
		}
 | 
						|
 | 
						|
		message->since = ctx->interface->since;
 | 
						|
 | 
						|
		if (strcmp(name, "destroy") == 0 && !message->destructor)
 | 
						|
			fail(ctx, "destroy request should be destructor type");
 | 
						|
 | 
						|
		ctx->message = message;
 | 
						|
	} else if (strcmp(element_name, "arg") == 0) {
 | 
						|
		arg = malloc(sizeof *arg);
 | 
						|
		arg->name = strdup(name);
 | 
						|
 | 
						|
		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 {
 | 
						|
			fail(ctx, "unknown type");
 | 
						|
		}
 | 
						|
 | 
						|
		switch (arg->type) {
 | 
						|
		case NEW_ID:
 | 
						|
		case OBJECT:
 | 
						|
			if (interface_name == NULL)
 | 
						|
				fail(ctx, "no interface name given");
 | 
						|
			arg->interface_name = strdup(interface_name);
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			if (interface_name != NULL)
 | 
						|
				fail(ctx, "interface not allowed");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		if (allow_null == NULL || strcmp(allow_null, "false") == 0)
 | 
						|
			arg->nullable = 0;
 | 
						|
		else if (strcmp(allow_null, "true") == 0)
 | 
						|
			arg->nullable = 1;
 | 
						|
		else
 | 
						|
			fail(ctx, "invalid value for allow-null attribute");
 | 
						|
 | 
						|
		if (allow_null != NULL && !is_nullable_type(arg))
 | 
						|
			fail(ctx, "allow-null is only valid for objects, strings, and arrays");
 | 
						|
 | 
						|
		arg->summary = NULL;
 | 
						|
		if (summary)
 | 
						|
			arg->summary = strdup(summary);
 | 
						|
 | 
						|
		wl_list_insert(ctx->message->arg_list.prev, &arg->link);
 | 
						|
		ctx->message->arg_count++;
 | 
						|
	} else if (strcmp(element_name, "enum") == 0) {
 | 
						|
		if (name == NULL)
 | 
						|
			fail(ctx, "no enum name given");
 | 
						|
 | 
						|
		enumeration = malloc(sizeof *enumeration);
 | 
						|
		enumeration->name = strdup(name);
 | 
						|
		enumeration->uppercase_name = uppercase_dup(name);
 | 
						|
		enumeration->description = NULL;
 | 
						|
		wl_list_init(&enumeration->entry_list);
 | 
						|
 | 
						|
		wl_list_insert(ctx->interface->enumeration_list.prev,
 | 
						|
			       &enumeration->link);
 | 
						|
 | 
						|
		ctx->enumeration = enumeration;
 | 
						|
	} else if (strcmp(element_name, "entry") == 0) {
 | 
						|
		if (name == NULL)
 | 
						|
			fail(ctx, "no entry name given");
 | 
						|
 | 
						|
		entry = malloc(sizeof *entry);
 | 
						|
		entry->name = strdup(name);
 | 
						|
		entry->uppercase_name = uppercase_dup(name);
 | 
						|
		entry->value = strdup(value);
 | 
						|
		if (summary)
 | 
						|
			entry->summary = strdup(summary);
 | 
						|
		else
 | 
						|
			entry->summary = NULL;
 | 
						|
		wl_list_insert(ctx->enumeration->entry_list.prev,
 | 
						|
			       &entry->link);
 | 
						|
	} else if (strcmp(element_name, "description") == 0) {
 | 
						|
		if (summary == NULL)
 | 
						|
			fail(ctx, "description without summary");
 | 
						|
 | 
						|
		description = malloc(sizeof *description);
 | 
						|
		if (summary)
 | 
						|
			description->summary = strdup(summary);
 | 
						|
		else
 | 
						|
			description->summary = NULL;
 | 
						|
 | 
						|
		if (ctx->message)
 | 
						|
			ctx->message->description = description;
 | 
						|
		else if (ctx->enumeration)
 | 
						|
			ctx->enumeration->description = description;
 | 
						|
		else if (ctx->interface)
 | 
						|
			ctx->interface->description = description;
 | 
						|
		else
 | 
						|
			ctx->protocol->description = description;
 | 
						|
		ctx->description = description;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
end_element(void *data, const XML_Char *name)
 | 
						|
{
 | 
						|
	struct parse_context *ctx = data;
 | 
						|
 | 
						|
	if (strcmp(name, "copyright") == 0) {
 | 
						|
		ctx->protocol->copyright =
 | 
						|
			strndup(ctx->character_data,
 | 
						|
				ctx->character_data_length);
 | 
						|
	} else if (strcmp(name, "description") == 0) {
 | 
						|
		char *text = strndup(ctx->character_data,
 | 
						|
				     ctx->character_data_length);
 | 
						|
		if (text)
 | 
						|
			ctx->description->text = text;
 | 
						|
		ctx->description = NULL;
 | 
						|
	} else if (strcmp(name, "request") == 0 ||
 | 
						|
		   strcmp(name, "event") == 0) {
 | 
						|
		ctx->message = NULL;
 | 
						|
	} else if (strcmp(name, "enum") == 0) {
 | 
						|
		ctx->enumeration = NULL;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_opcodes(struct wl_list *message_list, struct interface *interface)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	int opcode;
 | 
						|
 | 
						|
	if (wl_list_empty(message_list))
 | 
						|
		return;
 | 
						|
 | 
						|
	opcode = 0;
 | 
						|
	wl_list_for_each(m, message_list, link)
 | 
						|
		printf("#define %s_%s\t%d\n",
 | 
						|
		       interface->uppercase_name, m->uppercase_name, opcode++);
 | 
						|
 | 
						|
	printf("\n");
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_type(struct arg *a)
 | 
						|
{
 | 
						|
	switch (a->type) {
 | 
						|
	default:
 | 
						|
	case INT:
 | 
						|
	case FD:
 | 
						|
		printf("int32_t ");
 | 
						|
		break;
 | 
						|
	case NEW_ID:
 | 
						|
	case UNSIGNED:
 | 
						|
		printf("uint32_t ");
 | 
						|
		break;
 | 
						|
	case FIXED:
 | 
						|
		printf("wl_fixed_t ");
 | 
						|
		break;
 | 
						|
	case STRING:
 | 
						|
		printf("const char *");
 | 
						|
		break;
 | 
						|
	case OBJECT:
 | 
						|
		printf("struct %s *", a->interface_name);
 | 
						|
		break;
 | 
						|
	case ARRAY:
 | 
						|
		printf("struct wl_array *");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_stubs(struct wl_list *message_list, struct interface *interface)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a, *ret;
 | 
						|
	int has_destructor, has_destroy;
 | 
						|
 | 
						|
	/* We provide a hand written functions for the display object */
 | 
						|
	if (strcmp(interface->name, "wl_display") == 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	printf("static inline void\n"
 | 
						|
	       "%s_set_user_data(struct %s *%s, void *user_data)\n"
 | 
						|
	       "{\n"
 | 
						|
	       "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
 | 
						|
	       "}\n\n",
 | 
						|
	       interface->name, interface->name, interface->name,
 | 
						|
	       interface->name);
 | 
						|
 | 
						|
	printf("static inline void *\n"
 | 
						|
	       "%s_get_user_data(struct %s *%s)\n"
 | 
						|
	       "{\n"
 | 
						|
	       "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
 | 
						|
	       "}\n\n",
 | 
						|
	       interface->name, interface->name, interface->name,
 | 
						|
	       interface->name);
 | 
						|
 | 
						|
	has_destructor = 0;
 | 
						|
	has_destroy = 0;
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		if (m->destructor)
 | 
						|
			has_destructor = 1;
 | 
						|
		if (strcmp(m->name, "destroy)") == 0)
 | 
						|
			has_destroy = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!has_destructor && has_destroy) {
 | 
						|
		fprintf(stderr,
 | 
						|
			"interface %s has method named destroy but"
 | 
						|
			"no destructor", interface->name);
 | 
						|
		exit(EXIT_FAILURE);
 | 
						|
	}
 | 
						|
 | 
						|
	if (!has_destructor)
 | 
						|
		printf("static inline void\n"
 | 
						|
		       "%s_destroy(struct %s *%s)\n"
 | 
						|
		       "{\n"
 | 
						|
		       "\twl_proxy_destroy("
 | 
						|
		       "(struct wl_proxy *) %s);\n"
 | 
						|
		       "}\n\n",
 | 
						|
		       interface->name, interface->name, interface->name,
 | 
						|
		       interface->name);
 | 
						|
 | 
						|
	if (wl_list_empty(message_list))
 | 
						|
		return;
 | 
						|
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		ret = NULL;
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			if (a->type == NEW_ID)
 | 
						|
				ret = a;
 | 
						|
		}
 | 
						|
 | 
						|
		if (ret)
 | 
						|
			printf("static inline struct %s *\n",
 | 
						|
			       ret->interface_name);
 | 
						|
		else
 | 
						|
			printf("static inline void\n");
 | 
						|
 | 
						|
		printf("%s_%s(struct %s *%s",
 | 
						|
		       interface->name, m->name,
 | 
						|
		       interface->name, interface->name);
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			if (a->type == NEW_ID)
 | 
						|
				continue;
 | 
						|
			printf(", ");
 | 
						|
			emit_type(a);
 | 
						|
			printf("%s", a->name);
 | 
						|
		}
 | 
						|
 | 
						|
		printf(")\n"
 | 
						|
		       "{\n");
 | 
						|
		if (ret)
 | 
						|
			printf("\tstruct wl_proxy *%s;\n\n"
 | 
						|
			       "\t%s = wl_proxy_create("
 | 
						|
			       "(struct wl_proxy *) %s,\n"
 | 
						|
			       "\t\t\t     &%s_interface);\n"
 | 
						|
			       "\tif (!%s)\n"
 | 
						|
			       "\t\treturn NULL;\n\n",
 | 
						|
			       ret->name,
 | 
						|
			       ret->name,
 | 
						|
			       interface->name, ret->interface_name,
 | 
						|
			       ret->name);
 | 
						|
 | 
						|
		printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
 | 
						|
		       "\t\t\t %s_%s",
 | 
						|
		       interface->name,
 | 
						|
		       interface->uppercase_name,
 | 
						|
		       m->uppercase_name);
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			printf(", ");
 | 
						|
				printf("%s", a->name);
 | 
						|
		}
 | 
						|
		printf(");\n");
 | 
						|
 | 
						|
		if (m->destructor)
 | 
						|
			printf("\n\twl_proxy_destroy("
 | 
						|
			       "(struct wl_proxy *) %s);\n",
 | 
						|
			       interface->name);
 | 
						|
 | 
						|
		if (ret)
 | 
						|
			printf("\n\treturn (struct %s *) %s;\n",
 | 
						|
			       ret->interface_name, ret->name);
 | 
						|
 | 
						|
		printf("}\n\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a;
 | 
						|
 | 
						|
	/* We provide hand written functions for the display object */
 | 
						|
	if (strcmp(interface->name, "wl_display") == 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		printf("static inline void\n"
 | 
						|
		       "%s_send_%s(struct wl_resource *resource_",
 | 
						|
		       interface->name, m->name);
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			printf(", ");
 | 
						|
			switch (a->type) {
 | 
						|
			case NEW_ID:
 | 
						|
			case OBJECT:
 | 
						|
				printf("struct wl_resource *");
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				emit_type(a);
 | 
						|
			}
 | 
						|
			printf("%s", a->name);
 | 
						|
		}
 | 
						|
 | 
						|
		printf(")\n"
 | 
						|
		       "{\n"
 | 
						|
		       "\twl_resource_post_event(resource_, %s_%s",
 | 
						|
		       interface->uppercase_name, m->uppercase_name);
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link)
 | 
						|
			printf(", %s", a->name);
 | 
						|
 | 
						|
		printf(");\n");
 | 
						|
		printf("}\n\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_enumerations(struct interface *interface)
 | 
						|
{
 | 
						|
	struct enumeration *e;
 | 
						|
	struct entry *entry;
 | 
						|
 | 
						|
	wl_list_for_each(e, &interface->enumeration_list, link) {
 | 
						|
		struct description *desc = e->description;
 | 
						|
 | 
						|
		printf("#ifndef %s_%s_ENUM\n",
 | 
						|
		       interface->uppercase_name, e->uppercase_name);
 | 
						|
		printf("#define %s_%s_ENUM\n",
 | 
						|
		       interface->uppercase_name, e->uppercase_name);
 | 
						|
 | 
						|
		if (desc) {
 | 
						|
			printf("/**\n");
 | 
						|
			desc_dump(" * %s_%s - ",
 | 
						|
				  interface->name, e->name, desc->summary);
 | 
						|
			wl_list_for_each(entry, &e->entry_list, link) {
 | 
						|
				desc_dump(" * @%s_%s_%s: ",
 | 
						|
					  interface->uppercase_name,
 | 
						|
					  e->uppercase_name,
 | 
						|
					  entry->uppercase_name,
 | 
						|
					  entry->summary);
 | 
						|
			}
 | 
						|
			if (desc->text) {
 | 
						|
				printf(" *\n");
 | 
						|
				desc_dump(" * ", desc->text);
 | 
						|
			}
 | 
						|
			printf(" */\n");
 | 
						|
		}
 | 
						|
		printf("enum %s_%s {\n", interface->name, e->name);
 | 
						|
		wl_list_for_each(entry, &e->entry_list, link)
 | 
						|
			printf("\t%s_%s_%s = %s,\n",
 | 
						|
			       interface->uppercase_name,
 | 
						|
			       e->uppercase_name,
 | 
						|
			       entry->uppercase_name, entry->value);
 | 
						|
		printf("};\n");
 | 
						|
		printf("#endif /* %s_%s_ENUM */\n\n",
 | 
						|
		       interface->uppercase_name, e->uppercase_name);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_structs(struct wl_list *message_list, struct interface *interface)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a;
 | 
						|
	int is_interface, n;
 | 
						|
 | 
						|
	if (wl_list_empty(message_list))
 | 
						|
		return;
 | 
						|
 | 
						|
	is_interface = message_list == &interface->request_list;
 | 
						|
	if (interface->description) {
 | 
						|
		struct description *desc = interface->description;
 | 
						|
		printf("/**\n");
 | 
						|
		desc_dump(" * %s - ", interface->name, desc->summary);
 | 
						|
		wl_list_for_each(m, message_list, link) {
 | 
						|
			struct description *mdesc = m->description;
 | 
						|
			desc_dump(" * @%s: ",
 | 
						|
				  m->name, mdesc ? mdesc->summary : "(none)");
 | 
						|
		}
 | 
						|
		printf(" *\n");
 | 
						|
		desc_dump(" * ", desc->text);
 | 
						|
		printf(" */\n");
 | 
						|
	}
 | 
						|
	printf("struct %s_%s {\n", interface->name,
 | 
						|
	       is_interface ? "interface" : "listener");
 | 
						|
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		struct description *mdesc = m->description;
 | 
						|
 | 
						|
		printf("\t/**\n");
 | 
						|
		desc_dump("\t * %s - ",
 | 
						|
			  m->name, mdesc ? mdesc->summary : "(none)");
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			desc_dump("\t * @%s: ",
 | 
						|
				  a->name, a->summary ? a->summary : "(none)");
 | 
						|
		}
 | 
						|
		if (mdesc) {
 | 
						|
			printf("\t *\n");
 | 
						|
			desc_dump("\t * ", mdesc->text, 8, 0);
 | 
						|
		}
 | 
						|
		if (m->since > 1) {
 | 
						|
			printf("\t * @since: %d\n", m->since);
 | 
						|
		}
 | 
						|
		printf("\t */\n");
 | 
						|
		printf("\tvoid (*%s)(", m->name);
 | 
						|
 | 
						|
		n = strlen(m->name) + 17;
 | 
						|
		if (is_interface) {
 | 
						|
			printf("struct wl_client *client,\n"
 | 
						|
			       "%sstruct wl_resource *resource",
 | 
						|
			       indent(n));
 | 
						|
		} else {
 | 
						|
			printf("void *data,\n"),
 | 
						|
			printf("%sstruct %s *%s",
 | 
						|
			       indent(n), interface->name, interface->name);
 | 
						|
		}
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			printf(",\n%s", indent(n));
 | 
						|
 | 
						|
			if (is_interface && a->type == OBJECT)
 | 
						|
				printf("struct wl_resource *");
 | 
						|
			else if (!is_interface && a->type == NEW_ID)
 | 
						|
				printf("struct %s *", a->interface_name);
 | 
						|
			else
 | 
						|
				emit_type(a);
 | 
						|
 | 
						|
			printf("%s", a->name);
 | 
						|
		}
 | 
						|
 | 
						|
		printf(");\n");
 | 
						|
	}
 | 
						|
 | 
						|
	printf("};\n\n");
 | 
						|
 | 
						|
	if (!is_interface) {
 | 
						|
	    printf("static inline int\n"
 | 
						|
		   "%s_add_listener(struct %s *%s,\n"
 | 
						|
		   "%sconst struct %s_listener *listener, void *data)\n"
 | 
						|
		   "{\n"
 | 
						|
		   "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
 | 
						|
		   "%s(void (**)(void)) listener, data);\n"
 | 
						|
		   "}\n\n",
 | 
						|
		   interface->name, interface->name, interface->name,
 | 
						|
		   indent(14 + strlen(interface->name)),
 | 
						|
		   interface->name,
 | 
						|
		   interface->name,
 | 
						|
		   indent(37));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
format_copyright(const char *copyright)
 | 
						|
{
 | 
						|
	int bol = 1, start = 0, i;
 | 
						|
 | 
						|
	for (i = 0; copyright[i]; i++) {
 | 
						|
		if (bol && (copyright[i] == ' ' || copyright[i] == '\t')) {
 | 
						|
			continue;
 | 
						|
		} else if (bol) {
 | 
						|
			bol = 0;
 | 
						|
			start = i;
 | 
						|
		}
 | 
						|
 | 
						|
		if (copyright[i] == '\n' || copyright[i] == '\0') {
 | 
						|
			printf("%s %.*s\n",
 | 
						|
			       i == 0 ? "/*" : " *",
 | 
						|
			       i - start, copyright + start);
 | 
						|
			bol = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	printf(" */\n\n");
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_header(struct protocol *protocol, int server)
 | 
						|
{
 | 
						|
	struct interface *i;
 | 
						|
	const char *s = server ? "SERVER" : "CLIENT";
 | 
						|
 | 
						|
	if (protocol->copyright)
 | 
						|
		format_copyright(protocol->copyright);
 | 
						|
 | 
						|
	printf("#ifndef %s_%s_PROTOCOL_H\n"
 | 
						|
	       "#define %s_%s_PROTOCOL_H\n"
 | 
						|
	       "\n"
 | 
						|
	       "#ifdef  __cplusplus\n"
 | 
						|
	       "extern \"C\" {\n"
 | 
						|
	       "#endif\n"
 | 
						|
	       "\n"
 | 
						|
	       "#include <stdint.h>\n"
 | 
						|
	       "#include <stddef.h>\n"
 | 
						|
	       "#include \"wayland-util.h\"\n\n"
 | 
						|
	       "struct wl_client;\n"
 | 
						|
	       "struct wl_resource;\n\n",
 | 
						|
	       protocol->uppercase_name, s,
 | 
						|
	       protocol->uppercase_name, s);
 | 
						|
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link)
 | 
						|
		printf("struct %s;\n", i->name);
 | 
						|
	printf("\n");
 | 
						|
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link) {
 | 
						|
		printf("extern const struct wl_interface "
 | 
						|
		       "%s_interface;\n",
 | 
						|
		       i->name);
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link) {
 | 
						|
 | 
						|
		emit_enumerations(i);
 | 
						|
 | 
						|
		if (server) {
 | 
						|
			emit_structs(&i->request_list, i);
 | 
						|
			emit_opcodes(&i->event_list, i);
 | 
						|
			emit_event_wrappers(&i->event_list, i);
 | 
						|
		} else {
 | 
						|
			emit_structs(&i->event_list, i);
 | 
						|
			emit_opcodes(&i->request_list, i);
 | 
						|
			emit_stubs(&i->request_list, i);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	printf("#ifdef  __cplusplus\n"
 | 
						|
	       "}\n"
 | 
						|
	       "#endif\n"
 | 
						|
	       "\n"
 | 
						|
	       "#endif\n");
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_types_forward_declarations(struct protocol *protocol,
 | 
						|
				struct wl_list *message_list)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a;
 | 
						|
	int length;
 | 
						|
 | 
						|
	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:
 | 
						|
				m->all_null = 0;
 | 
						|
				printf("extern const struct wl_interface %s_interface;\n",
 | 
						|
				       a->interface_name);
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (m->all_null && length > protocol->null_run_length)
 | 
						|
			protocol->null_run_length = length;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_null_run(struct protocol *protocol)
 | 
						|
{
 | 
						|
	int i;
 | 
						|
 | 
						|
	for (i = 0; i < protocol->null_run_length; i++)
 | 
						|
		printf("\tNULL,\n");
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_types(struct protocol *protocol, struct wl_list *message_list)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a;
 | 
						|
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		if (m->all_null) {
 | 
						|
			m->type_index = 0;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		m->type_index =
 | 
						|
			protocol->null_run_length + protocol->type_index;
 | 
						|
		protocol->type_index += m->arg_count;
 | 
						|
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			switch (a->type) {
 | 
						|
			case NEW_ID:
 | 
						|
			case OBJECT:
 | 
						|
				if (strcmp(a->interface_name,
 | 
						|
					   "wl_object") != 0)
 | 
						|
					printf("\t&%s_interface,\n",
 | 
						|
					       a->interface_name);
 | 
						|
				else
 | 
						|
					printf("\tNULL,\n");
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				printf("\tNULL,\n");
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_messages(struct wl_list *message_list,
 | 
						|
	      struct interface *interface, const char *suffix)
 | 
						|
{
 | 
						|
	struct message *m;
 | 
						|
	struct arg *a;
 | 
						|
 | 
						|
	if (wl_list_empty(message_list))
 | 
						|
		return;
 | 
						|
 | 
						|
	printf("static const struct wl_message "
 | 
						|
	       "%s_%s[] = {\n",
 | 
						|
	       interface->name, suffix);
 | 
						|
 | 
						|
	wl_list_for_each(m, message_list, link) {
 | 
						|
		printf("\t{ \"%s\", \"", m->name);
 | 
						|
		wl_list_for_each(a, &m->arg_list, link) {
 | 
						|
			if (is_nullable_type(a) && a->nullable)
 | 
						|
				printf("?");
 | 
						|
 | 
						|
			switch (a->type) {
 | 
						|
			default:
 | 
						|
			case INT:
 | 
						|
				printf("i");
 | 
						|
				break;
 | 
						|
			case NEW_ID:
 | 
						|
				printf("n");
 | 
						|
				break;
 | 
						|
			case UNSIGNED:
 | 
						|
				printf("u");
 | 
						|
				break;
 | 
						|
			case FIXED:
 | 
						|
				printf("f");
 | 
						|
				break;
 | 
						|
			case STRING:
 | 
						|
				printf("s");
 | 
						|
				break;
 | 
						|
			case OBJECT:
 | 
						|
				printf("o");
 | 
						|
				break;
 | 
						|
			case ARRAY:
 | 
						|
				printf("a");
 | 
						|
				break;
 | 
						|
			case FD:
 | 
						|
				printf("h");
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printf("\", types + %d },\n", m->type_index);
 | 
						|
	}
 | 
						|
 | 
						|
	printf("};\n\n");
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit_code(struct protocol *protocol)
 | 
						|
{
 | 
						|
	struct interface *i;
 | 
						|
 | 
						|
	if (protocol->copyright)
 | 
						|
		format_copyright(protocol->copyright);
 | 
						|
 | 
						|
	printf("#include <stdlib.h>\n"
 | 
						|
	       "#include <stdint.h>\n"
 | 
						|
	       "#include \"wayland-util.h\"\n\n");
 | 
						|
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link) {
 | 
						|
		emit_types_forward_declarations(protocol, &i->request_list);
 | 
						|
		emit_types_forward_declarations(protocol, &i->event_list);
 | 
						|
	}
 | 
						|
	printf("\n");
 | 
						|
 | 
						|
	printf("static const struct wl_interface *types[] = {\n");
 | 
						|
	emit_null_run(protocol);
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link) {
 | 
						|
		emit_types(protocol, &i->request_list);
 | 
						|
		emit_types(protocol, &i->event_list);
 | 
						|
	}
 | 
						|
	printf("};\n\n");
 | 
						|
 | 
						|
	wl_list_for_each(i, &protocol->interface_list, link) {
 | 
						|
 | 
						|
		emit_messages(&i->request_list, i, "requests");
 | 
						|
		emit_messages(&i->event_list, i, "events");
 | 
						|
 | 
						|
		printf("WL_EXPORT const struct wl_interface "
 | 
						|
		       "%s_interface = {\n"
 | 
						|
		       "\t\"%s\", %d,\n",
 | 
						|
		       i->name, i->name, i->version);
 | 
						|
 | 
						|
		if (!wl_list_empty(&i->request_list))
 | 
						|
			printf("\tARRAY_LENGTH(%s_requests), %s_requests,\n",
 | 
						|
			       i->name, i->name);
 | 
						|
		else
 | 
						|
			printf("\t0, NULL,\n");
 | 
						|
 | 
						|
		if (!wl_list_empty(&i->event_list))
 | 
						|
			printf("\tARRAY_LENGTH(%s_events), %s_events,\n",
 | 
						|
			       i->name, i->name);
 | 
						|
		else
 | 
						|
			printf("\t0, NULL,\n");
 | 
						|
 | 
						|
		printf("};\n\n");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char *argv[])
 | 
						|
{
 | 
						|
	struct parse_context ctx;
 | 
						|
	struct protocol protocol;
 | 
						|
	int len;
 | 
						|
	void *buf;
 | 
						|
 | 
						|
	if (argc != 2)
 | 
						|
		usage(EXIT_FAILURE);
 | 
						|
 | 
						|
	wl_list_init(&protocol.interface_list);
 | 
						|
	protocol.type_index = 0;
 | 
						|
	protocol.null_run_length = 0;
 | 
						|
	protocol.copyright = NULL;
 | 
						|
	ctx.protocol = &protocol;
 | 
						|
 | 
						|
	ctx.filename = "<stdin>";
 | 
						|
	ctx.parser = XML_ParserCreate(NULL);
 | 
						|
	XML_SetUserData(ctx.parser, &ctx);
 | 
						|
	if (ctx.parser == NULL) {
 | 
						|
		fprintf(stderr, "failed to create parser\n");
 | 
						|
		exit(EXIT_FAILURE);
 | 
						|
	}
 | 
						|
 | 
						|
	XML_SetElementHandler(ctx.parser, start_element, end_element);
 | 
						|
	XML_SetCharacterDataHandler(ctx.parser, character_data);
 | 
						|
 | 
						|
	do {
 | 
						|
		buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
 | 
						|
		len = fread(buf, 1, XML_BUFFER_SIZE, stdin);
 | 
						|
		if (len < 0) {
 | 
						|
			fprintf(stderr, "fread: %m\n");
 | 
						|
			exit(EXIT_FAILURE);
 | 
						|
		}
 | 
						|
		XML_ParseBuffer(ctx.parser, len, len == 0);
 | 
						|
 | 
						|
	} while (len > 0);
 | 
						|
 | 
						|
	XML_ParserFree(ctx.parser);
 | 
						|
 | 
						|
	if (strcmp(argv[1], "client-header") == 0) {
 | 
						|
		emit_header(&protocol, 0);
 | 
						|
	} else if (strcmp(argv[1], "server-header") == 0) {
 | 
						|
		emit_header(&protocol, 1);
 | 
						|
	} else if (strcmp(argv[1], "code") == 0) {
 | 
						|
		emit_code(&protocol);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |