1.1 --- a/Makefile Fri Dec 09 19:33:15 2022 +0100
1.2 +++ b/Makefile Sat Dec 10 01:28:22 2022 +0100
1.3 @@ -1,6 +1,6 @@
1.4 # Makefile for building the idl tool.
1.5 #
1.6 -# Copyright (C) 2019, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
1.7 +# Copyright (C) 2019, 2020, 2021, 2022 Paul Boddie <paul@boddie.org.uk>
1.8 #
1.9 # This program is free software; you can redistribute it and/or
1.10 # modify it under the terms of the GNU General Public License as
1.11 @@ -17,11 +17,18 @@
1.12 # Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.13 # Boston, MA 02110-1301, USA
1.14
1.15 -# Original sources and final program.
1.16 +# Original sources, headers and final program.
1.17
1.18 SOURCES = \
1.19 - main.c client.c common.c config.c declaration.c dispatch.c includes.c \
1.20 - interface.c message.c program.c server.c structure.c summary.c \
1.21 + main.c client.c common.c config.c declaration.c dispatch.c imports.c \
1.22 + includes.c interface.c message.c program.c server.c \
1.23 + structure.c summary.c
1.24 +
1.25 +HEADERS = \
1.26 + client.h common.h config.h declaration.h dispatch.h imports.h \
1.27 + includes.h interface.h message.h parser.h program.h server.h \
1.28 + structure.h summary.h \
1.29 + templates.h types.h
1.30
1.31 PROGRAM = idl
1.32
1.33 @@ -71,5 +78,5 @@
1.34
1.35 main.c: $(VERSION)
1.36
1.37 -.c.o:
1.38 +%.o: %.c $(HEADERS)
1.39 $(CC) $(CFLAGS) -o $@ -c $<
2.1 --- a/client.c Fri Dec 09 19:33:15 2022 +0100
2.2 +++ b/client.c Sat Dec 10 01:28:22 2022 +0100
2.3 @@ -165,16 +165,21 @@
2.4 struct signature *sig;
2.5 char *opname;
2.6
2.7 - fprintf(fp, client_interface_prologue_c, iface->name, iface->name);
2.8 -
2.9 - for (sig = iface->signatures; sig != NULL; sig = sig->tail)
2.10 + if (iface->signatures == NULL)
2.11 + fprintf(fp, client_interface_prologue_empty_c, iface->name, iface->name);
2.12 + else
2.13 {
2.14 - opname = get_operation_name(iface, sig);
2.15 + fprintf(fp, client_interface_prologue_c, iface->name, iface->name);
2.16
2.17 - fprintf(fp, client_interface_member_c, sig->operation, opname);
2.18 + for (sig = iface->signatures; sig != NULL; sig = sig->tail)
2.19 + {
2.20 + opname = get_operation_name(iface, sig);
2.21
2.22 - free(opname);
2.23 + fprintf(fp, client_interface_member_c, sig->operation, opname);
2.24 +
2.25 + free(opname);
2.26 + }
2.27 +
2.28 + fputs(client_interface_epilogue_c, fp);
2.29 }
2.30 -
2.31 - fputs(client_interface_epilogue_c, fp);
2.32 }
3.1 --- a/common.c Fri Dec 09 19:33:15 2022 +0100
3.2 +++ b/common.c Sat Dec 10 01:28:22 2022 +0100
3.3 @@ -34,6 +34,13 @@
3.4 fprintf(stderr, "Could not open source file for writing in directory %s (name %s).\n", dir, name);
3.5 }
3.6
3.7 +/* Test for a basename. */
3.8 +
3.9 +int is_basename(char *path)
3.10 +{
3.11 + return basename(path) == path;
3.12 +}
3.13 +
3.14 /* Obtain a new basename string. */
3.15
3.16 char *make_basename(const char *path)
3.17 @@ -77,6 +84,13 @@
3.18 return fp;
3.19 }
3.20
3.21 +/* Return whether an interface is a compound interface. */
3.22 +
3.23 +int is_compound_interface(struct interface *iface)
3.24 +{
3.25 + return iface->bases != NULL;
3.26 +}
3.27 +
3.28 /* Find an attribute value. */
3.29
3.30 char *get_attribute_value(struct attribute *attr, const char *name)
3.31 @@ -352,12 +366,26 @@
3.32 /* Return the maximum number of input items accepted by any one of the given
3.33 signatures. */
3.34
3.35 -int get_max_input_items(struct signature *sig)
3.36 +int get_max_input_items(struct interface *iface)
3.37 {
3.38 int input_words, input_items, output_words, output_items;
3.39 int max_input_items = 0;
3.40 + struct interface_ref *base;
3.41 + struct signature *sig;
3.42
3.43 - for (; sig != NULL; sig = sig->tail)
3.44 + /* Test any base interfaces. */
3.45 +
3.46 + for (base = iface->bases; base != NULL; base = base->tail)
3.47 + {
3.48 + input_items = get_max_input_items(base->iface);
3.49 +
3.50 + if (input_items > max_input_items)
3.51 + max_input_items = input_items;
3.52 + }
3.53 +
3.54 + /* Test the signatures. */
3.55 +
3.56 + for (sig = iface->signatures; sig != NULL; sig = sig->tail)
3.57 {
3.58 count_parameters(sig->parameters, &input_words, &input_items, &output_words, &output_items);
3.59
4.1 --- a/common.h Fri Dec 09 19:33:15 2022 +0100
4.2 +++ b/common.h Sat Dec 10 01:28:22 2022 +0100
4.3 @@ -28,8 +28,9 @@
4.4
4.5 void open_error(const char *dir, const char *name);
4.6
4.7 -/* Filename manipulation. */
4.8 +/* Filename testing and manipulation. */
4.9
4.10 +int is_basename(char *path);
4.11 char *make_basename(const char *path);
4.12 char *make_dirname(const char *path);
4.13
4.14 @@ -37,6 +38,10 @@
4.15
4.16 FILE *get_output_file(const char *filename_template, const char *dir, const char *name);
4.17
4.18 +/* Interface testing. */
4.19 +
4.20 +int is_compound_interface(struct interface *iface);
4.21 +
4.22 /* Interface attribute access. */
4.23
4.24 char *get_attribute_value(struct attribute *attr, const char *name);
4.25 @@ -80,7 +85,7 @@
4.26 void count_parameters(struct parameter *param, int *input_words,
4.27 int *input_items, int *output_words, int *output_items);
4.28
4.29 -int get_max_input_items(struct signature *sig);
4.30 +int get_max_input_items(struct interface *iface);
4.31
4.32 /* Message access details. */
4.33
5.1 --- a/config.c Fri Dec 09 19:33:15 2022 +0100
5.2 +++ b/config.c Sat Dec 10 01:28:22 2022 +0100
5.3 @@ -1,7 +1,7 @@
5.4 /*
5.5 * Configuration settings.
5.6 *
5.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
5.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
5.9 *
5.10 * This program is free software; you can redistribute it and/or
5.11 * modify it under the terms of the GNU General Public License as
5.12 @@ -23,10 +23,9 @@
5.13 #include "config.h"
5.14
5.15 struct config conf = {
5.16 - .output_prefix = NULL,
5.17 .output_dir = NULL,
5.18 - .compound = NULL,
5.19 - .compound_name = NULL,
5.20 + .generate_all = 0,
5.21 + .show_filenames = 0,
5.22 .client = 0,
5.23 .server = 0,
5.24 .headers = 0,
6.1 --- a/config.h Fri Dec 09 19:33:15 2022 +0100
6.2 +++ b/config.h Sat Dec 10 01:28:22 2022 +0100
6.3 @@ -1,7 +1,7 @@
6.4 /*
6.5 * Configuration settings.
6.6 *
6.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
6.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
6.9 *
6.10 * This program is free software; you can redistribute it and/or
6.11 * modify it under the terms of the GNU General Public License as
6.12 @@ -25,15 +25,11 @@
6.13
6.14 struct config
6.15 {
6.16 - /* Current filename and output options. */
6.17 -
6.18 - char *output_prefix;
6.19 - char *output_dir;
6.20 + /* Current output options. */
6.21
6.22 - /* Compound interface and dispatcher output. */
6.23 -
6.24 - char *compound;
6.25 - char *compound_name;
6.26 + char *output_dir;
6.27 + int generate_all;
6.28 + int show_filenames;
6.29
6.30 /* Configurations for generated code. */
6.31
7.1 --- a/dispatch.c Fri Dec 09 19:33:15 2022 +0100
7.2 +++ b/dispatch.c Sat Dec 10 01:28:22 2022 +0100
7.3 @@ -1,7 +1,7 @@
7.4 /*
7.5 * Generation of server dispatch and handle functions.
7.6 *
7.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
7.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
7.9 *
7.10 * This program is free software; you can redistribute it and/or
7.11 * modify it under the terms of the GNU General Public License as
7.12 @@ -26,6 +26,93 @@
7.13
7.14
7.15
7.16 +/* Generate each dispatch possibility within an interface. */
7.17 +
7.18 +static void write_dispatcher_cases(FILE *fp, struct interface *iface,
7.19 + int compound)
7.20 +{
7.21 + struct signature *sig;
7.22 + char *opcode, *opname, *protocol, *prefix, *ref, *s;
7.23 +
7.24 + for (sig = iface->signatures; sig != NULL; sig = sig->tail)
7.25 + {
7.26 + opname = get_operation_name(iface, sig);
7.27 + opcode = get_opcode_identifier(NULL, opname);
7.28 + prefix = get_operation_wrapper_prefix(sig->attributes);
7.29 +
7.30 + /* Convert to any base interface. */
7.31 +
7.32 + ref = get_object_conversion(iface, compound);
7.33 +
7.34 + /* Generate a reply if appropriate. */
7.35 +
7.36 + if (have_attribute(sig->attributes, "completion"))
7.37 + s = dispatch_function_wrapper_case;
7.38 + else
7.39 + s = dispatch_function_reply_wrapper_case;
7.40 +
7.41 + /* Generate the case and invocation. */
7.42 +
7.43 + fprintf(fp, s, opcode, prefix, opname, ref);
7.44 +
7.45 + /* Free allocated strings. */
7.46 +
7.47 + free(opcode);
7.48 + free(opname);
7.49 + free(ref);
7.50 + }
7.51 +}
7.52 +
7.53 +/* Dispatch to each interface-level function where the same protocol applies to
7.54 + an entire interface. Dispatch to each operation where an interface does not
7.55 + specify a protocol. */
7.56 +
7.57 +static void write_dispatcher_interface_cases(FILE *fp, struct interface *iface,
7.58 + int by_protocol)
7.59 +{
7.60 + struct interface_ref *base;
7.61 + char *protocol, *ref;
7.62 +
7.63 + for (base = iface->bases; base != NULL; base = base->tail)
7.64 + {
7.65 + protocol = get_protocol(base->iface->attributes);
7.66 +
7.67 + /* Write cases for each interface, using the protocol to select between the
7.68 + cases. */
7.69 +
7.70 + if (by_protocol && (protocol != NULL))
7.71 + {
7.72 + /* Convert to any base interface. */
7.73 +
7.74 + ref = get_object_conversion(base->iface, 1);
7.75 + fprintf(fp, dispatch_function_interface_case, protocol, base->name, ref);
7.76 + free(ref);
7.77 + }
7.78 +
7.79 + /* Write cases for each operation provided by the interface so that they can
7.80 + be selected. Note that this requires distinct opcodes to be used, so in
7.81 + practice requiring explicit opcodes to be indicated. */
7.82 +
7.83 + else if (!by_protocol && (protocol == NULL))
7.84 + write_dispatcher_cases(fp, base->iface, 1);
7.85 + }
7.86 +}
7.87 +
7.88 +/* Return whether any base interface specifies a protocol. */
7.89 +
7.90 +static int have_interfaces_using_protocols(struct interface *iface)
7.91 +{
7.92 + struct interface_ref *base;
7.93 +
7.94 + for (base = iface->bases; base != NULL; base = base->tail)
7.95 + if (get_protocol(base->iface->attributes) != NULL)
7.96 + return 1;
7.97 +
7.98 + return 0;
7.99 +}
7.100 +
7.101 +
7.102 +
7.103 /* Generate dispatch function signatures. */
7.104
7.105 void write_dispatcher_signature(const char *name, enum signature_role role,
7.106 @@ -46,61 +133,47 @@
7.107
7.108 /* Generate a dispatch function for the different operations. */
7.109
7.110 -void write_dispatcher(struct signature *sig, FILE *fp, struct interface *iface)
7.111 +void write_dispatcher(FILE *fp, struct interface *iface)
7.112 {
7.113 + char *protocol = get_protocol(iface->attributes);
7.114 +
7.115 write_dispatcher_signature(iface->name, DEFINITION_ROLE, fp);
7.116
7.117 /* Declare an error variable to support testing for already-sent messages. */
7.118
7.119 fputs(" long err;\n\n", fp);
7.120
7.121 - /* Interpret an operation indicator in the word data if a protocol applies to
7.122 - the entire interface. */
7.123 + /* Without a protocol applying to the entire interface, dispatch using the
7.124 + protocol from the message label. */
7.125
7.126 - if (get_protocol(iface->attributes))
7.127 - fputs(" switch (ipc_message_get_word(msg, 0))\n {\n", fp);
7.128 - else
7.129 + if (protocol == NULL)
7.130 + {
7.131 fputs(" switch (l4_msgtag_label(msg->tag))\n {\n", fp);
7.132
7.133 - write_dispatcher_cases(sig, fp, iface, 0);
7.134 - fputs(server_function_dispatcher_body_epilogue, fp);
7.135 + /* Dispatch using the protocol to base interfaces employing protocols. */
7.136
7.137 - fputs("}\n", fp);
7.138 -}
7.139 -
7.140 -/* Generate each dispatch possibility within an interface. */
7.141 + if (have_interfaces_using_protocols(iface))
7.142 + write_dispatcher_interface_cases(fp, iface, 1);
7.143 + }
7.144
7.145 -void write_dispatcher_cases(struct signature *sig, FILE *fp,
7.146 - struct interface *iface, int compound)
7.147 -{
7.148 - char *opcode, *opname, *protocol, *prefix, *ref, *s;
7.149 + /* If a protocol applies to the entire interface, dispatch using an operation
7.150 + indicator in the word data. */
7.151
7.152 - if (sig == NULL)
7.153 - return;
7.154 + else
7.155 + fputs(" switch (ipc_message_get_word(msg, 0))\n {\n", fp);
7.156
7.157 - opname = get_operation_name(iface, sig);
7.158 - opcode = get_opcode_identifier(NULL, opname);
7.159 - prefix = get_operation_wrapper_prefix(sig->attributes);
7.160 - ref = get_object_conversion(iface, compound);
7.161 + /* Dispatch to operations provided by compound interfaces. */
7.162
7.163 - /* Generate a reply if appropriate. */
7.164 + write_dispatcher_interface_cases(fp, iface, 0);
7.165
7.166 - if (have_attribute(sig->attributes, "completion"))
7.167 - s = dispatch_function_wrapper_case;
7.168 - else
7.169 - s = dispatch_function_reply_wrapper_case;
7.170 + /* Dispatch to each operation defined at this level. */
7.171
7.172 - /* Generate the case and invocation. */
7.173 -
7.174 - fprintf(fp, s, opcode, prefix, opname, ref);
7.175 + write_dispatcher_cases(fp, iface, is_compound_interface(iface));
7.176
7.177 - /* Generate the other cases. */
7.178 -
7.179 - write_dispatcher_cases(sig->tail, fp, iface, compound);
7.180 + /* Terminate the dispatcher. */
7.181
7.182 - /* Free allocated strings. */
7.183 + fputs(dispatch_function_default_case, fp);
7.184 + fputs(dispatch_function_dispatcher_epilogue, fp);
7.185
7.186 - free(opcode);
7.187 - free(opname);
7.188 - free(ref);
7.189 + fputs(END_FUNCTION, fp);
7.190 }
8.1 --- a/dispatch.h Fri Dec 09 19:33:15 2022 +0100
8.2 +++ b/dispatch.h Sat Dec 10 01:28:22 2022 +0100
8.3 @@ -1,7 +1,7 @@
8.4 /*
8.5 * Generation of server dispatch and handle functions.
8.6 *
8.7 - * Copyright (C) 2019, 2020 Paul Boddie <paul@boddie.org.uk>
8.8 + * Copyright (C) 2019, 2020, 2022 Paul Boddie <paul@boddie.org.uk>
8.9 *
8.10 * This program is free software; you can redistribute it and/or
8.11 * modify it under the terms of the GNU General Public License as
8.12 @@ -24,8 +24,6 @@
8.13 #include <stdio.h>
8.14 #include "types.h"
8.15
8.16 -void write_dispatcher(struct signature *sig, FILE *fp, struct interface *iface);
8.17 -void write_dispatcher_cases(struct signature *sig, FILE *fp,
8.18 - struct interface *iface, int compound);
8.19 +void write_dispatcher(FILE *fp, struct interface *iface);
8.20 void write_dispatcher_signature(const char *name, enum signature_role role, FILE *fp);
8.21 void write_handler_signature(const char *name, enum signature_role role, FILE *fp);
9.1 --- a/docs/idl.1 Fri Dec 09 19:33:15 2022 +0100
9.2 +++ b/docs/idl.1 Sat Dec 10 01:28:22 2022 +0100
9.3 @@ -1,4 +1,4 @@
9.4 -.TH IDL "1" "2022-09-15" "idl 0.1" "User Commands"
9.5 +.TH IDL "1" "2022-12-09" "idl 2022-12-09" "User Commands"
9.6
9.7 .SH NAME
9.8 idl \- L4Re IDL parser and code generator
9.9 @@ -60,6 +60,10 @@
9.10 .BR \-c ", " \-\-client
9.11 Generate client files only, appropriate when needing to access interfaces.
9.12 .TP
9.13 +.BR \-f ", " \-\-files
9.14 +Only show processed filenames on standard output, with no output files being
9.15 +produced.
9.16 +.TP
9.17 .BR \-h ", " \-\-headers
9.18 Generate header files for the selected configuration or for both client and
9.19 server configurations.
9.20 @@ -69,6 +73,11 @@
9.21 implementing the operations of the described interfaces. Common definitions
9.22 employed by client and server code are also defined in these files.
9.23 .TP
9.24 +.BR \-R ", " \-\-recursive
9.25 +Generate output files corresponding to all interface files processed. Where an
9.26 +interface file imports other files, output will also be generated for these
9.27 +files.
9.28 +.TP
9.29 .BR \-r ", " \-\-routines
9.30 Generate routines, these defining functions exposing the operations of the
9.31 described interfaces.
9.32 @@ -86,20 +95,16 @@
9.33 configuration has been selected.
9.34 .PP
9.35 If the
9.36 -.BR \-c ", " \-\-client ", " \-s ", " \-\-server ", " \-C ", " \-\-comp ", "
9.37 -.BR \-N " or " \-\-comp-name
9.38 +.BR \-c ", " \-\-client ", " \-s " or " \-\-server
9.39 options are not given, output is produced for client and server configurations.
9.40 +The
9.41 +.BR \-f " and " \-\-files
9.42 +options will suppress all output regardless of any other options indicated.
9.43 .PP
9.44 Some options may be followed by a value, either immediately after the long form
9.45 of the option and an equals sign (\fB=\fR) or in the argument that follows them:
9.46 .PP
9.47 .TP
9.48 -\fB\-C\fR, \fB\-\-comp\fR=\fIPREFIX\fR
9.49 -Generate compound (or composite, or component) interface files, indicating the
9.50 -name of the compound interface which will also be the prefix of the generated
9.51 -files; such files are employed by servers to pass control to individual
9.52 -interfaces.
9.53 -.TP
9.54 \fB\-d\fR, \fB\-\-dir\fR=\fIDIRECTORY\fR
9.55 Indicate the output directory for generated files.
9.56 .TP
9.57 @@ -107,12 +112,6 @@
9.58 Select the programming language to be used for output; currently only
9.59 .BR C " and " C++
9.60 are accepted as values for this option.
9.61 -.TP
9.62 -\fB\-N\fR, \fB\-\-comp-name\fR=\fINAME\fR
9.63 -Select a different name for a compound (or composite, component) interface than
9.64 -that indicated by the
9.65 -.BR \-C " or " \-\-comp
9.66 -options.
9.67
9.68 .SH EXAMPLES
9.69 Compile the interfaces in
9.70 @@ -143,20 +142,13 @@
9.71 .IP
9.72 idl --language=C++ -r -s hello.idl
9.73 .PP
9.74 -Generate compound interface header files and dispatch routines for a server:
9.75 +Generate files for multiple interface files:
9.76 .IP
9.77 -idl -C greetings hello.idl goodbye.idl
9.78 +idl hello.idl goodbye.idl
9.79 .PP
9.80 -The above would create a dispatch mechanism for a component called
9.81 -.I greetings
9.82 -supporting both of the indicated interfaces. This complements server code
9.83 -generated for the individual interfaces:
9.84 +Generate all output files for an interface file that imports other files:
9.85 .IP
9.86 -idl -s hello.idl goodbye.idl
9.87 -.PP
9.88 -Generate just the interface headers for the individual interfaces:
9.89 -.IP
9.90 -idl -i hello.idl goodbye.idl
9.91 +idl -R hello_and_goodbye.idl
9.92
9.93 .SH INTERFACE DESCRIPTIONS
9.94 An interface will resemble the following in its simplest practical form:
9.95 @@ -250,11 +242,14 @@
9.96 \fBopcode_type(\fIopcode_type_value\fB)\fR
9.97 An explicit type for the opcode applying to the given operation.
9.98
9.99 -.SH COMPLETION OPERATIONS
9.100 -Operations can be annotated with the \fBcompletion\fR attribute, indicating
9.101 -that a client will initiate the operation with any parameters conveying input
9.102 -values, with the completion of the operation being performed explicitly by
9.103 -server code.
9.104 +.SH SENDING RESULTS DURING OPERATIONS
9.105 +.PP
9.106 +Normally, results are communicated from operations by setting the appropriate
9.107 +output parameter values. However, it is possible to send results in advance by
9.108 +calling a completion function. Completion functions are generally made available
9.109 +for all operations, regardless of whether the \fBcompletion\fR attribute is
9.110 +specified. Such default completion functions merely provide a way of
9.111 +communicating results.
9.112 .PP
9.113 Consider the following interface:
9.114 .in +4n
9.115 @@ -274,10 +269,56 @@
9.116 Calc_pow(ref_Calc _self, double left, double right, double *result);
9.117 .fi
9.118 .PP
9.119 -Here, the result is written to the address provided by the corresponding
9.120 -parameter. When the client invokes the operation, it remains unaware of the
9.121 -nature of the work done by the server: the operation acts like a typical
9.122 -function call.
9.123 +Here, the result is normally written to the address provided by the
9.124 +corresponding parameter. However, the operation is also supported by another
9.125 +function as follows:
9.126 +.in +4n
9.127 +.nf
9.128 +.sp
9.129 +complete_Calc_pow(double result);
9.130 +.fi
9.131 +.PP
9.132 +Instead of using the \fBresult\fR output parameter in \fBCalc_pow\fR to return a
9.133 +result value, this parameter can be ignored and the \fBcomplete_Calc_pow\fR
9.134 +function used to send a response to the client, the result value being passed as
9.135 +a parameter to this function. To prevent the server framework from attempting to
9.136 +use the \fBresult\fR output parameter to send another response, a special value
9.137 +is returned from the operation:
9.138 +.in +4n
9.139 +.nf
9.140 +.sp
9.141 +/* Complete the operation and send results. */
9.142 +
9.143 +complete_Calc_pow(result);
9.144 +
9.145 +/* More work done. */
9.146 +
9.147 +return IPC_MESSAGE_SENT;
9.148 +.fi
9.149 +.PP
9.150 +Unlike explicitly designated completion operations, results sent in this way
9.151 +will be directed to the initiating client as a reply to its original request.
9.152 +
9.153 +.SH COMPLETION OPERATIONS
9.154 +Operations can be annotated with the \fBcompletion\fR attribute, indicating
9.155 +that a client will initiate the operation with any parameters conveying input
9.156 +values, with the completion of the operation being performed explicitly by
9.157 +server code. Unlike regular operations, such annotated operations allow the
9.158 +completion to involve another endpoint, as opposed to the client that initiated
9.159 +the operation.
9.160 +.PP
9.161 +Consider the following interface:
9.162 +.in +4n
9.163 +.nf
9.164 +.sp
9.165 +interface Calc
9.166 +{
9.167 + void pow(in double left, in double right, out double result);
9.168 +};
9.169 +.fi
9.170 +.PP
9.171 +This interface would be presented to the client for it to use when initiating
9.172 +operations.
9.173 .PP
9.174 Now consider the following interface annotated with the \fBcompletion\fR
9.175 attribute:
9.176 @@ -297,8 +338,9 @@
9.177 CalcPrivate_pow(ref_CalcPrivate _self, double base, double exponent);
9.178 .fi
9.179 .PP
9.180 -This function is not intended to communicate the result. Instead, within the
9.181 -server code, a function of the following form will need to be invoked:
9.182 +This function is not intended to communicate the result, and it even lacks the
9.183 +appropriate output parameter. Instead, within the server code, a function of the
9.184 +following form will need to be invoked:
9.185 .in +4n
9.186 .nf
9.187 .sp
9.188 @@ -306,23 +348,52 @@
9.189 .fi
9.190 .PP
9.191 Here, the result is communicated via the corresponding parameter, with the
9.192 -indicated endpoint (\fB_endp\fR) receiving the reply.
9.193 +indicated endpoint (\fB_endp\fR) receiving the reply. Where the endpoint is
9.194 +the client that initiated an operation, the effect will be indistinguishable
9.195 +from a normal invocation. However, where another endpoint is chosen to receive
9.196 +the reply, the initiating client will effectively give up control to the client
9.197 +employing the chosen endpoint, with that designated client assuming control
9.198 +until such time that it calls the operation. Thus, this form of completion
9.199 +operation permits a form of simple scheduling.
9.200
9.201 .SH COMPONENTS AND COMPOUND INTERFACES
9.202 -Components may attempt to support more than one interface. Although inheritance
9.203 -might be employed to achieve this, the combination or composition of interfaces
9.204 -is somewhat different: crucially, all involved interfaces remain distinct and do
9.205 -not override each other (conflicts between protocols and operation codes
9.206 -notwithstanding).
9.207 +Components may wish to support more than one interface, and this can be done
9.208 +using composition, as illustrated below involving two interfaces:
9.209 +.in +4n
9.210 +.nf
9.211 +.sp
9.212 +interface \fIinterface_name\fR composes \fIbase_interface1\fR, \fIbase_interface2\fR;
9.213 +.fi
9.214 +.PP
9.215 +Although inheritance might be employed to provide compound interfaces, the
9.216 +combination or composition of interfaces is somewhat different: crucially, all
9.217 +involved interfaces remain distinct and do not override each other (conflicts
9.218 +between protocols and operation codes notwithstanding).
9.219 +.PP
9.220 +Base interfaces, these being interfaces used in composition to make a compound
9.221 +interface, can be defined in the same file as the compound interface.
9.222 +Alternatively, an \fBimport\fR statement can be used to import interface
9.223 +definitions from another file, such files residing in the same directory as the
9.224 +file currently being processed. For example:
9.225 +.in +4n
9.226 +.nf
9.227 +.sp
9.228 +import "calc.idl";
9.229 +import "counter.idl";
9.230 +
9.231 +interface \fICalcCounter\fR composes \fICalc\fR, \fICounter\fR;
9.232 +.fi
9.233 +.PP
9.234 +Here, \fBcalc.idl\fR would provide \fBCalc\fR, and \fBcounter.idl\fR would
9.235 +provide \fBCounter\fR.
9.236
9.237 .SH FILES
9.238 .B idl
9.239 reads all interfaces in a single input file and generates output files that
9.240 -each contain the details of all of these interfaces. Apart from the compound
9.241 -interface files, output files are written alongside their corresponding input
9.242 -files. This behaviour can be overridden with the \fB\-d\fR or \fB\-\-dir\fR
9.243 -options, choosing a specific output directory for all files including compound
9.244 -interface files.
9.245 +each contain the details of all of these interfaces. By default, output files
9.246 +are written alongside their corresponding input files, but this behaviour can be
9.247 +overridden with the \fB\-d\fR or \fB\-\-dir\fR options, choosing a specific
9.248 +output directory for all files including compound interface files.
9.249 .PP
9.250 The following kinds of output files are generated for a file with a name of the
9.251 form
9.252 @@ -343,7 +414,9 @@
9.253 .TP
9.254 .IR name "_server.c or " name _server.cc
9.255 contains the function definitions needed to provide entry points for the
9.256 -operations of all the interfaces.
9.257 +operations of all the interfaces. Where an interface is composed of other
9.258 +interfaces, the function definitions will dispatch to these interfaces' own
9.259 +functions.
9.260 .TP
9.261 .IR name _server.h
9.262 contains the function declarations, signatures or prototypes for the entry
9.263 @@ -354,29 +427,11 @@
9.264 processes each one in turn, generating a separate set of output files for each
9.265 input file.
9.266 .PP
9.267 -For server components, compound interface files can also be produced with their
9.268 -names chosen using the \fB\-C\fR or \fB\-\-comp\fR options. With a value of
9.269 -\fIname\fR given with these options, files of the following form are produced:
9.270 -.TP
9.271 -.IR name _interface.h
9.272 -contains a compound interface declaration (for C++ only) needed for the dispatch
9.273 -mechanism to function, also to be used by the actual component implementing the
9.274 -interfaces.
9.275 -.TP
9.276 -.IR name _interfaces.h
9.277 -contains include statements referencing individual interfaces, needed by the
9.278 -above compound interface declaration.
9.279 -.TP
9.280 -.IR name "_server.c or " name _server.cc
9.281 -contains the function definitions needed to dispatch to the interfaces.
9.282 -.TP
9.283 -.IR name _server.h
9.284 -contains the function declarations, signatures or prototypes for the dispatch
9.285 -functions.
9.286 -.PP
9.287 -These files provide support for interpreting messages received by servers and
9.288 -directing handling of such messages to interface-specific dispatch functions or
9.289 -directly to functions acting as operation entry points.
9.290 +Output files will only be produced corresponding to the indicated input files,
9.291 +even if those files import other files. To generate output for the input files
9.292 +together with the imported files, use the
9.293 +.BR \-R " or " \-\-recursive
9.294 +options.
9.295
9.296 .SH L4RE BUILD SYSTEM INTEGRATION
9.297 To be useful in the L4Re build system, the
9.298 @@ -384,10 +439,10 @@
9.299 distribution should be made available with the name
9.300 .I idl4re
9.301 in the
9.302 -.I src/l4
9.303 -section of the general L4Re distribution. Rules can then be added to Makefiles
9.304 -to invoke the tool and to produce source files that can then be compiled in the
9.305 -normal way. A collection of Makefile-compatible files are provided in the
9.306 +.IR l4 " section (or " src/l4 " in earlier forms)"
9.307 +of the general L4Re distribution. Rules can then be added to Makefiles to invoke
9.308 +the tool and to produce source files that can then be compiled in the normal
9.309 +way. A collection of Makefile-compatible files are provided in the
9.310 .I mk
9.311 directory within the
9.312 .I idl4re
9.313 @@ -402,12 +457,19 @@
9.314 error details from the scanner and parser. Obviously, this should be improved
9.315 to make the tool more usable.
9.316 .PP
9.317 +Memory management is not comprehensive. However, this tool is meant to be run
9.318 +for the duration of a given code generation task, not run as a service
9.319 +indefinitely.
9.320 +.PP
9.321 Validation of input is also minimal, with the tool mostly acting as a kind of
9.322 preprocessor, generating code that may then not behave exactly as intended,
9.323 although the code should be well-formed.
9.324 .PP
9.325 -Interface inheritance is not supported, neither are modules. Both of these
9.326 -things are typically available in other languages describing interfaces.
9.327 +File inclusion is currently limited to loading files that all reside in the same
9.328 +location, although include paths could be supported.
9.329 +.PP
9.330 +Things like modules and type definitions are not supported, these typically
9.331 +being available in other languages describing interfaces.
9.332
9.333 .SH AUTHOR
9.334 Paul Boddie <paul@boddie.org.uk>
10.1 --- a/docs/wiki/Clients Fri Dec 09 19:33:15 2022 +0100
10.2 +++ b/docs/wiki/Clients Sat Dec 10 01:28:22 2022 +0100
10.3 @@ -4,7 +4,8 @@
10.4 those components' interfaces, potentially via interprocess communications
10.5 mechanisms. Given an interface description featuring component operations,
10.6 code may be written to invoke these operations and to treat the component as
10.7 -if it resides in the same program.
10.8 +if it resides in the same program, even if it actually resides in another
10.9 +program operating as a [[Servers|server]].
10.10
10.11 <<TableOfContents(2)>>
10.12
11.1 --- a/docs/wiki/Development Fri Dec 09 19:33:15 2022 +0100
11.2 +++ b/docs/wiki/Development Sat Dec 10 01:28:22 2022 +0100
11.3 @@ -18,11 +18,6 @@
11.4
11.5 * Input file access and output coordination.
11.6
11.7 - * Parser initialisation and invocation using the `yyrestart` and
11.8 - `yyparse` functions, and parser state management.
11.9 -
11.10 -Various helper functions are also defined.
11.11 -
11.12 == Configuration ==
11.13
11.14 The `config.c` and `config.h` files define configuration state for the program
11.15 @@ -97,10 +92,11 @@
11.16 directly by the scanner.
11.17
11.18 For example, the `include` rule obtains a value associated with a header
11.19 -filename. This filename is associated with the `HEADER` token and its value is
11.20 -interpreted as a string. However, the rule needs to prepare a structure that
11.21 -incorporates the filename and that can be referenced by other structures. To
11.22 -achieve this, a `%union` member is defined for the structure type concerned:
11.23 +filename. This filename is associated with the `PHEADER` and `QHEADER` tokens
11.24 +and its value is interpreted as a string. However, the rule needs to prepare a
11.25 +structure that incorporates the filename and that can be referenced by other
11.26 +structures. To achieve this, a `%union` member is defined for the structure
11.27 +type concerned:
11.28
11.29 {{{
11.30 %union {
11.31 @@ -220,56 +216,63 @@
11.32 {
11.33 node [shape=record,fontsize="12.0",fontname="sans-serif"];
11.34
11.35 - interface [label="{interface | {name |<s> signatures |<a> attributes |<i> includes |<t> tail}}"];
11.36 - signature [label="{signature | {qualifier | operation |<p> parameters |<a> attributes |<t> tail}}"];
11.37 - attribute [label="{attribute | {attribute |<i> identifiers |<t> tail}}"];
11.38 - parameter [label="{parameter | {specifier | class |<i> identifiers |<t> tail}}"];
11.39 - identifier [label="{identifier | {identifier |<t> tail}}"];
11.40 - include [label="{include | {filename |<t> tail}}"];
11.41 + interface [label="{<X> interface | {name |<b> bases |<s> signatures |<a> attributes |<I> imports |<i> includes |<t> tail}}"];
11.42 + interface_ref [label="{<X> interface_ref | {name |<i> iface |<t> tail}}"];
11.43 + signature [label="{<X> signature | {qualifier | operation |<p> parameters |<a> attributes |<t> tail}}"];
11.44 + attribute [label="{<X> attribute | {attribute |<i> identifiers |<t> tail}}"];
11.45 + parameter [label="{<X> parameter | {specifier | class |<i> identifiers |<t> tail}}"];
11.46 + identifier [label="{<X> identifier | {identifier |<t> tail}}"];
11.47 + import [label="{<X> import | {filename |<t> tail}}"];
11.48 + include [label="{<X> include | {filename |<t> tail}}"];
11.49
11.50 + interface:b -> interface_ref;
11.51 interface:s -> signature;
11.52 interface:a -> attribute;
11.53 + interface:I -> import;
11.54 interface:i -> include;
11.55 - interface:t -> interface;
11.56 + interface:t -> interface:X;
11.57 +
11.58 + interface_ref:i -> interface:X;
11.59 + interface_ref:t -> interface_ref:X;
11.60
11.61 signature:p -> parameter;
11.62 signature:a -> attribute;
11.63 - signature:t -> signature;
11.64 + signature:t -> signature:X;
11.65
11.66 attribute:i -> identifier;
11.67 - attribute:t -> attribute;
11.68 + attribute:t -> attribute:X;
11.69
11.70 parameter:i -> identifier;
11.71 - parameter:t -> parameter;
11.72 + parameter:t -> parameter:X;
11.73 +
11.74 + identifier:t -> identifier:X;
11.75
11.76 - identifier:t -> identifier;
11.77 + import:t -> import:X;
11.78
11.79 - include:t -> include;
11.80 + include:t -> include:X;
11.81 }
11.82 }}}
11.83
11.84 ######## End of graph.
11.85
11.86 The nature of the hierarchy should reflect the conceptual form of the input.
11.87 -It should be noted that header file information (represented by `include`
11.88 -structures) is associated with interface information (represented by
11.89 -`interface` structures). This arrangement merely attempts to indicate the
11.90 -header file declarations that preceded specific interface declarations, but
11.91 -the two different types of information should arguably be grouped within a
11.92 +It should be noted that imported file and header file information (represented
11.93 +by `import` and `include` structures respectively) is associated with
11.94 +interface information (represented by `interface` structures). This
11.95 +arrangement merely attempts to indicate the import and header file
11.96 +declarations that preceded specific interface declarations, but the two
11.97 +different types of information should arguably be grouped within a
11.98 file-oriented structure.
11.99
11.100 == Code Generation ==
11.101
11.102 The `program.c` and `program.h` files define the functions that coordinate the
11.103 generation of program code. It is in `program.c` that files are opened for
11.104 -writing (using the `get_output_file` function provided by `common.c`), and two
11.105 -principal functions are involved in initiating the population of these files:
11.106 -
11.107 - * `begin_compound_output`
11.108 - * `write_files`
11.109 -
11.110 -These functions are described in more detail with regard to the topics of
11.111 -compound and individual interfaces.
11.112 +writing (using the `get_output_file` function provided by `common.c`), and the
11.113 +principal function involved in initiating the population of these files is the
11.114 +`write_files` function. This function then invokes `write_interfaces` to
11.115 +coordinate the code generation for each of the interfaces described by the
11.116 +input.
11.117
11.118 Meanwhile, a selection of writer functions are employed to generate code for
11.119 the different structures employed within interface descriptions. Since output
11.120 @@ -289,93 +292,21 @@
11.121 Through the use of roles, the same fundamental information can be expressed in
11.122 different ways by the same routine.
11.123
11.124 -=== Compound Interfaces ===
11.125 -
11.126 -The `begin_compound_output` function is called by the main program when
11.127 -compound interface generation has been requested. It produces extra output
11.128 -that references and augments output produced for individual interfaces.
11.129 +=== Interfaces ===
11.130
11.131 -Various details of individual interfaces are incorporated into the compound
11.132 -interface output. To achieve this, once the `begin_compound_output` function
11.133 -has been called, individual interface output is generated. During this
11.134 -activity, the `write_compound_output` function is called for each individual
11.135 -interface to insert details of that interface into the appropriate place
11.136 -within the compound interface output.
11.137 -
11.138 -The `end_compound_output` function ultimately closes the files involved,
11.139 -either through being invoked by the main program or upon a failure condition.
11.140 -
11.141 -The following diagram summarises the general function organisation involved.
11.142 +The `write_files` function coordinates output generation for each interface.
11.143
11.144 ######## A graph showing the function organisation involved in generating
11.145 -######## compound interfaces...
11.146 +######## interfaces...
11.147
11.148 {{{#!graphviz
11.149 #format svg
11.150 #transform notugly
11.151 -digraph compound
11.152 +digraph interfaces
11.153 {
11.154 node [shape=box,fontsize="12.0",fontname="sans-serif",style=filled,fillcolor=white];
11.155 rankdir=LR;
11.156
11.157 - parser [shape=ellipse];
11.158 -
11.159 - subgraph {
11.160 - rank=same;
11.161 - server [shape=folder,fillcolor="#77ff77",label="..._server.{c,cc,h}"];
11.162 - interface [shape=folder,fillcolor="#77ff77",label="..._interface.h"];
11.163 - interfaces [shape=folder,fillcolor="#77ff77",label="..._interfaces.h"];
11.164 - interface_type [shape=folder,fillcolor="#77ff77",label="..._interface_type.h"];
11.165 - }
11.166 -
11.167 - subgraph {
11.168 - rank=same;
11.169 - main -> yyparse -> parser -> write_files -> write_interfaces;
11.170 - }
11.171 -
11.172 - main -> begin_compound_output;
11.173 - main -> end_compound_output;
11.174 -
11.175 - begin_compound_output -> write_handler_signature;
11.176 - begin_compound_output -> write_dispatcher_signature;
11.177 -
11.178 - write_handler_signature -> server;
11.179 -
11.180 - write_dispatcher_signature -> server;
11.181 -
11.182 - write_files -> write_compound_dispatch_include -> server;
11.183 -
11.184 - write_interfaces -> write_compound_output;
11.185 -
11.186 - write_compound_output -> write_dispatcher_cases -> server;
11.187 - write_compound_output -> write_compound_interface;
11.188 -
11.189 - write_compound_interface -> interface;
11.190 - write_compound_output -> write_include -> interfaces;
11.191 - write_include -> interface_type;
11.192 -}
11.193 -}}}
11.194 -
11.195 -######## End of graph.
11.196 -
11.197 -=== Individual Interfaces ===
11.198 -
11.199 -The `write_files` function coordinates the generation of individual interface
11.200 -output.
11.201 -
11.202 -######## A graph showing the function organisation involved in generating
11.203 -######## individual interfaces...
11.204 -
11.205 -{{{#!graphviz
11.206 -#format svg
11.207 -#transform notugly
11.208 -digraph individual
11.209 -{
11.210 - node [shape=box,fontsize="12.0",fontname="sans-serif",style=filled,fillcolor=white];
11.211 - rankdir=LR;
11.212 -
11.213 - parser [shape=ellipse];
11.214 -
11.215 subgraph {
11.216 rank=same;
11.217 client [shape=folder,fillcolor="#77ff77",label="..._client.{c,cc,h}"];
11.218 @@ -385,7 +316,7 @@
11.219
11.220 subgraph {
11.221 rank=same;
11.222 - main -> yyparse -> parser -> write_files -> write_interfaces;
11.223 + main -> import_file -> write_files -> write_interfaces;
11.224 }
11.225
11.226 write_interfaces -> write_client_interface;
11.227 @@ -395,6 +326,7 @@
11.228 write_interfaces -> write_handler_signature;
11.229 write_interfaces -> write_include;
11.230 write_interfaces -> write_interface_definition;
11.231 + write_interfaces -> write_server_includes -> write_include;
11.232 write_interfaces -> write_signatures;
11.233
11.234 write_client_interface -> client;
11.235 @@ -415,19 +347,67 @@
11.236
11.237 ######## End of graph.
11.238
11.239 +=== Imports and Parsing ===
11.240 +
11.241 +The `imports.c` file coordinates the parsing and code generation activities.
11.242 +Upon running the tool, the `import_file` function is invoked by the `main`
11.243 +function (in `main.c`) for each input file.
11.244 +
11.245 +The `import_file` function invokes the parser and with a successfully parsed
11.246 +result, it then seeks to resolve any `import` statements mentioned in the
11.247 +input. The `resolve_imports` function iterates over any such imports, these
11.248 +represented by import structures, calling the `import_file` function to obtain
11.249 +another parsing result structure for each import, with a reference to this
11.250 +structure being stored in the import structure concerned, thus establishing
11.251 +inter-file relationships. Such importing is done recursively.
11.252 +
11.253 +######## A graph showing the function organisation involved in importing
11.254 +######## files...
11.255 +
11.256 +{{{#!graphviz
11.257 +#format svg
11.258 +#transform notugly
11.259 +digraph importing
11.260 +{
11.261 + node [shape=box,fontsize="12.0",fontname="sans-serif",style=filled,fillcolor=white];
11.262 + rankdir=LR;
11.263 +
11.264 + parser [shape=ellipse];
11.265 +
11.266 + subgraph {
11.267 + rank=same;
11.268 +
11.269 + main -> import_file;
11.270 + }
11.271 +
11.272 + import_file -> yyparse -> parser;
11.273 + import_file -> resolve_imports -> import_file;
11.274 + import_file -> populate_bases;
11.275 +}
11.276 +}}}
11.277 +
11.278 +######## End of graph.
11.279 +
11.280 +Where compound interfaces are defined in the input, these composing or
11.281 +combining other interfaces, the identity of such base interfaces needs to be
11.282 +determined. This is done by the `populate_bases` function which searches the
11.283 +parsing results from the location of each compound interface whose base
11.284 +interfaces are to be resolved, traversing interface definitions and imports.
11.285 +When determined, an interface definition will then be directly referenced by
11.286 +the base interface reference associated with the compound interface.
11.287 +
11.288 === Includes and Headers ===
11.289
11.290 -The `includes.c` and `includes.h` files provide support for writing `#include`
11.291 -statements in C and C++ programs, with the `write_includes` function
11.292 -traversing an `include` structure list to emit a list of statements.
11.293 +The `includes.c` file provides support for writing `#include` statements in C
11.294 +and C++ programs, with the `write_includes` function traversing an `include`
11.295 +structure list to emit a list of statements.
11.296
11.297 === Interface Definitions ===
11.298
11.299 -The `interface.c` and `interface.h` files provide the
11.300 -`write_interface_definition` function which is concerned with generating a
11.301 -description of an interface in two different contexts: client and server.
11.302 -Some generated files are employed in both contexts such as the file of the
11.303 -form `<interface>_interface.h`.
11.304 +The `interface.c` file provides the `write_interface_definition` function
11.305 +which is concerned with generating a description of an interface in two
11.306 +different contexts: client and server. Some generated files are employed in
11.307 +both contexts such as the file of the form `<interface>_interface.h`.
11.308
11.309 ==== Client Definitions ====
11.310
11.311 @@ -464,25 +444,64 @@
11.312
11.313 === Templates and Output ===
11.314
11.315 - * `templates.h`
11.316 +The strings used to generate output are provided in `templates.h`. Many of
11.317 +these strings contain placeholders in the form of output specifiers such as
11.318 +`%s` and `%d` used by the `fprintf` function. A more sophisticated approach
11.319 +would involve the use of a template language, which would potentially simplify
11.320 +this tool's code and make the output generation mechanisms somewhat clearer.
11.321 +
11.322 +=== Clients ===
11.323 +
11.324 +The `client.c` file is concerned with generating wrapper functions that
11.325 +present the operations exposed by an interface to a client program. These
11.326 +wrapper functions take any parameters supplied to them and populate a message
11.327 +to be sent to the server providing the implementation of the interface,
11.328 +sending the message to the server, interpreting the reply, and setting output
11.329 +parameters appropriately.
11.330 +
11.331 +The form of client wrapper functions is similar to that of server wrapper
11.332 +functions, and various common functions are used by both client and server
11.333 +code generation activities.
11.334
11.335 === Servers ===
11.336
11.337 - * `server.c`
11.338 +The `server.c` file is concerned with the generation of code for wrapper
11.339 +functions for each of the operations associated with an interface, this code
11.340 +obtaining values from messages and invoking the actual operation
11.341 +implementations.
11.342 +
11.343 +Most of the functions provided are concerned with the generation of variable
11.344 +declarations and the initialisation of such variables from messages, the
11.345 +formulation of invocation statements, and the population of messages from
11.346 +operation results. Various common functions are used by client and server code
11.347 +generation activities.
11.348
11.349 === Dispatchers and Handlers ===
11.350
11.351 - * `dispatch.c`
11.352 +The generation of code that interprets message details and dispatches to the
11.353 +wrapper functions written by `server.c` can be found in the `dispatch.c` file.
11.354
11.355 === Parameters and Members ===
11.356
11.357 - * `declaration.c`
11.358 +The `declaration.c` file provides general support for generating declarations
11.359 +for client and server code, handling artefacts such as interfaces, function
11.360 +signatures and parameters.
11.361
11.362 === Message Structures and Access ===
11.363
11.364 - * `message.c`
11.365 - * `structure.c`
11.366 +The `message.c` file provides support for the generation of statements related
11.367 +to the access of message contents. The functions provided are used by the
11.368 +`client.c` and `server.c` files in the generation of wrapper functions.
11.369 +
11.370 +The `structure.c` file concerns itself with the generation of operation code
11.371 +(opcode) enumerations, these giving each operation a distinct identifier,
11.372 +along with the generation of structures used to interpret and populate
11.373 +messages for each operation.
11.374
11.375 === Summaries ===
11.376
11.377 - * `summary.c`
11.378 +The `summary.c` file provides functions to display the structure of parsed
11.379 +interface files. Each function corresponds to a data structure defined in
11.380 +`types.h`, with references traversed to other structures. The `show_interface`
11.381 +function is the entry point from which other structures created during parsing
11.382 +are reached.
12.1 --- a/docs/wiki/L4Re_Support Fri Dec 09 19:33:15 2022 +0100
12.2 +++ b/docs/wiki/L4Re_Support Sat Dec 10 01:28:22 2022 +0100
12.3 @@ -316,84 +316,3 @@
12.4
12.5 The variables are then employed in filename transformations, described in more
12.6 detail elsewhere in this document.
12.7 -
12.8 -=== Compound Interfaces ===
12.9 -
12.10 -The `idl` tool also supports compound interfaces which combine individual
12.11 -interface descriptions so that server components can expose multiple
12.12 -interfaces. Here, a naming convention is employed:
12.13 -
12.14 -|| '''Variable''' || '''Details''' ||
12.15 -|| `interface_NAME` || Indicates the program name of a compound object ||
12.16 -|| `interface_INTERFACES` || A list of individual interface descriptions ||
12.17 -
12.18 -The `interface` portion of each variable is replaced by a compound interface
12.19 -name as in the following example:
12.20 -
12.21 -{{{
12.22 -mapped_file_object_NAME = MappedFileObject
12.23 -mapped_file_object_INTERFACES = dataspace file mapped_file sync
12.24 -}}}
12.25 -
12.26 -Thus, the compound interface description `mapped_file_object` employs the
12.27 -stated individual interfaces and program name:
12.28 -
12.29 -######## A diagram showing an example compound interface...
12.30 -
12.31 -{{{#!graphviz
12.32 -#format svg
12.33 -#transform notugly
12.34 -digraph example
12.35 -{
12.36 - graph [splines=ortho];
12.37 - node [shape=box,fontsize="12.0",fontname="sans-serif",style=filled,fillcolor=white];
12.38 - edge [arrowhead=empty];
12.39 - rankdir=BT;
12.40 -
12.41 - MappedFileObject [label="MappedFileObject\n(from mapped_file_object)"];
12.42 - Dataspace [label="Dataspace\n(from dataspace)"];
12.43 - File [label="File\n(from file)"];
12.44 - MappedFile [label="MappedFile\n(from mapped_file)"];
12.45 - Sync [label="Sync\n(from sync)"];
12.46 -
12.47 - MappedFileObject -> Dataspace;
12.48 - MappedFileObject -> File;
12.49 - MappedFileObject -> MappedFile;
12.50 - MappedFileObject -> Sync;
12.51 -}
12.52 -}}}
12.53 -
12.54 -######## End of diagram.
12.55 -
12.56 -Defining a compound interface would be equivalent to defining an interface as
12.57 -follows, if `idl` were to support this syntax:
12.58 -
12.59 -{{{
12.60 -interface MappedFileObject inherits Dataspace, File, MappedFile, Sync
12.61 -{
12.62 -};
12.63 -}}}
12.64 -
12.65 -(Currently, this syntax is not supported due to limitations with the tool.)
12.66 -
12.67 -Just as with individual interface descriptions, rules are generated to ensure
12.68 -that code supporting compound interfaces is generated from the interface
12.69 -description files.
12.70 -
12.71 -Special variables act as manifests of all compound interface descriptions used
12.72 -in a particular way:
12.73 -
12.74 -|| '''Variable''' || '''Interface Usage''' ||
12.75 -|| `COMP_INTERFACES_C` || C language server code ||
12.76 -|| `COMP_INTERFACES_CC` || C++ language server code ||
12.77 -
12.78 -For example:
12.79 -
12.80 -{{{
12.81 -COMP_INTERFACES_CC = filesystem_object mapped_file_object
12.82 -}}}
12.83 -
12.84 -Here, two compound interfaces are listed for generation as C++ components.
12.85 -Thus, appropriate `_NAME` and `_INTERFACES` variables must be defined to
12.86 -permit the necessary rule generation so that `make` can generate and build all
12.87 -appropriate files.
13.1 --- a/docs/wiki/Servers Fri Dec 09 19:33:15 2022 +0100
13.2 +++ b/docs/wiki/Servers Sat Dec 10 01:28:22 2022 +0100
13.3 @@ -1,14 +1,15 @@
13.4 = Servers =
13.5
13.6 Server code is code that provides components in the form described by those
13.7 -components' interfaces, employing interprocess communications mechanisms.
13.8 +components' interfaces, employing interprocess communications mechanisms to
13.9 +expose those components to [[Clients|clients]].
13.10
13.11 <<TableOfContents(2)>>
13.12
13.13 == Introduction ==
13.14
13.15 -The following example interface, resident in a file called `calc.idl`, will be
13.16 -used to illustrate the mechanisms described in this document:
13.17 +The following example interfaces will be used to illustrate the mechanisms
13.18 +described in this document. Firstly, in `calc.idl`:
13.19
13.20 {{{
13.21 interface Calc
13.22 @@ -20,8 +21,26 @@
13.23 };
13.24 }}}
13.25
13.26 -To expose this interface to other programs, a server program would do the
13.27 -following:
13.28 +Secondly, in `counter.idl`:
13.29 +
13.30 +{{{
13.31 +interface Counter
13.32 +{
13.33 + void increment(out int result);
13.34 +};
13.35 +}}}
13.36 +
13.37 +Finally, in `calc_counter.idl`:
13.38 +
13.39 +{{{
13.40 +import "calc.idl";
13.41 +import "counter.idl";
13.42 +
13.43 +interface MappedFileObject composes Dataspace, File, Flush, MappedFile, Notification;
13.44 +}}}
13.45 +
13.46 +To expose these interfaces to other programs, a server program would do the
13.47 +following in each case:
13.48
13.49 * Obtain appropriate program types to reference the interface
13.50
13.51 @@ -54,19 +73,22 @@
13.52
13.53 == C Language Servers ==
13.54
13.55 -An object representing a server will have the `Calc` type. This encapsulates
13.56 -a reference to the object state and a reference to the interface details.
13.57 +A server exposing the `Calc` interface will employ an object having the `Calc`
13.58 +type. This encapsulates a reference to the object state and a reference to the
13.59 +interface details.
13.60
13.61 Since the aim in implementing a server is to provide access to state
13.62 information held within a process, the object state reference will refer to a
13.63 -location holding such information via a pointer member.
13.64 +location holding such information via a pointer member. The following could be
13.65 +used for the state supporting the `Calc` interface.
13.66
13.67 {{{
13.68 ref_Calc ref = {.ptr=0};
13.69 }}}
13.70
13.71 Here, a value of `0` is used because the interface operations are stateless
13.72 -(they act like plain functions):
13.73 +(they act like plain functions), and so it does not really matter what `ptr`
13.74 +is set to.
13.75
13.76 The `Calc` object is initialised using the chosen reference value and a
13.77 reference to interface information:
13.78 @@ -89,8 +111,23 @@
13.79 };
13.80 }}}
13.81
13.82 -The `Calc` object is then associated with a server capability and invoked when
13.83 -incoming messages are directed towards it.
13.84 +The `Calc` object is then [[#Exposing|associated with a server capability]]
13.85 +and invoked when incoming messages are directed towards it.
13.86 +
13.87 +Where operations are not stateless and instead operate on some kind of state
13.88 +or object, the reference is initialised as in this example involving the
13.89 +`Counter` interface:
13.90 +
13.91 +{{{
13.92 +int counter = 0;
13.93 +ref_Counter ref = {.ptr=&counter};
13.94 +}}}
13.95 +
13.96 +Here, the state modified by the `Counter` operations is a simple integer. As
13.97 +long as the operations are written to interpret the state correctly, it does
13.98 +not matter what kind of object provides the state. For C language servers,
13.99 +there is not necessarily a requirement to have a dedicated data structure
13.100 +containing the state.
13.101
13.102 === Compound Interfaces ===
13.103
13.104 @@ -99,22 +136,26 @@
13.105 example involving a reference suitable for a `CalcCounter` object:
13.106
13.107 {{{
13.108 -ref_CalcCounter ref = {.ptr=&counter};
13.109 +ref_CalcCounter ref = {.ptr=0, .as_Counter={.ptr=&counter}};
13.110 }}}
13.111
13.112 -Here, the pointer member employs the address of a counter. This is accessed in
13.113 -the appropriate operation function.
13.114 +Here, the pointer member is given as `0` because there is no dedicated state
13.115 +for the `CalcCounter` compound interface. However, when the component is to be
13.116 +interpreted as a `Counter`, the `as_Counter` member provides the corresponding
13.117 +reference, this indicating the address of a counter as the pointer to the
13.118 +appropriate state, as previously suggested.
13.119
13.120 -The object itself is populated in the same way as shown above:
13.121 +The object employed by the server is itself populated in the same way as shown
13.122 +above:
13.123
13.124 {{{
13.125 CalcCounter obj = {.ref=ref, .iface=&server_iface_CalcCounter};
13.126 }}}
13.127
13.128 -The principal difference involves the interface details. Since a compound
13.129 -interface is exposed, there must be a way to address the individual
13.130 -interfaces, and this is done using members employing a specific naming
13.131 -convention:
13.132 +The principal difference between simple and compound interface definition
13.133 +involves the interface details. With a compound interface, there must be a way
13.134 +to address the individual interfaces, and this is done using members employing
13.135 +a specific naming convention:
13.136
13.137 {{{
13.138 iface_CalcCounter server_iface_CalcCounter = {
13.139 @@ -145,7 +186,9 @@
13.140 }}}
13.141
13.142 Here, the pointer member is used to access the information referenced when the
13.143 -object was initialised.
13.144 +object was initialised. As noted above, the interpretation of the pointer
13.145 +member is left to the operations, with the chosen interpretation being a
13.146 +simple integer in this example.
13.147
13.148 == C++ Language Servers ==
13.149
13.150 @@ -171,8 +214,8 @@
13.151 };
13.152 }}}
13.153
13.154 -The `server_Calc` object is then associated with a server capability and
13.155 -invoked when incoming messages are directed towards it.
13.156 +The `server_Calc` object is then [[#Exposing|associated with a server
13.157 +capability]] and invoked when incoming messages are directed towards it.
13.158
13.159 === Compound Interfaces ===
13.160
13.161 @@ -215,6 +258,7 @@
13.162 }
13.163 }}}
13.164
13.165 +((Exposing))
13.166 == Exposing Objects as Servers ==
13.167
13.168 In L4Re, component objects can be made available to other programs by
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/examples/directory_object.idl Sat Dec 10 01:28:22 2022 +0100
14.3 @@ -0,0 +1,4 @@
14.4 +import "directory.idl";
14.5 +import "notification.idl";
14.6 +
14.7 +interface DirectoryObject composes Directory, Notification;
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/examples/filesystem_object.idl Sat Dec 10 01:28:22 2022 +0100
15.3 @@ -0,0 +1,4 @@
15.4 +import "filesystem.idl";
15.5 +import "filesystem_factory.idl";
15.6 +
15.7 +interface FilesystemObject composes Filesystem, FilesystemFactory;
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/examples/mapped_file_object.idl Sat Dec 10 01:28:22 2022 +0100
16.3 @@ -0,0 +1,7 @@
16.4 +import "dataspace.idl";
16.5 +import "file.idl";
16.6 +import "flush.idl";
16.7 +import "mapped_file.idl";
16.8 +import "notification.idl";
16.9 +
16.10 +interface MappedFileObject composes Dataspace, File, Flush, MappedFile, Notification;
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/examples/opener_context_object.idl Sat Dec 10 01:28:22 2022 +0100
17.3 @@ -0,0 +1,4 @@
17.4 +import "dataspace.idl";
17.5 +import "opener_context.idl";
17.6 +
17.7 +interface OpenerContextObject composes Dataspace, OpenerContext;
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/examples/pager_object.idl Sat Dec 10 01:28:22 2022 +0100
18.3 @@ -0,0 +1,4 @@
18.4 +import "region_mapper.idl";
18.5 +import "system_pager.idl";
18.6 +
18.7 +interface PagerObject composes RegionMapper, SystemPager;
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/examples/pipe_object.idl Sat Dec 10 01:28:22 2022 +0100
19.3 @@ -0,0 +1,6 @@
19.4 +import "dataspace.idl";
19.5 +import "flush.idl";
19.6 +import "notification.idl";
19.7 +import "pipe.idl";
19.8 +
19.9 +interface PipeObject composes Dataspace, Flush, Notification, Pipe;
20.1 --- a/idl.lex Fri Dec 09 19:33:15 2022 +0100
20.2 +++ b/idl.lex Sat Dec 10 01:28:22 2022 +0100
20.3 @@ -42,9 +42,10 @@
20.4 {WS} /* discard */
20.5
20.6 ^"#include" return INCLUDE;
20.7 -"<"[^>]*">" yylval.str = strdup(yytext); return HEADER;
20.8 -\"[^"]*\" yylval.str = strdup(yytext); return HEADER;
20.9 +"<"[^>]*">" yylval.str = strdup(yytext); return PHEADER;
20.10 +\"[^"]*\" yylval.str = strdup(yytext); return QHEADER;
20.11
20.12 +"import" return IMPORT;
20.13 "interface" return INTERFACE;
20.14
20.15 "in" yylval.num = IN_PARAMETER; return IN;
20.16 @@ -66,6 +67,8 @@
20.17 "{" return BEGINSECTION;
20.18 "}" return ENDSECTION;
20.19
20.20 +"composes" return COMPOSES;
20.21 +
20.22 [_[:alpha:]][_[:alnum:]]* yylval.str = strdup(yytext); return IDENTIFIER;
20.23 [[:digit:]]+ yylval.str = strdup(yytext); return DECIMAL;
20.24 "0"[xX][[:xdigit:]]+ yylval.str = strdup(yytext); return HEXADECIMAL;
21.1 --- a/idl.y Fri Dec 09 19:33:15 2022 +0100
21.2 +++ b/idl.y Sat Dec 10 01:28:22 2022 +0100
21.3 @@ -1,7 +1,7 @@
21.4 /*
21.5 * Grammar for a simple interface description language.
21.6 *
21.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
21.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
21.9 *
21.10 * This program is free software; you can redistribute it and/or
21.11 * modify it under the terms of the GNU General Public License as
21.12 @@ -33,7 +33,9 @@
21.13 /* State information, also reset by the function defined below. */
21.14
21.15 struct interface *last_interface = NULL;
21.16 +struct import *last_import = NULL;
21.17 struct include *last_include = NULL;
21.18 +const char *output_dirname = NULL, *output_basename = NULL;
21.19 %}
21.20
21.21 %define parse.error verbose
21.22 @@ -43,8 +45,10 @@
21.23 %union {
21.24 long num;
21.25 char *str;
21.26 + struct import imp;
21.27 struct include inc;
21.28 struct interface iface;
21.29 + struct interface_ref iface_ref;
21.30 struct signature sig;
21.31 struct identifier ident;
21.32 struct parameter param;
21.33 @@ -56,7 +60,7 @@
21.34 %type <str> IDENTIFIER DECIMAL HEXADECIMAL
21.35 %type <str> interface_name
21.36 %type <str> qualifier operation
21.37 -%type <str> HEADER
21.38 +%type <str> header PHEADER QHEADER
21.39 %type <str> attr_param
21.40
21.41 /* Specifiers and items have numeric values. */
21.42 @@ -68,9 +72,11 @@
21.43
21.44 /* Associate rules with the appropriate union members. */
21.45
21.46 +%type <imp> import
21.47 %type <inc> include
21.48 %type <iface> q_interface
21.49 %type <iface> interface
21.50 +%type <iface_ref> interface_bases
21.51 %type <sig> q_signature
21.52 %type <sig> signature
21.53 %type <sig> signatures
21.54 @@ -83,7 +89,7 @@
21.55
21.56 /* Scanner token types. */
21.57
21.58 -%token INCLUDE HEADER
21.59 +%token IMPORT INCLUDE PHEADER QHEADER
21.60 %token INTERFACE
21.61 %token BEGINSECTION ENDSECTION
21.62 %token LPAR RPAR
21.63 @@ -92,6 +98,7 @@
21.64 %token IN INOUT OUT
21.65 %token CAP FPAGE
21.66 %token IDENTIFIER DECIMAL HEXADECIMAL
21.67 +%token COMPOSES
21.68
21.69 /* Starting rule. */
21.70
21.71 @@ -99,24 +106,36 @@
21.72
21.73 %%
21.74
21.75 +/* Parse each file, with last_interface yielding the parsing products. */
21.76 +
21.77 file : statements
21.78 - { write_files(last_interface); }
21.79 ;
21.80
21.81 statements : statement statements
21.82 | %empty
21.83 ;
21.84
21.85 -statement : include
21.86 +statement : import
21.87 + | include
21.88 | q_interface
21.89 - { $1.tail = last_interface; last_interface = copy_interface($1); }
21.90 + { $1.output_dirname = output_dirname; $1.output_basename = output_basename;
21.91 + $1.tail = last_interface; last_interface = copy_interface($1); }
21.92 ;
21.93
21.94 -include : INCLUDE HEADER
21.95 +import : IMPORT QHEADER TERM
21.96 + { $$.filename = $2; $$.tail = last_import; last_import = copy_import($$); }
21.97 + ;
21.98 +
21.99 +include : INCLUDE header
21.100 { $$.filename = $2; $$.tail = last_include; last_include = copy_include($$); }
21.101 ;
21.102
21.103 -/* Interface qualified with or without attributes. */
21.104 +header : PHEADER
21.105 + | QHEADER
21.106 + ;
21.107 +
21.108 +/* Interface qualified with or without attributes, either having a signature
21.109 + section or a list of base interfaces. */
21.110
21.111 q_interface : LBRACE attributes RBRACE interface
21.112 { $4.attributes = copy_attribute($2); $$ = $4; }
21.113 @@ -125,13 +144,26 @@
21.114 ;
21.115
21.116 interface : INTERFACE interface_name BEGINSECTION signatures ENDSECTION TERM
21.117 - { $$.name = $2; $$.signatures = copy_signature($4); $$.includes = last_include; last_include = NULL; }
21.118 + { $$.name = $2; $$.bases = NULL; $$.signatures = copy_signature($4);
21.119 + $$.imports = last_import;
21.120 + $$.includes = last_include; last_include = NULL; }
21.121 | INTERFACE interface_name BEGINSECTION ENDSECTION TERM
21.122 - { $$.name = $2; $$.signatures = NULL; $$.includes = last_include; last_include = NULL; }
21.123 + { $$.name = $2; $$.bases = NULL; $$.signatures = NULL;
21.124 + $$.imports = last_import;
21.125 + $$.includes = last_include; last_include = NULL; }
21.126 + | INTERFACE interface_name COMPOSES interface_bases TERM
21.127 + { $$.name = $2; $$.bases = copy_interface_ref($4); $$.signatures = NULL;
21.128 + $$.imports = last_import;
21.129 + $$.includes = last_include; last_include = NULL; }
21.130 ;
21.131
21.132 interface_name : IDENTIFIER ;
21.133
21.134 +interface_bases : interface_name SEP interface_bases
21.135 + { $$.name = $1; $$.iface = NULL; copy_tail(interface_ref, $$, $3); }
21.136 + | interface_name
21.137 + { $$.name = $1; $$.iface = NULL; $$.tail = NULL; }
21.138 +
21.139 /* Signatures qualified with or without attributes. */
21.140
21.141 signatures : q_signature signatures
21.142 @@ -219,10 +251,13 @@
21.143 return v;
21.144 }
21.145
21.146 -void reset(void)
21.147 +void reset(const char *dirname, const char *basename)
21.148 {
21.149 last_interface = NULL;
21.150 + last_import = NULL;
21.151 last_include = NULL;
21.152 + output_dirname = dirname;
21.153 + output_basename = basename;
21.154 }
21.155
21.156 void yyerror(const char *message)
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/imports.c Sat Dec 10 01:28:22 2022 +0100
22.3 @@ -0,0 +1,288 @@
22.4 +/*
22.5 + * File parsing and importing.
22.6 + *
22.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
22.8 + *
22.9 + * This program is free software; you can redistribute it and/or
22.10 + * modify it under the terms of the GNU General Public License as
22.11 + * published by the Free Software Foundation; either version 2 of
22.12 + * the License, or (at your option) any later version.
22.13 + *
22.14 + * This program is distributed in the hope that it will be useful,
22.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
22.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22.17 + * GNU General Public License for more details.
22.18 + *
22.19 + * You should have received a copy of the GNU General Public License
22.20 + * along with this program; if not, write to the Free Software
22.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
22.22 + * Boston, MA 02110-1301, USA
22.23 + */
22.24 +
22.25 +#include <stdio.h>
22.26 +#include <stdlib.h>
22.27 +#include <string.h>
22.28 +#include "common.h"
22.29 +#include "config.h"
22.30 +#include "imports.h"
22.31 +#include "program.h"
22.32 +
22.33 +
22.34 +
22.35 +/* Parser functions and settings. */
22.36 +
22.37 +extern void yyparse(void);
22.38 +extern void yyrestart(FILE *);
22.39 +extern int yydebug;
22.40 +
22.41 +/* Specialised parser functions. */
22.42 +
22.43 +extern void reset(const char *dirname, const char *basename);
22.44 +
22.45 +/* Parsing products. */
22.46 +
22.47 +extern struct interface *last_interface;
22.48 +
22.49 +/* Input directory. */
22.50 +
22.51 +static char *input_dirname = NULL;
22.52 +
22.53 +
22.54 +
22.55 +/* Obtain the basename and directory name of generated output. */
22.56 +
22.57 +static int get_output_location(const char *filename, char **dirname, char **basename)
22.58 +{
22.59 + char *ext;
22.60 +
22.61 + /* Obtain the basename of the output prefix. */
22.62 +
22.63 + *basename = make_basename(filename);
22.64 +
22.65 + if (*basename == NULL)
22.66 + return 0;
22.67 +
22.68 + /* Truncate the basename to remove the extension. */
22.69 +
22.70 + ext = strrchr(*basename, '.');
22.71 +
22.72 + if (ext != NULL)
22.73 + *ext = '\0';
22.74 +
22.75 + /* Obtain the directory name from the output prefix. */
22.76 +
22.77 + if (conf.output_dir == NULL)
22.78 + *dirname = make_dirname(filename);
22.79 + else
22.80 + *dirname = conf.output_dir;
22.81 +
22.82 + if (*dirname == NULL)
22.83 + {
22.84 + free(*basename);
22.85 + return 0;
22.86 + }
22.87 +
22.88 + return 1;
22.89 +}
22.90 +
22.91 +/* Obtain a suitable filename from the parsed import details. */
22.92 +
22.93 +static struct interface *import_interface_file(const char *quoted_filename)
22.94 +{
22.95 + /* Allocate a string for the quoted filename minus quotes. */
22.96 +
22.97 + size_t length = strlen(quoted_filename) - 1;
22.98 + char filename[length];
22.99 +
22.100 + /* For full paths, allocate enough space for both the dirname and the
22.101 + filename. */
22.102 +
22.103 + char pathname[strlen(input_dirname) + 1 + length];
22.104 +
22.105 + /* Strip quotes from the filename token. */
22.106 +
22.107 + strncpy(filename, quoted_filename + 1, length - 1);
22.108 + filename[length - 1] = '\0';
22.109 +
22.110 + /* Introduce the same dirname as the original input file.
22.111 + NOTE: This should probably use a search path. */
22.112 +
22.113 + if (is_basename(filename))
22.114 + {
22.115 + sprintf(pathname, "%s/%s", input_dirname, filename);
22.116 + return import_file(pathname, 0);
22.117 + }
22.118 + else
22.119 + return import_file(filename, 0);
22.120 +}
22.121 +
22.122 +/* Resolve imports in the interface description. */
22.123 +
22.124 +static int resolve_imports(struct interface *iface)
22.125 +{
22.126 + struct import *imp;
22.127 +
22.128 + for (; iface != NULL; iface = iface->tail)
22.129 + {
22.130 + /* Traverse the imports list to resolve imports. */
22.131 +
22.132 + for (imp = iface->imports; imp != NULL; imp = imp->tail)
22.133 + {
22.134 + imp->iface = import_interface_file(imp->filename);
22.135 +
22.136 + if (imp->iface == NULL)
22.137 + return 0;
22.138 + }
22.139 + }
22.140 +
22.141 + return 1;
22.142 +}
22.143 +
22.144 +/* Populate an interface reference if the base is found. */
22.145 +
22.146 +static int populate_base(struct interface_ref *base, struct interface *iface)
22.147 +{
22.148 + if (!strcmp(iface->name, base->name))
22.149 + {
22.150 + base->iface = iface;
22.151 + return 1;
22.152 + }
22.153 + else
22.154 + return 0;
22.155 +}
22.156 +
22.157 +/* Find a base interface definition. */
22.158 +
22.159 +static int find_base_in_imports(struct interface_ref *base, struct import *imp)
22.160 +{
22.161 + struct interface *iface;
22.162 +
22.163 + for (; imp != NULL; imp = imp->tail)
22.164 + {
22.165 + for (iface = imp->iface; iface != NULL; iface = iface->tail)
22.166 + {
22.167 + if (populate_base(base, iface))
22.168 + return 1;
22.169 +
22.170 + /* Investigate imports related to an interface. */
22.171 +
22.172 + if (find_base_in_imports(base, iface->imports))
22.173 + return 1;
22.174 + }
22.175 + }
22.176 +
22.177 + return 0;
22.178 +}
22.179 +
22.180 +/* Find a base interface in the current file or in imports. */
22.181 +
22.182 +static int find_base(struct interface_ref *base, struct interface *iface)
22.183 +{
22.184 + struct interface *preceding;
22.185 +
22.186 + /* Search preceding interfaces in the same file. */
22.187 +
22.188 + for (preceding = iface->tail; preceding != NULL; preceding = preceding->tail)
22.189 + {
22.190 + if (populate_base(base, preceding))
22.191 + return 1;
22.192 + }
22.193 +
22.194 + /* Search imported files. */
22.195 +
22.196 + if (find_base_in_imports(base, iface->imports))
22.197 + return 1;
22.198 +
22.199 + fprintf(stderr, "Could not locate base interface %s used by interface %s.\n",
22.200 + base->name, iface->name);
22.201 + return 0;
22.202 +}
22.203 +
22.204 +/* Populate any base interfaces by traversing all interfaces and searching for
22.205 + the base interface definitions. */
22.206 +
22.207 +static int populate_bases(struct interface *iface)
22.208 +{
22.209 + struct interface_ref *base;
22.210 +
22.211 + /* Traverse all interfaces. */
22.212 +
22.213 + for (; iface != NULL; iface = iface->tail)
22.214 + {
22.215 + /* Check all bases. */
22.216 +
22.217 + for (base = iface->bases; base != NULL; base = base->tail)
22.218 + {
22.219 + if (!find_base(base, iface))
22.220 + return 0;
22.221 + }
22.222 + }
22.223 +
22.224 + return 1;
22.225 +}
22.226 +
22.227 +
22.228 +
22.229 +/* Return the last interface from the parsing of the given file, or NULL if
22.230 + parsing or importing failed. */
22.231 +
22.232 +struct interface *import_file(const char *filename, int top_level)
22.233 +{
22.234 + struct interface *result;
22.235 + FILE *fp;
22.236 + char *dirname, *basename;
22.237 +
22.238 + /* Obtain output location details for interfaces within a file. */
22.239 +
22.240 + if (!get_output_location(filename, &dirname, &basename))
22.241 + return NULL;
22.242 +
22.243 + /* Record the input dirname using the original input file. */
22.244 +
22.245 + if (input_dirname == NULL)
22.246 + {
22.247 + input_dirname = make_dirname(filename);
22.248 + if (input_dirname == NULL)
22.249 + return NULL;
22.250 + }
22.251 +
22.252 + fp = fopen(filename, "r");
22.253 +
22.254 + if (fp == NULL)
22.255 + {
22.256 + fprintf(stderr, "Could not open file: %s\n", filename);
22.257 + return NULL;
22.258 + }
22.259 +
22.260 + /* Reset any specialised parser state and set the prefix to annotate parsing
22.261 + products. */
22.262 +
22.263 + reset(dirname, basename);
22.264 +
22.265 + yyrestart(fp);
22.266 + yyparse();
22.267 + fclose(fp);
22.268 +
22.269 + /* Obtain the parsing products and process them. */
22.270 +
22.271 + result = last_interface;
22.272 +
22.273 + if (!resolve_imports(result))
22.274 + return NULL;
22.275 +
22.276 + if (!populate_bases(result))
22.277 + return NULL;
22.278 +
22.279 + /* Either report basenames of processed files... */
22.280 +
22.281 + if (conf.show_filenames)
22.282 + printf("%s\n", basename);
22.283 +
22.284 + /* Or write files where directed. */
22.285 +
22.286 + else
22.287 + if (top_level || conf.generate_all)
22.288 + write_files(result);
22.289 +
22.290 + return result;
22.291 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/imports.h Sat Dec 10 01:28:22 2022 +0100
23.3 @@ -0,0 +1,26 @@
23.4 +/*
23.5 + * File parsing and importing.
23.6 + *
23.7 + * Copyright (C) 2022 Paul Boddie <paul@boddie.org.uk>
23.8 + *
23.9 + * This program is free software; you can redistribute it and/or
23.10 + * modify it under the terms of the GNU General Public License as
23.11 + * published by the Free Software Foundation; either version 2 of
23.12 + * the License, or (at your option) any later version.
23.13 + *
23.14 + * This program is distributed in the hope that it will be useful,
23.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
23.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23.17 + * GNU General Public License for more details.
23.18 + *
23.19 + * You should have received a copy of the GNU General Public License
23.20 + * along with this program; if not, write to the Free Software
23.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
23.22 + * Boston, MA 02110-1301, USA
23.23 + */
23.24 +
23.25 +#pragma once
23.26 +
23.27 +#include "types.h"
23.28 +
23.29 +struct interface *import_file(const char *filename, int top_level);
24.1 --- a/interface.c Fri Dec 09 19:33:15 2022 +0100
24.2 +++ b/interface.c Sat Dec 10 01:28:22 2022 +0100
24.3 @@ -1,7 +1,7 @@
24.4 /*
24.5 * Generation of interface headers.
24.6 *
24.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
24.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
24.9 *
24.10 * This program is free software; you can redistribute it and/or
24.11 * modify it under the terms of the GNU General Public License as
24.12 @@ -20,6 +20,7 @@
24.13 */
24.14
24.15 #include <stdlib.h>
24.16 +#include <string.h>
24.17 #include "client.h"
24.18 #include "common.h"
24.19 #include "config.h"
24.20 @@ -32,6 +33,78 @@
24.21
24.22
24.23
24.24 +/* Emit compound interface includes. */
24.25 +
24.26 +static void write_compound_includes(FILE *fp, struct interface *iface)
24.27 +{
24.28 + struct interface_ref *base;
24.29 +
24.30 + for (base = iface->bases; base != NULL; base = base->tail)
24.31 + {
24.32 + /* Only output includes where the base resides in a different file. */
24.33 +
24.34 + if (strcmp(iface->output_basename, base->iface->output_basename))
24.35 + fprintf(fp, compound_interface_include, base->iface->output_basename);
24.36 + }
24.37 +}
24.38 +
24.39 +/* Write the reference type members. */
24.40 +
24.41 +static void write_reference_type_members(FILE *fp, struct interface_ref *base)
24.42 +{
24.43 + if (base == NULL)
24.44 + return;
24.45 +
24.46 + /* Reverse the list by processing subsequent members first. */
24.47 +
24.48 + write_reference_type_members(fp, base->tail);
24.49 +
24.50 + fprintf(fp, compound_ref_type_definition_member_c,
24.51 + base->name, base->name);
24.52 +}
24.53 +
24.54 +/* Generate a reference type for C language interfaces. */
24.55 +
24.56 +static void write_reference_type(FILE *fp, struct interface *iface)
24.57 +{
24.58 + struct interface *i;
24.59 +
24.60 + if (is_compound_interface(iface))
24.61 + {
24.62 + fprintf(fp, compound_ref_type_definition_prologue_c, L4_CAP_TYPE);
24.63 +
24.64 + write_reference_type_members(fp, iface->bases);
24.65 +
24.66 + fprintf(fp, compound_ref_type_definition_epilogue_c,
24.67 + iface->name);
24.68 + }
24.69 + else
24.70 + fprintf(fp, ref_type_definition_c, L4_CAP_TYPE, iface->name);
24.71 +}
24.72 +
24.73 +/* Augment compound interface class declarations. */
24.74 +
24.75 +static void write_compound_interface_bases_c(FILE *fp, struct interface *iface)
24.76 +{
24.77 + struct interface_ref *base;
24.78 +
24.79 + for (base = iface->bases; base != NULL; base = base->tail)
24.80 + fprintf(fp, interface_body_base_c, base->name, base->name);
24.81 +}
24.82 +
24.83 +/* Augment compound interface type declarations. */
24.84 +
24.85 +static void write_compound_interface_bases_cpp(FILE *fp, struct interface *iface)
24.86 +{
24.87 + struct interface_ref *base;
24.88 + int first;
24.89 +
24.90 + for (base = iface->bases, first = 1; base != NULL; base = base->tail, first = 0)
24.91 + fprintf(fp, interface_prologue_base_cpp, first ? " : " : ", ", base->name);
24.92 +}
24.93 +
24.94 +
24.95 +
24.96 /* Write the definition of an interface to the given file for use by client or
24.97 server components. Client headers employ such definitions as do server
24.98 interface headers, whereas server wrapper headers employ other descriptions
24.99 @@ -42,7 +115,7 @@
24.100 {
24.101 int cpp = (conf.language == CPP_LANGUAGE);
24.102 int client = (component == CLIENT_ROLE);
24.103 - int input_items = get_max_input_items(iface->signatures);
24.104 + int input_items = get_max_input_items(iface);
24.105 char *class_name = get_interface_class_name(iface, component);
24.106 char *name = iface->name;
24.107
24.108 @@ -50,6 +123,7 @@
24.109
24.110 write_includes_separator(iface->includes, fp);
24.111 write_includes(iface->includes, fp);
24.112 + write_compound_includes(fp, iface);
24.113
24.114 /* Generate interface abstractions. */
24.115
24.116 @@ -58,7 +132,7 @@
24.117 /* Define an object reference type for C. */
24.118
24.119 if (!client)
24.120 - fprintf(fp, ref_type_definition_c, L4_CAP_TYPE, name);
24.121 + write_reference_type(fp, iface);
24.122
24.123 /* Define C client signatures representing the client functions. */
24.124
24.125 @@ -87,10 +161,22 @@
24.126 else
24.127 fputs(interface_prologue_c, fp);
24.128
24.129 + /* Augment the interface declaration with base interfaces for compound
24.130 + interfaces. */
24.131 +
24.132 + if (!client && cpp && is_compound_interface(iface))
24.133 + write_compound_interface_bases_cpp(fp, iface);
24.134 +
24.135 /* Start the class or type body. */
24.136
24.137 fputs(interface_body_begin, fp);
24.138
24.139 + /* Augment the interface declaration with base interfaces for compound
24.140 + interfaces. */
24.141 +
24.142 + if (!client && !cpp && is_compound_interface(iface))
24.143 + write_compound_interface_bases_c(fp, iface);
24.144 +
24.145 /* Define any state and initialisation details of a class. */
24.146
24.147 if (cpp)
24.148 @@ -98,7 +184,8 @@
24.149 if (client)
24.150 fprintf(fp, client_interface_endpoint_declaration_cpp, L4_CAP_TYPE);
24.151
24.152 - fputs(interface_signatures_prologue_cpp, fp);
24.153 + if (iface->signatures != NULL)
24.154 + fputs(interface_signatures_prologue_cpp, fp);
24.155
24.156 /* Define a constructor. */
24.157
24.158 @@ -137,7 +224,7 @@
24.159 /* Emit opcodes and message access structures with the generic server
24.160 interface, these being common to both client and server. */
24.161
24.162 - if (!client)
24.163 + if (!client && (iface->signatures != NULL))
24.164 {
24.165 write_opcode_definition(iface, fp);
24.166 write_structures(iface->signatures, fp, iface);
25.1 --- a/main.c Fri Dec 09 19:33:15 2022 +0100
25.2 +++ b/main.c Sat Dec 10 01:28:22 2022 +0100
25.3 @@ -1,7 +1,7 @@
25.4 /*
25.5 * Main program.
25.6 *
25.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
25.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
25.9 *
25.10 * This program is free software; you can redistribute it and/or
25.11 * modify it under the terms of the GNU General Public License as
25.12 @@ -26,70 +26,11 @@
25.13 #include <strings.h>
25.14 #include "common.h"
25.15 #include "config.h"
25.16 -#include "program.h"
25.17 +#include "imports.h"
25.18 +#include "summary.h"
25.19 #include "templates.h"
25.20 #include "version.h"
25.21
25.22 -/* Parser functions and settings. */
25.23 -
25.24 -extern void yyparse(void);
25.25 -extern void yyrestart(FILE *);
25.26 -extern int yydebug;
25.27 -
25.28 -/* Specialised parser functions. */
25.29 -
25.30 -extern void reset(void);
25.31 -
25.32 -
25.33 -
25.34 -/* Return a copy of the given string without any extension. */
25.35 -
25.36 -static char *make_prefix(const char *s)
25.37 -{
25.38 - char *copy = strdup(s);
25.39 - char *ext;
25.40 -
25.41 - if (copy == NULL)
25.42 - return NULL;
25.43 -
25.44 - ext = strrchr(copy, '.');
25.45 -
25.46 - if (ext != NULL)
25.47 - *ext = '\0';
25.48 -
25.49 - return copy;
25.50 -}
25.51 -
25.52 -static int get_compound_prefix_conflict(int argc, char *argv[])
25.53 -{
25.54 - char *arg, *prefix, *name;
25.55 - int index, result;
25.56 -
25.57 - for (index = optind; index < argc; index++)
25.58 - {
25.59 - arg = argv[index];
25.60 - prefix = make_prefix(arg);
25.61 - result = 0;
25.62 -
25.63 - if (prefix != NULL)
25.64 - {
25.65 - name = make_basename(prefix);
25.66 -
25.67 - if (name != NULL)
25.68 - {
25.69 - result = strcasecmp(name, conf.compound);
25.70 - free(name);
25.71 - }
25.72 -
25.73 - free(prefix);
25.74 - }
25.75 -
25.76 - if (!result)
25.77 - return index;
25.78 - }
25.79 -
25.80 - return 0;
25.81 -}
25.82
25.83
25.84 /* Option definitions. */
25.85 @@ -98,13 +39,13 @@
25.86 /* long opt following var pointer short opt */
25.87 {"all", no_argument, NULL, 'a' },
25.88 {"client", no_argument, NULL, 'c' },
25.89 - {"comp", required_argument, NULL, 'C' },
25.90 {"dir", required_argument, NULL, 'd' },
25.91 + {"files", no_argument, NULL, 'f' },
25.92 {"headers", no_argument, NULL, 'h' },
25.93 {"help", no_argument, NULL, '?' },
25.94 {"interfaces", no_argument, NULL, 'i' },
25.95 {"language", required_argument, NULL, 'l' },
25.96 - {"comp-name", required_argument, NULL, 'N' },
25.97 + {"recursive", no_argument, NULL, 'R' },
25.98 {"routines", no_argument, NULL, 'r' },
25.99 {"server", no_argument, NULL, 's' },
25.100 {"verbose", no_argument, NULL, 'v' },
25.101 @@ -117,19 +58,21 @@
25.102
25.103 int main(int argc, char *argv[])
25.104 {
25.105 - FILE *fp;
25.106 char *arg, *progname;
25.107 int option, index, selected_content = 0, selected_role = 0;
25.108 + struct interface *iface;
25.109
25.110 #if YYDEBUG == 1
25.111 yydebug = 0;
25.112 #endif
25.113
25.114 + /* The configuration structure is already initialised in config.c. */
25.115 +
25.116 /* Accept various options. */
25.117
25.118 while (1)
25.119 {
25.120 - option = getopt_long(argc, argv, "acC:d:hil:N:rsvV?", long_options, NULL);
25.121 + option = getopt_long(argc, argv, "acd:fhil:rRsvV?", long_options, NULL);
25.122 if (option == -1)
25.123 break;
25.124
25.125 @@ -149,19 +92,16 @@
25.126 selected_role = 1;
25.127 break;
25.128
25.129 - /* Select compound interface filename prefix and output. */
25.130 - case 'C':
25.131 - conf.compound = optarg;
25.132 - if (conf.compound_name == NULL)
25.133 - conf.compound_name = conf.compound;
25.134 - selected_role = 1;
25.135 - break;
25.136 -
25.137 /* Set output directory. */
25.138 case 'd':
25.139 conf.output_dir = optarg;
25.140 break;
25.141
25.142 + /* Only report processed file basenames. */
25.143 + case 'f':
25.144 + conf.show_filenames = 1;
25.145 + break;
25.146 +
25.147 /* Generate headers. */
25.148 case 'h':
25.149 conf.headers = 1;
25.150 @@ -187,20 +127,17 @@
25.151 }
25.152 break;
25.153
25.154 - /* Select compound interface name and output. */
25.155 - case 'N':
25.156 - conf.compound_name = optarg;
25.157 - if (conf.compound == NULL)
25.158 - conf.compound = conf.compound_name;
25.159 - selected_role = 1;
25.160 - break;
25.161 -
25.162 /* Generate routines (definitions). */
25.163 case 'r':
25.164 conf.routines = 1;
25.165 selected_content = 1;
25.166 break;
25.167
25.168 + /* Also generate files associated with base interfaces. */
25.169 + case 'R':
25.170 + conf.generate_all = 1;
25.171 + break;
25.172 +
25.173 /* Select server output. */
25.174 case 's':
25.175 conf.server = 1;
25.176 @@ -241,18 +178,6 @@
25.177 conf.client = 1; conf.server = 1;
25.178 }
25.179
25.180 - /* Check any compound interface prefix against named files. */
25.181 -
25.182 - if (conf.compound != NULL)
25.183 - {
25.184 - if ((index = get_compound_prefix_conflict(argc, argv)))
25.185 - {
25.186 - fprintf(stderr, "Compound interface prefix %s conflicts with filename %s.\n",
25.187 - conf.compound, argv[index]);
25.188 - return 1;
25.189 - }
25.190 - }
25.191 -
25.192 /* Produce an error without any input files. */
25.193
25.194 if (optind >= argc)
25.195 @@ -261,52 +186,27 @@
25.196 return 1;
25.197 }
25.198
25.199 - /* Begin generating any compound interface code. */
25.200 -
25.201 - if (!begin_compound_output())
25.202 - {
25.203 - end_compound_output();
25.204 - return 1;
25.205 - }
25.206 -
25.207 /* Process named files. */
25.208
25.209 for (index = optind; index < argc; index++)
25.210 {
25.211 arg = argv[index];
25.212
25.213 - /* Handle actual files. */
25.214 -
25.215 - conf.output_prefix = make_prefix(arg);
25.216 -
25.217 - if (conf.output_prefix != NULL)
25.218 - {
25.219 - fp = fopen(arg, "r");
25.220 + /* Import each file for processing. */
25.221
25.222 - if (fp != NULL)
25.223 - {
25.224 - yyrestart(fp);
25.225 - yyparse();
25.226 - fclose(fp);
25.227 -
25.228 - /* Reset any specialised parser state. */
25.229 + iface = import_file(arg, 1);
25.230
25.231 - reset();
25.232 - }
25.233 -
25.234 - free(conf.output_prefix);
25.235 + if (iface == NULL)
25.236 + {
25.237 + fprintf(stderr, "Could not process file: %s\n", arg);
25.238 + return 1;
25.239 + }
25.240
25.241 - if (fp == NULL)
25.242 - {
25.243 - fprintf(stderr, "Could not open file: %s\n", arg);
25.244 - return 1;
25.245 - }
25.246 - }
25.247 + /* Summarise interfaces if requested. */
25.248 +
25.249 + if (conf.verbose)
25.250 + show_interfaces(iface);
25.251 }
25.252
25.253 - /* End generating any compound interface code. */
25.254 -
25.255 - end_compound_output();
25.256 -
25.257 return 0;
25.258 }
26.1 --- a/mk/client_interface_c.mk Fri Dec 09 19:33:15 2022 +0100
26.2 +++ b/mk/client_interface_c.mk Sat Dec 10 01:28:22 2022 +0100
26.3 @@ -1,6 +1,6 @@
26.4 # C client interface generation rules.
26.5 #
26.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
26.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
26.8 #
26.9 # This program is free software; you can redistribute it and/or
26.10 # modify it under the terms of the GNU General Public License as
26.11 @@ -18,8 +18,9 @@
26.12 # Boston, MA 02110-1301, USA
26.13
26.14 define client_interface_c_template =
26.15 +$(1)_CLIENT = $(call interfaces_to_client_c_h,$(1))
26.16 $(1)_CLIENT_IDL = $(call interfaces_to_idl,$(1))
26.17 -$(1)_CLIENT = $(call interfaces_to_client_c_h,$(1))
26.18 +$(1)_CLIENT_C_ = $(IDL_BUILD_DIR)/__client_c__$(1)
26.19
26.20 # Reference interfaces if exported.
26.21
26.22 @@ -27,6 +28,16 @@
26.23 $(1)_CLIENT_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
26.24 endif
26.25
26.26 -$$($(1)_CLIENT): $$($(1)_CLIENT_IDL) $$($(1)_CLIENT_INC)
26.27 +# All generated files depend on a target file produced by a single invocation of
26.28 +# the idl command. Where any generated files are missing, the invocation is
26.29 +# performed again.
26.30 +
26.31 +$$(foreach FILENAME,$$($(1)_CLIENT),$$(if $$(wildcard $$(FILENAME)),,$$(shell rm -f $$($(1)_CLIENT_C_))))
26.32 +
26.33 +$$($(1)_CLIENT): $$($(1)_CLIENT_C_)
26.34 + @touch $$@
26.35 +
26.36 +$$($(1)_CLIENT_C_): $$($(1)_CLIENT_IDL) $$($(1)_CLIENT_INC) $(IDL_PROG)
26.37 $(IDL_PROG) -d $(IDL_BUILD_DIR) --client --headers --routines --language=c $$($(1)_CLIENT_IDL)
26.38 + @touch $$@
26.39 endef
27.1 --- a/mk/client_interface_cc.mk Fri Dec 09 19:33:15 2022 +0100
27.2 +++ b/mk/client_interface_cc.mk Sat Dec 10 01:28:22 2022 +0100
27.3 @@ -1,6 +1,6 @@
27.4 # C++ client interface generation rules.
27.5 #
27.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
27.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
27.8 #
27.9 # This program is free software; you can redistribute it and/or
27.10 # modify it under the terms of the GNU General Public License as
27.11 @@ -18,8 +18,9 @@
27.12 # Boston, MA 02110-1301, USA
27.13
27.14 define client_interface_cc_template =
27.15 +$(1)_CLIENT = $(call interfaces_to_client_cc_h,$(1))
27.16 $(1)_CLIENT_IDL = $(call interfaces_to_idl,$(1))
27.17 -$(1)_CLIENT = $(call interfaces_to_client_cc_h,$(1))
27.18 +$(1)_CLIENT_CC_ = $(IDL_BUILD_DIR)/__client_cc__$(1)
27.19
27.20 # Reference interfaces if exported.
27.21
27.22 @@ -27,6 +28,16 @@
27.23 $(1)_CLIENT_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
27.24 endif
27.25
27.26 -$$($(1)_CLIENT): $$($(1)_CLIENT_IDL) $$($(1)_CLIENT_INC)
27.27 +# All generated files depend on a target file produced by a single invocation of
27.28 +# the idl command. Where any generated files are missing, the invocation is
27.29 +# performed again.
27.30 +
27.31 +$$(foreach FILENAME,$$($(1)_CLIENT),$$(if $$(wildcard $$(FILENAME)),,$$(shell rm -f $$($(1)_CLIENT_CC_))))
27.32 +
27.33 +$$($(1)_CLIENT): $$($(1)_CLIENT_CC_)
27.34 + @touch $$@
27.35 +
27.36 +$$($(1)_CLIENT_CC_): $$($(1)_CLIENT_IDL) $$($(1)_CLIENT_INC) $(IDL_PROG)
27.37 $(IDL_PROG) -d $(IDL_BUILD_DIR) --client --headers --routines --language=c++ $$($(1)_CLIENT_IDL)
27.38 + @touch $$@
27.39 endef
28.1 --- a/mk/comp_interface_c.mk Fri Dec 09 19:33:15 2022 +0100
28.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
28.3 @@ -1,28 +0,0 @@
28.4 -# C compound server interface generation rules.
28.5 -#
28.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
28.7 -#
28.8 -# This program is free software; you can redistribute it and/or
28.9 -# modify it under the terms of the GNU General Public License as
28.10 -# published by the Free Software Foundation; either version 2 of
28.11 -# the License, or (at your option) any later version.
28.12 -#
28.13 -# This program is distributed in the hope that it will be useful,
28.14 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
28.15 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.16 -# GNU General Public License for more details.
28.17 -#
28.18 -# You should have received a copy of the GNU General Public License
28.19 -# along with this program; if not, write to the Free Software
28.20 -# Foundation, Inc., 51 Franklin Street, Fifth Floor,
28.21 -# Boston, MA 02110-1301, USA
28.22 -
28.23 -define comp_interface_c_template =
28.24 -$(1)_SERVER_IDL = $(call interfaces_to_idl,$(3))
28.25 -$(1)_SERVER = $(call interfaces_to_server_c_h,$(1))
28.26 -$(1)_SERVER_INC = $(call export_includes, $(call interfaces_to_interfaces_h,$(1)))
28.27 -$(1)_SERVER_OPT = --comp=$(1) --comp-name=$(2)
28.28 -
28.29 -$$($(1)_SERVER): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC)
28.30 - $(IDL_PROG) -d $(IDL_BUILD_DIR) $$($(1)_SERVER_OPT) --headers --routines --language=c $$($(1)_SERVER_IDL)
28.31 -endef
29.1 --- a/mk/comp_interface_cc.mk Fri Dec 09 19:33:15 2022 +0100
29.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
29.3 @@ -1,28 +0,0 @@
29.4 -# C++ compound server interface generation rules.
29.5 -#
29.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
29.7 -#
29.8 -# This program is free software; you can redistribute it and/or
29.9 -# modify it under the terms of the GNU General Public License as
29.10 -# published by the Free Software Foundation; either version 2 of
29.11 -# the License, or (at your option) any later version.
29.12 -#
29.13 -# This program is distributed in the hope that it will be useful,
29.14 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
29.15 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.16 -# GNU General Public License for more details.
29.17 -#
29.18 -# You should have received a copy of the GNU General Public License
29.19 -# along with this program; if not, write to the Free Software
29.20 -# Foundation, Inc., 51 Franklin Street, Fifth Floor,
29.21 -# Boston, MA 02110-1301, USA
29.22 -
29.23 -define comp_interface_cc_template =
29.24 -$(1)_SERVER_IDL = $(call interfaces_to_idl,$(3))
29.25 -$(1)_SERVER = $(call interfaces_to_server_cc_h,$(1))
29.26 -$(1)_SERVER_INC = $(call export_includes, $(call interfaces_to_interfaces_h,$(1)))
29.27 -$(1)_SERVER_OPT = --comp=$(1) --comp-name=$(2)
29.28 -
29.29 -$$($(1)_SERVER): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC)
29.30 - $(IDL_PROG) -d $(IDL_BUILD_DIR) $$($(1)_SERVER_OPT) --headers --routines --language=c++ $$($(1)_SERVER_IDL)
29.31 -endef
30.1 --- a/mk/export_comp_interface_c.mk Fri Dec 09 19:33:15 2022 +0100
30.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
30.3 @@ -1,30 +0,0 @@
30.4 -# C compound server interface exporting rules.
30.5 -#
30.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
30.7 -#
30.8 -# This program is free software; you can redistribute it and/or
30.9 -# modify it under the terms of the GNU General Public License as
30.10 -# published by the Free Software Foundation; either version 2 of
30.11 -# the License, or (at your option) any later version.
30.12 -#
30.13 -# This program is distributed in the hope that it will be useful,
30.14 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
30.15 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30.16 -# GNU General Public License for more details.
30.17 -#
30.18 -# You should have received a copy of the GNU General Public License
30.19 -# along with this program; if not, write to the Free Software
30.20 -# Foundation, Inc., 51 Franklin Street, Fifth Floor,
30.21 -# Boston, MA 02110-1301, USA
30.22 -
30.23 -define export_comp_interface_c_template =
30.24 -ifdef IDL_EXPORT_DIR
30.25 -$(1)_INT_IDL = $(call interfaces_to_idl,$(3))
30.26 -$(1)_INT_INC = $(call export_includes, $(call interfaces_to_interfaces_h,$(1)))
30.27 -$(1)_INT_OPT = --comp=$(1) --comp-name=$(2)
30.28 -
30.29 -$$($(1)_INT_INC): $$($(1)_INT_IDL)
30.30 - -mkdir -p $(IDL_EXPORT_DIR)
30.31 - $(IDL_PROG) -d $(IDL_EXPORT_DIR) $$($(1)_INT_OPT) --interfaces --language=c $$($(1)_INT_IDL)
30.32 -endif
30.33 -endef
31.1 --- a/mk/export_comp_interface_cc.mk Fri Dec 09 19:33:15 2022 +0100
31.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
31.3 @@ -1,30 +0,0 @@
31.4 -# C++ compound server interface exporting rules.
31.5 -#
31.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
31.7 -#
31.8 -# This program is free software; you can redistribute it and/or
31.9 -# modify it under the terms of the GNU General Public License as
31.10 -# published by the Free Software Foundation; either version 2 of
31.11 -# the License, or (at your option) any later version.
31.12 -#
31.13 -# This program is distributed in the hope that it will be useful,
31.14 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
31.15 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31.16 -# GNU General Public License for more details.
31.17 -#
31.18 -# You should have received a copy of the GNU General Public License
31.19 -# along with this program; if not, write to the Free Software
31.20 -# Foundation, Inc., 51 Franklin Street, Fifth Floor,
31.21 -# Boston, MA 02110-1301, USA
31.22 -
31.23 -define export_comp_interface_cc_template =
31.24 -ifdef IDL_EXPORT_DIR
31.25 -$(1)_INT_IDL = $(call interfaces_to_idl,$(3))
31.26 -$(1)_INT_INC = $(call export_includes, $(call interfaces_to_interfaces_h,$(1)))
31.27 -$(1)_INT_OPT = --comp=$(1) --comp-name=$(2)
31.28 -
31.29 -$$($(1)_INT_INC): $$($(1)_INT_IDL)
31.30 - -mkdir -p $(IDL_EXPORT_DIR)
31.31 - $(IDL_PROG) -d $(IDL_EXPORT_DIR) $$($(1)_INT_OPT) --interfaces --language=c++ $$($(1)_INT_IDL)
31.32 -endif
31.33 -endef
32.1 --- a/mk/export_interface_c.mk Fri Dec 09 19:33:15 2022 +0100
32.2 +++ b/mk/export_interface_c.mk Sat Dec 10 01:28:22 2022 +0100
32.3 @@ -1,6 +1,6 @@
32.4 # C interface exporting rules.
32.5 #
32.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
32.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
32.8 #
32.9 # This program is free software; you can redistribute it and/or
32.10 # modify it under the terms of the GNU General Public License as
32.11 @@ -22,7 +22,7 @@
32.12 $(1)_INT_IDL = $(call interfaces_to_idl,$(1))
32.13 $(1)_INT_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
32.14
32.15 -$$($(1)_INT_INC): $$($(1)_INT_IDL)
32.16 +$$($(1)_INT_INC): $$($(1)_INT_IDL) $(IDL_PROG)
32.17 -mkdir -p $(IDL_EXPORT_DIR)
32.18 $(IDL_PROG) -d $(IDL_EXPORT_DIR) --interfaces --language=c $$($(1)_INT_IDL)
32.19 endif
33.1 --- a/mk/export_interface_cc.mk Fri Dec 09 19:33:15 2022 +0100
33.2 +++ b/mk/export_interface_cc.mk Sat Dec 10 01:28:22 2022 +0100
33.3 @@ -1,6 +1,6 @@
33.4 # C++ interface exporting rules.
33.5 #
33.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
33.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
33.8 #
33.9 # This program is free software; you can redistribute it and/or
33.10 # modify it under the terms of the GNU General Public License as
33.11 @@ -22,7 +22,7 @@
33.12 $(1)_INT_IDL = $(call interfaces_to_idl,$(1))
33.13 $(1)_INT_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
33.14
33.15 -$$($(1)_INT_INC): $$($(1)_INT_IDL)
33.16 +$$($(1)_INT_INC): $$($(1)_INT_IDL) $(IDL_PROG)
33.17 -mkdir -p $(IDL_EXPORT_DIR)
33.18 $(IDL_PROG) -d $(IDL_EXPORT_DIR) --interfaces --language=c++ $$($(1)_INT_IDL)
33.19 endif
34.1 --- a/mk/idl.mk Fri Dec 09 19:33:15 2022 +0100
34.2 +++ b/mk/idl.mk Sat Dec 10 01:28:22 2022 +0100
34.3 @@ -1,6 +1,6 @@
34.4 # Common definitions and functions.
34.5 #
34.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
34.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
34.8 #
34.9 # This program is free software; you can redistribute it and/or
34.10 # modify it under the terms of the GNU General Public License as
34.11 @@ -19,7 +19,7 @@
34.12
34.13 IDL_PROG = $(L4DIR)/idl4re/idl
34.14
34.15 -# Functions to generate filenames.
34.16 +# Functions to generate filenames for individual interfaces.
34.17
34.18 export_includes = $(patsubst %,$(IDL_EXPORT_DIR)/%,$(1))
34.19
34.20 @@ -39,20 +39,6 @@
34.21 $(patsubst %,%_client.cc,$(1)) \
34.22 $(patsubst %,%_client.h,$(1)) \
34.23
34.24 -interfaces_to_server_c = \
34.25 - $(patsubst %,%_server.c,$(1)) \
34.26 -
34.27 -interfaces_to_server_c_h = \
34.28 - $(patsubst %,%_server.c,$(1)) \
34.29 - $(patsubst %,%_server.h,$(1)) \
34.30 -
34.31 -interfaces_to_server_cc = \
34.32 - $(patsubst %,%_server.cc,$(1)) \
34.33 -
34.34 -interfaces_to_server_cc_h = \
34.35 - $(patsubst %,%_server.cc,$(1)) \
34.36 - $(patsubst %,%_server.h,$(1)) \
34.37 -
34.38 interfaces_to_interface_h = \
34.39 $(patsubst %,%_interface.h,$(1)) \
34.40
34.41 @@ -60,11 +46,33 @@
34.42 $(patsubst %,%_interface.h,$(1)) \
34.43 $(patsubst %,%_interfaces.h,$(1)) \
34.44
34.45 -# For each interface <name>, obtain a variable of the form <name>_INTERFACES,
34.46 -# accumulating words from each variable. The resulting list is sorted and
34.47 -# without duplicate words.
34.48 +_interfaces_to_server_c = \
34.49 + $(patsubst %,%_server.c,$(1)) \
34.50 +
34.51 +_interfaces_to_server_c_h = \
34.52 + $(patsubst %,%_server.c,$(1)) \
34.53 + $(patsubst %,%_server.h,$(1)) \
34.54 +
34.55 +_interfaces_to_server_cc = \
34.56 + $(patsubst %,%_server.cc,$(1)) \
34.57 +
34.58 +_interfaces_to_server_cc_h = \
34.59 + $(patsubst %,%_server.cc,$(1)) \
34.60 + $(patsubst %,%_server.h,$(1)) \
34.61
34.62 -common_interfaces = $(sort $(foreach INTERFACE,$(1),$(value $(INTERFACE)_INTERFACES)))
34.63 +# For each interface file basename, obtain basenames of all other files needed
34.64 +# to complete the interfaces in the given file. The resulting list is sorted and
34.65 +# without duplicate words. This function is used to support the indication of
34.66 +# compound interfaces, providing the constituent interfaces.
34.67 +
34.68 +needed_interfaces = $(sort $(foreach BASENAME,$(call interfaces_to_idl,$(1)),$(shell $(IDL_PROG) -f $(BASENAME))))
34.69 +
34.70 +# File generation for all needed interfaces.
34.71 +
34.72 +interfaces_to_server_c = $(call _interfaces_to_server_c,$(call needed_interfaces,$(1)))
34.73 +interfaces_to_server_c_h = $(call _interfaces_to_server_c_h,$(call needed_interfaces,$(1)))
34.74 +interfaces_to_server_cc = $(call _interfaces_to_server_cc,$(call needed_interfaces,$(1)))
34.75 +interfaces_to_server_cc_h = $(call _interfaces_to_server_cc_h,$(call needed_interfaces,$(1)))
34.76
34.77 # Generation of exported interface header file locations.
34.78
35.1 --- a/mk/interface_rules.mk Fri Dec 09 19:33:15 2022 +0100
35.2 +++ b/mk/interface_rules.mk Sat Dec 10 01:28:22 2022 +0100
35.3 @@ -1,6 +1,6 @@
35.4 # C and C++ rule generation for interfaces.
35.5 #
35.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
35.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
35.8 #
35.9 # This program is free software; you can redistribute it and/or
35.10 # modify it under the terms of the GNU General Public License as
35.11 @@ -22,8 +22,6 @@
35.12
35.13 include $(IDL_MK_DIR)/export_interface_c.mk
35.14 include $(IDL_MK_DIR)/export_interface_cc.mk
35.15 -include $(IDL_MK_DIR)/export_comp_interface_c.mk
35.16 -include $(IDL_MK_DIR)/export_comp_interface_cc.mk
35.17
35.18 # Generate routines.
35.19
35.20 @@ -31,12 +29,10 @@
35.21 include $(IDL_MK_DIR)/client_interface_cc.mk
35.22 include $(IDL_MK_DIR)/server_interface_c.mk
35.23 include $(IDL_MK_DIR)/server_interface_cc.mk
35.24 -include $(IDL_MK_DIR)/comp_interface_c.mk
35.25 -include $(IDL_MK_DIR)/comp_interface_cc.mk
35.26
35.27 # Extra rules to generate files from the interface descriptions.
35.28
35.29 -# Generate an interface rule for each individual client interface.
35.30 +# Generate an interface rule for each client interface.
35.31
35.32 $(foreach INTERFACE,$(CLIENT_INTERFACES_C),\
35.33 $(eval $(call client_interface_c_template,$(INTERFACE))))
35.34 @@ -44,35 +40,18 @@
35.35 $(foreach INTERFACE,$(CLIENT_INTERFACES_CC),\
35.36 $(eval $(call client_interface_cc_template,$(INTERFACE))))
35.37
35.38 -# Generate an interface rule for each individual server interface.
35.39 +# Generate an interface rule for each server interface.
35.40
35.41 -$(foreach INTERFACE,$(SERVER_INTERFACES_C),\
35.42 +$(foreach INTERFACE,$(call needed_interfaces,$(SERVER_INTERFACES_C)),\
35.43 $(eval $(call server_interface_c_template,$(INTERFACE))))
35.44
35.45 -$(foreach INTERFACE,$(SERVER_INTERFACES_CC),\
35.46 +$(foreach INTERFACE,$(call needed_interfaces,$(SERVER_INTERFACES_CC)),\
35.47 $(eval $(call server_interface_cc_template,$(INTERFACE))))
35.48
35.49 -# Generate a compound interface rule for each compound interface, using details
35.50 -# provided in the <interface>_NAME and <interface>_INTERFACES definitions.
35.51 -
35.52 -$(foreach INTERFACE,$(COMP_INTERFACES_C),\
35.53 -$(eval $(call comp_interface_c_template,$(INTERFACE),$(value $(INTERFACE)_NAME),$(value $(INTERFACE)_INTERFACES))))
35.54 +# Generate rules for exported interfaces.
35.55
35.56 -$(foreach INTERFACE,$(COMP_INTERFACES_CC),\
35.57 -$(eval $(call comp_interface_cc_template,$(INTERFACE),$(value $(INTERFACE)_NAME),$(value $(INTERFACE)_INTERFACES))))
35.58 -
35.59 -# Generate rules for exported individual interfaces.
35.60 -
35.61 -$(foreach INTERFACE,$(sort $(CLIENT_INTERFACES_C) $(SERVER_INTERFACES_C)),\
35.62 +$(foreach INTERFACE,$(call needed_interfaces,$(CLIENT_INTERFACES_C) $(SERVER_INTERFACES_C)),\
35.63 $(eval $(call export_interface_c_template,$(INTERFACE))))
35.64
35.65 -$(foreach INTERFACE,$(sort $(CLIENT_INTERFACES_CC) $(SERVER_INTERFACES_CC)),\
35.66 +$(foreach INTERFACE,$(call needed_interfaces,$(CLIENT_INTERFACES_CC) $(SERVER_INTERFACES_CC)),\
35.67 $(eval $(call export_interface_cc_template,$(INTERFACE))))
35.68 -
35.69 -# Generate rules for exported compound interfaces.
35.70 -
35.71 -$(foreach INTERFACE,$(COMP_INTERFACES_C),\
35.72 -$(eval $(call export_comp_interface_c_template,$(INTERFACE),$(value $(INTERFACE)_NAME),$(value $(INTERFACE)_INTERFACES))))
35.73 -
35.74 -$(foreach INTERFACE,$(COMP_INTERFACES_CC),\
35.75 -$(eval $(call export_comp_interface_cc_template,$(INTERFACE),$(value $(INTERFACE)_NAME),$(value $(INTERFACE)_INTERFACES))))
36.1 --- a/mk/server_interface_c.mk Fri Dec 09 19:33:15 2022 +0100
36.2 +++ b/mk/server_interface_c.mk Sat Dec 10 01:28:22 2022 +0100
36.3 @@ -1,6 +1,6 @@
36.4 # C server interface generation rules.
36.5 #
36.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
36.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
36.8 #
36.9 # This program is free software; you can redistribute it and/or
36.10 # modify it under the terms of the GNU General Public License as
36.11 @@ -18,8 +18,9 @@
36.12 # Boston, MA 02110-1301, USA
36.13
36.14 define server_interface_c_template =
36.15 -$(1)_SERVER = $(call interfaces_to_server_c_h,$(1))
36.16 +$(1)_SERVER = $(call _interfaces_to_server_c_h,$(1))
36.17 $(1)_SERVER_IDL = $(call interfaces_to_idl,$(1))
36.18 +$(1)_SERVER_C_ = $(IDL_BUILD_DIR)/__server_c__$(1)
36.19
36.20 # Reference interfaces if exported.
36.21
36.22 @@ -27,6 +28,16 @@
36.23 $(1)_SERVER_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
36.24 endif
36.25
36.26 -$$($(1)_SERVER): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC)
36.27 +# All generated files depend on a target file produced by a single invocation of
36.28 +# the idl command. Where any generated files are missing, the invocation is
36.29 +# performed again.
36.30 +
36.31 +$$(foreach FILENAME,$$($(1)_SERVER),$$(if $$(wildcard $$(FILENAME)),,$$(shell rm -f $$($(1)_SERVER_C_))))
36.32 +
36.33 +$$($(1)_SERVER): $$($(1)_SERVER_C_)
36.34 + @touch $$@
36.35 +
36.36 +$$($(1)_SERVER_C_): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC) $(IDL_PROG)
36.37 $(IDL_PROG) -d $(IDL_BUILD_DIR) --server --headers --routines --language=c $$($(1)_SERVER_IDL)
36.38 + @touch $$@
36.39 endef
37.1 --- a/mk/server_interface_cc.mk Fri Dec 09 19:33:15 2022 +0100
37.2 +++ b/mk/server_interface_cc.mk Sat Dec 10 01:28:22 2022 +0100
37.3 @@ -1,6 +1,6 @@
37.4 # C++ server interface generation rules.
37.5 #
37.6 -# Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
37.7 +# Copyright (C) 2020, 2022 Paul Boddie <paul@boddie.org.uk>
37.8 #
37.9 # This program is free software; you can redistribute it and/or
37.10 # modify it under the terms of the GNU General Public License as
37.11 @@ -18,8 +18,9 @@
37.12 # Boston, MA 02110-1301, USA
37.13
37.14 define server_interface_cc_template =
37.15 -$(1)_SERVER = $(call interfaces_to_server_cc_h,$(1))
37.16 +$(1)_SERVER = $(call _interfaces_to_server_cc_h,$(1))
37.17 $(1)_SERVER_IDL = $(call interfaces_to_idl,$(1))
37.18 +$(1)_SERVER_CC_ = $(IDL_BUILD_DIR)/__server_cc__$(1)
37.19
37.20 # Reference interfaces if exported.
37.21
37.22 @@ -27,6 +28,16 @@
37.23 $(1)_SERVER_INC = $(call export_includes,$(call interfaces_to_interface_h,$(1)))
37.24 endif
37.25
37.26 -$$($(1)_SERVER): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC)
37.27 +# All generated files depend on a target file produced by a single invocation of
37.28 +# the idl command. Where any generated files are missing, the invocation is
37.29 +# performed again.
37.30 +
37.31 +$$(foreach FILENAME,$$($(1)_SERVER),$$(if $$(wildcard $$(FILENAME)),,$$(shell rm -f $$($(1)_SERVER_CC_))))
37.32 +
37.33 +$$($(1)_SERVER): $$($(1)_SERVER_CC_)
37.34 + @touch $$@
37.35 +
37.36 +$$($(1)_SERVER_CC_): $$($(1)_SERVER_IDL) $$($(1)_SERVER_INC) $(IDL_PROG)
37.37 $(IDL_PROG) -d $(IDL_BUILD_DIR) --server --headers --routines --language=c++ $$($(1)_SERVER_IDL)
37.38 + @touch $$@
37.39 endef
38.1 --- a/parser.h Fri Dec 09 19:33:15 2022 +0100
38.2 +++ b/parser.h Sat Dec 10 01:28:22 2022 +0100
38.3 @@ -1,7 +1,7 @@
38.4 /*
38.5 * Parser definitions.
38.6 *
38.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
38.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
38.9 *
38.10 * This program is free software; you can redistribute it and/or
38.11 * modify it under the terms of the GNU General Public License as
38.12 @@ -31,8 +31,10 @@
38.13
38.14 #define copy_attribute(in) (struct attribute *) copy(&in);
38.15 #define copy_identifier(in) (struct identifier *) copy(&in);
38.16 +#define copy_import(in) (struct import *) copy(&in);
38.17 #define copy_include(in) (struct include *) copy(&in);
38.18 #define copy_interface(in) (struct interface *) copy(&in);
38.19 +#define copy_interface_ref(in) (struct interface_ref *) copy(&in);
38.20 #define copy_parameter(in) (struct parameter *) copy(&in);
38.21 #define copy_signature(in) (struct signature *) copy(&in);
38.22
39.1 --- a/pkg/idl4re-examples/calc++/Makefile Fri Dec 09 19:33:15 2022 +0100
39.2 +++ b/pkg/idl4re-examples/calc++/Makefile Sat Dec 10 01:28:22 2022 +0100
39.3 @@ -13,15 +13,10 @@
39.4
39.5 include $(IDL_MK_DIR)/idl.mk
39.6
39.7 -calc_counter_NAME = CalcCounter
39.8 -calc_counter_INTERFACES = calc counter
39.9 -
39.10 -COMP_INTERFACES_CC = calc_counter
39.11 -
39.12 -# Individual interfaces.
39.13 +# Required interfaces.
39.14
39.15 CLIENT_INTERFACES_CC = calc counter
39.16 -SERVER_INTERFACES_CC = calc counter
39.17 +SERVER_INTERFACES_CC = calc counter calc_counter
39.18
39.19 # Generated and plain source files.
39.20
39.21 @@ -29,9 +24,7 @@
39.22 SERVER_INTERFACES_SRC_CC_calc_server++ = $(call interfaces_to_server_cc,calc)
39.23 CLIENT_INTERFACES_SRC_CC_calc_counter_client++ = $(call interfaces_to_client_cc,calc counter)
39.24
39.25 -SERVER_INTERFACES_SRC_CC_calc_counter_server++ = \
39.26 - $(call interfaces_to_server_cc,calc counter) \
39.27 - $(call interfaces_to_server_cc,calc_counter)
39.28 +SERVER_INTERFACES_SRC_CC_calc_counter_server++ = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC))
39.29
39.30 PLAIN_SRC_CC_calc_client++ = client.cc calc_local.cc
39.31 PLAIN_SRC_CC_calc_server++ = server.cc
40.1 --- a/pkg/idl4re-examples/calc/Makefile Fri Dec 09 19:33:15 2022 +0100
40.2 +++ b/pkg/idl4re-examples/calc/Makefile Sat Dec 10 01:28:22 2022 +0100
40.3 @@ -13,15 +13,10 @@
40.4
40.5 include $(IDL_MK_DIR)/idl.mk
40.6
40.7 -calc_counter_NAME = CalcCounter
40.8 -calc_counter_INTERFACES = calc counter
40.9 -
40.10 -COMP_INTERFACES_C = calc_counter
40.11 -
40.12 -# Individual interfaces.
40.13 +# Required interfaces.
40.14
40.15 CLIENT_INTERFACES_C = calc counter
40.16 -SERVER_INTERFACES_C = calc counter
40.17 +SERVER_INTERFACES_C = calc counter calc_counter
40.18
40.19 # Generated and plain source files.
40.20
40.21 @@ -29,9 +24,7 @@
40.22 CLIENT_INTERFACES_SRC_C_calc_counter_client = $(call interfaces_to_client_c,calc counter)
40.23 SERVER_INTERFACES_SRC_C_calc_server = $(call interfaces_to_server_c,calc)
40.24
40.25 -SERVER_INTERFACES_SRC_C_calc_counter_server = \
40.26 - $(call interfaces_to_server_c,calc counter) \
40.27 - $(call interfaces_to_server_c,calc_counter)
40.28 +SERVER_INTERFACES_SRC_C_calc_counter_server = $(call interfaces_to_server_c,$(SERVER_INTERFACES_C))
40.29
40.30 PLAIN_SRC_C_calc_client = client.c calc_local.c
40.31 PLAIN_SRC_C_calc_server = server.c
41.1 --- a/pkg/idl4re-examples/calc/server_compound.c Fri Dec 09 19:33:15 2022 +0100
41.2 +++ b/pkg/idl4re-examples/calc/server_compound.c Sat Dec 10 01:28:22 2022 +0100
41.3 @@ -112,7 +112,7 @@
41.4 {
41.5 /* Reference to state information and an encapsulation. */
41.6
41.7 - ref_CalcCounter ref = {.ptr=&counter};
41.8 + ref_CalcCounter ref = {.ptr=0, .as_Counter={.ptr=&counter}};
41.9 CalcCounter obj = {.ref=ref, .iface=&server_iface_CalcCounter};
41.10
41.11 /* Wait for messages, dispatching to the handler. */
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/pkg/idl4re-examples/idl/calc_counter.idl Sat Dec 10 01:28:22 2022 +0100
42.3 @@ -0,0 +1,4 @@
42.4 +import "calc.idl";
42.5 +import "counter.idl";
42.6 +
42.7 +interface CalcCounter composes Calc, Counter;
43.1 --- a/program.c Fri Dec 09 19:33:15 2022 +0100
43.2 +++ b/program.c Sat Dec 10 01:28:22 2022 +0100
43.3 @@ -30,330 +30,39 @@
43.4 #include "message.h"
43.5 #include "program.h"
43.6 #include "server.h"
43.7 -#include "summary.h"
43.8 #include "templates.h"
43.9
43.10
43.11
43.12 -/* Current filename details. */
43.13 -
43.14 -char *output_basename = NULL, *output_dirname = NULL;
43.15 -
43.16 /* Client, server and common files. */
43.17
43.18 FILE *client_fp = NULL, *client_header_fp = NULL,
43.19 *server_fp = NULL, *server_header_fp = NULL,
43.20 *interface_fp = NULL;
43.21
43.22 -/* Compound interface and dispatcher files. */
43.23 -
43.24 -FILE *compound_dispatch_fp = NULL, *compound_dispatch_header_fp = NULL,
43.25 - *compound_interface_fp = NULL, *compound_interfaces_fp = NULL,
43.26 - *compound_interface_type_fp = NULL;
43.27 -
43.28 -/* Processed interfaces. */
43.29 -
43.30 -int processed_interfaces;
43.31 -
43.32 -/* Maximum number of input items expected by an interface. */
43.33 -
43.34 -int max_input_items = 0;
43.35 -
43.36 -
43.37 -
43.38 -/* Return the first interface name as the output prefix. */
43.39 -
43.40 -static char *get_output_prefix(struct interface *i)
43.41 -{
43.42 - if (conf.output_prefix != NULL)
43.43 - return conf.output_prefix;
43.44 -
43.45 - if (i == NULL)
43.46 - return NULL;
43.47 -
43.48 - for (; i->tail != NULL; i = i->tail);
43.49 - return i->name;
43.50 -}
43.51 -
43.52 -/* Obtain the basename and directory name of generated output. */
43.53 -
43.54 -static int set_output_location(struct interface *iface)
43.55 -{
43.56 - /* Obtain a prefix for the output files. */
43.57 -
43.58 - conf.output_prefix = get_output_prefix(iface);
43.59 -
43.60 - if (conf.output_prefix == NULL)
43.61 - return 0;
43.62 -
43.63 - /* Obtain the basename of the output prefix. */
43.64 -
43.65 - output_basename = make_basename(conf.output_prefix);
43.66 -
43.67 - if (output_basename == NULL)
43.68 - return 0;
43.69 -
43.70 - /* Obtain the directory name from the output prefix. */
43.71 -
43.72 - if (conf.output_dir == NULL)
43.73 - output_dirname = make_dirname(conf.output_prefix);
43.74 - else
43.75 - output_dirname = conf.output_dir;
43.76 -
43.77 - if (output_dirname == NULL)
43.78 - {
43.79 - free(output_basename);
43.80 - return 0;
43.81 - }
43.82 -
43.83 - return 1;
43.84 -}
43.85 -
43.86
43.87
43.88 -/* Generate compound code output, if requested. */
43.89 -
43.90 -int begin_compound_output(void)
43.91 -{
43.92 - char *compound_dirname = conf.output_dir != NULL ? conf.output_dir : ".";
43.93 - char *s;
43.94 -
43.95 - if (conf.compound == NULL)
43.96 - return 1;
43.97 -
43.98 - processed_interfaces = 0;
43.99 -
43.100 - if (conf.headers)
43.101 - {
43.102 - compound_dispatch_header_fp = get_output_file(server_header_filename,
43.103 - compound_dirname, conf.compound);
43.104 - if (compound_dispatch_header_fp == NULL)
43.105 - return 0;
43.106 - }
43.107 -
43.108 - if (conf.interfaces)
43.109 - {
43.110 - compound_interface_fp = get_output_file(interface_filename,
43.111 - compound_dirname, conf.compound);
43.112 - if (compound_interface_fp == NULL)
43.113 - return 0;
43.114 -
43.115 - compound_interface_type_fp = get_output_file(compound_interface_type_filename,
43.116 - compound_dirname, conf.compound);
43.117 - if (compound_interface_type_fp == NULL)
43.118 - return 0;
43.119 -
43.120 - compound_interfaces_fp = get_output_file(compound_interfaces_filename,
43.121 - compound_dirname, conf.compound);
43.122 - if (compound_interfaces_fp == NULL)
43.123 - return 0;
43.124 - }
43.125 -
43.126 - if (conf.routines)
43.127 - {
43.128 - s = (conf.language == CPP_LANGUAGE) ? server_filename_cpp
43.129 - : server_filename_c;
43.130 - compound_dispatch_fp = get_output_file(s, compound_dirname, conf.compound);
43.131 - if (compound_dispatch_fp == NULL)
43.132 - return 0;
43.133 - }
43.134 -
43.135 - /* Emit prologues. */
43.136 +/* Generate functions corresponding to the signatures. */
43.137
43.138 - if (compound_dispatch_fp != NULL)
43.139 - {
43.140 - fprintf(compound_dispatch_fp, compound_dispatch_prologue, conf.compound);
43.141 -
43.142 - /* Write the handle function and dispatch function prologue. */
43.143 -
43.144 - write_handler_signature(conf.compound_name, DEFINITION_ROLE,
43.145 - compound_dispatch_fp);
43.146 - fprintf(compound_dispatch_fp, handle_function, conf.compound_name);
43.147 - fputs(END_FUNCTION, compound_dispatch_fp);
43.148 -
43.149 - write_dispatcher_signature(conf.compound_name, DEFINITION_ROLE,
43.150 - compound_dispatch_fp);
43.151 - fputs(compound_dispatch_function_prologue, compound_dispatch_fp);
43.152 - }
43.153 -
43.154 - if (compound_dispatch_header_fp != NULL)
43.155 - {
43.156 - fprintf(compound_dispatch_header_fp, compound_dispatch_header_prologue,
43.157 - conf.compound);
43.158 -
43.159 - /* Write the handler and dispatch signatures. */
43.160 +static void write_functions(struct signature *sig, FILE *fp,
43.161 + struct interface *iface,
43.162 + void (*write_function)(struct signature *, FILE *, struct interface *))
43.163 +{
43.164 + if (sig == NULL)
43.165 + return;
43.166
43.167 - write_handler_signature(conf.compound_name, DECLARATION_ROLE,
43.168 - compound_dispatch_header_fp);
43.169 -
43.170 - write_dispatcher_signature(conf.compound_name, DECLARATION_ROLE,
43.171 - compound_dispatch_header_fp);
43.172 - fputs("\n", compound_dispatch_header_fp);
43.173 - }
43.174 -
43.175 - if (compound_interface_fp != NULL)
43.176 - fprintf(compound_interface_fp,
43.177 - (conf.language == CPP_LANGUAGE) ? compound_interface_prologue_cpp
43.178 - : compound_interface_prologue_c,
43.179 - conf.compound, conf.compound_name);
43.180 -
43.181 - if (compound_interface_type_fp != NULL)
43.182 - {
43.183 - /* Begin reference type. */
43.184 -
43.185 - if (conf.language != CPP_LANGUAGE)
43.186 - fprintf(compound_interface_type_fp, compound_ref_type_definition_prologue_c,
43.187 - conf.compound, L4_CAP_TYPE);
43.188 - }
43.189 -
43.190 - if (compound_interfaces_fp != NULL)
43.191 - fputs(compound_interfaces_prologue, compound_interfaces_fp);
43.192 -
43.193 - return 1;
43.194 + write_function(sig, fp, iface);
43.195 + write_functions(sig->tail, fp, iface, write_function);
43.196 }
43.197
43.198 -void write_compound_output(struct interface *iface)
43.199 -{
43.200 - char *protocol, *ref;
43.201 - int input_items;
43.202 -
43.203 - if (compound_dispatch_fp != NULL)
43.204 - {
43.205 - protocol = get_protocol(iface->attributes);
43.206 -
43.207 - /* Populate a function dispatching to each interface-level function where
43.208 - the same protocol applies to an entire interface. */
43.209 -
43.210 - if (protocol != NULL)
43.211 - {
43.212 - ref = get_object_conversion(iface, 1);
43.213 -
43.214 - fprintf(compound_dispatch_fp, dispatch_function_interface_case,
43.215 - protocol, iface->name, ref);
43.216 -
43.217 - free(ref);
43.218 - }
43.219 -
43.220 - /* Or dispatch to each operation defined at this level. */
43.221 -
43.222 - else
43.223 - write_dispatcher_cases(iface->signatures, compound_dispatch_fp, iface, 1);
43.224 - }
43.225 -
43.226 - if (compound_dispatch_header_fp != NULL)
43.227 - {
43.228 - /* Compute the maximum number of items expected by each interface. */
43.229 -
43.230 - input_items = get_max_input_items(iface->signatures);
43.231 -
43.232 - if (input_items > max_input_items)
43.233 - max_input_items = input_items;
43.234 - }
43.235 -
43.236 - /* Add this interface to the compound interface. */
43.237 -
43.238 - if (compound_interface_fp != NULL)
43.239 - write_compound_interface(iface);
43.240 -
43.241 - /* Add this interface's header to the compound interface includes. */
43.242 -
43.243 - if (compound_interfaces_fp != NULL)
43.244 - write_include(output_basename, "_interface.h", compound_interfaces_fp);
43.245 -
43.246 - processed_interfaces++;
43.247 -}
43.248 -
43.249 -/* Generate includes for the server and common declarations from each input
43.250 - file. */
43.251 -
43.252 -void write_compound_dispatch_include(void)
43.253 -{
43.254 - if (compound_dispatch_header_fp != NULL)
43.255 - write_include(output_basename, "_server.h", compound_dispatch_header_fp);
43.256 -}
43.257 -
43.258 -/* Augment a compound interface class declaration. */
43.259 -
43.260 -void write_compound_interface(struct interface *iface)
43.261 -{
43.262 - char *sep;
43.263 +/* Write includes for base interfaces. */
43.264
43.265 - if (conf.language == CPP_LANGUAGE)
43.266 - {
43.267 - sep = processed_interfaces ? ", " : " ";
43.268 - fprintf(compound_interface_fp, "%spublic %s", sep, iface->name);
43.269 - }
43.270 - else
43.271 - fprintf(compound_interface_fp, " iface_%s *to_%s;\n", iface->name, iface->name);
43.272 -
43.273 - /* Include reference type. */
43.274 -
43.275 - if (conf.language != CPP_LANGUAGE)
43.276 - fprintf(compound_interface_type_fp, compound_ref_type_definition_member_c,
43.277 - iface->name, iface->name);
43.278 -}
43.279 -
43.280 -void end_compound_output(void)
43.281 +static void write_server_includes(struct interface *iface, FILE *fp)
43.282 {
43.283 - /* Close the files. */
43.284 -
43.285 - if (compound_dispatch_fp != NULL)
43.286 - {
43.287 - fputs(compound_dispatch_epilogue, compound_dispatch_fp);
43.288 - fputs(END_FUNCTION, compound_dispatch_fp);
43.289 -
43.290 - /* Emit default configuration instance definition. */
43.291 -
43.292 - fprintf(compound_dispatch_fp, server_config_instance,
43.293 - conf.compound_name, conf.compound_name, conf.compound_name);
43.294 -
43.295 - fclose(compound_dispatch_fp);
43.296 - }
43.297 -
43.298 - if (compound_dispatch_header_fp != NULL)
43.299 - {
43.300 - fprintf(compound_dispatch_header_fp, expected_items_definition,
43.301 - conf.compound_name, max_input_items);
43.302 + struct interface_ref *base;
43.303
43.304 - /* Emit default configuration instance declaration. */
43.305 -
43.306 - fprintf(compound_dispatch_header_fp, server_config_instance_declaration,
43.307 - conf.compound_name);
43.308 -
43.309 - fclose(compound_dispatch_header_fp);
43.310 - }
43.311 -
43.312 - if (compound_interface_fp != NULL)
43.313 - {
43.314 - if (conf.language == CPP_LANGUAGE)
43.315 - fputs(compound_interface_epilogue_cpp, compound_interface_fp);
43.316 - else
43.317 - {
43.318 - fprintf(compound_interface_fp, compound_interface_epilogue_c,
43.319 - conf.compound_name);
43.320 -
43.321 - /* Include object type. */
43.322 -
43.323 - fprintf(compound_interface_fp, object_type_definition_c,
43.324 - conf.compound_name, conf.compound_name, conf.compound_name);
43.325 - }
43.326 -
43.327 - fclose(compound_interface_fp);
43.328 - }
43.329 -
43.330 - if (compound_interface_type_fp != NULL)
43.331 - {
43.332 - /* Complete reference type. */
43.333 -
43.334 - if (conf.language != CPP_LANGUAGE)
43.335 - fprintf(compound_interface_type_fp, compound_ref_type_definition_epilogue_c,
43.336 - conf.compound_name);
43.337 -
43.338 - fclose(compound_interface_type_fp);
43.339 - }
43.340 -
43.341 - if (compound_interfaces_fp != NULL)
43.342 - fclose(compound_interfaces_fp);
43.343 + for (base = iface->bases; base != NULL; base = base->tail)
43.344 + write_include(base->iface->output_basename, "_server.h", fp);
43.345 }
43.346
43.347
43.348 @@ -364,29 +73,22 @@
43.349 {
43.350 char *filename;
43.351
43.352 - /* NOTE: Should exit with an error. */
43.353 -
43.354 - if (!set_output_location(iface))
43.355 - return;
43.356 -
43.357 - /* Include server details for a compound interface dispatch function. */
43.358 -
43.359 - write_compound_dispatch_include();
43.360 -
43.361 - /* Open the separate files and write the details of each interface. */
43.362 -
43.363 if (conf.headers)
43.364 {
43.365 if (conf.client)
43.366 {
43.367 - client_header_fp = get_output_file(client_header_filename, output_dirname, output_basename);
43.368 + client_header_fp = get_output_file(client_header_filename,
43.369 + iface->output_dirname,
43.370 + iface->output_basename);
43.371 if (client_header_fp == NULL)
43.372 goto finalisation;
43.373 }
43.374
43.375 if (conf.server)
43.376 {
43.377 - server_header_fp = get_output_file(server_header_filename, output_dirname, output_basename);
43.378 + server_header_fp = get_output_file(server_header_filename,
43.379 + iface->output_dirname,
43.380 + iface->output_basename);
43.381 if (server_header_fp == NULL)
43.382 goto finalisation;
43.383 }
43.384 @@ -394,7 +96,8 @@
43.385
43.386 if (conf.interfaces)
43.387 {
43.388 - interface_fp = get_output_file(interface_filename, output_dirname, output_basename);
43.389 + interface_fp = get_output_file(interface_filename, iface->output_dirname,
43.390 + iface->output_basename);
43.391 if (interface_fp == NULL)
43.392 goto finalisation;
43.393 }
43.394 @@ -403,16 +106,20 @@
43.395 {
43.396 if (conf.client)
43.397 {
43.398 - filename = (conf.language == CPP_LANGUAGE) ? client_filename_cpp : client_filename_c;
43.399 - client_fp = get_output_file(filename, output_dirname, output_basename);
43.400 + filename = (conf.language == CPP_LANGUAGE) ? client_filename_cpp
43.401 + : client_filename_c;
43.402 + client_fp = get_output_file(filename, iface->output_dirname,
43.403 + iface->output_basename);
43.404 if (client_fp == NULL)
43.405 goto finalisation;
43.406 }
43.407
43.408 if (conf.server)
43.409 {
43.410 - filename = (conf.language == CPP_LANGUAGE) ? server_filename_cpp : server_filename_c;
43.411 - server_fp = get_output_file(filename, output_dirname, output_basename);
43.412 + filename = (conf.language == CPP_LANGUAGE) ? server_filename_cpp
43.413 + : server_filename_c;
43.414 + server_fp = get_output_file(filename, iface->output_dirname,
43.415 + iface->output_basename);
43.416 if (server_fp == NULL)
43.417 goto finalisation;
43.418 }
43.419 @@ -421,13 +128,15 @@
43.420 /* Emit prologues. */
43.421
43.422 if (client_fp != NULL)
43.423 - fprintf(client_fp, client_prologue, output_basename, output_basename);
43.424 + fprintf(client_fp, client_prologue, iface->output_basename,
43.425 + iface->output_basename);
43.426
43.427 if (client_header_fp != NULL)
43.428 fputs(header_prologue, client_header_fp);
43.429
43.430 if (server_fp != NULL)
43.431 - fprintf(server_fp, server_prologue, output_basename, output_basename);
43.432 + fprintf(server_fp, server_prologue, iface->output_basename,
43.433 + iface->output_basename);
43.434
43.435 if (server_header_fp != NULL)
43.436 fputs(server_header_prologue, server_header_fp);
43.437 @@ -457,50 +166,44 @@
43.438
43.439 if (interface_fp != NULL)
43.440 fclose(interface_fp);
43.441 -
43.442 - /* Free the names. */
43.443 -
43.444 - if (conf.output_dir == NULL)
43.445 - free(output_dirname);
43.446 -
43.447 - free(output_basename);
43.448 }
43.449
43.450 -/* Generate the source file corresponding to the interface. */
43.451 +/* Generate source file content corresponding to each interface in turn. */
43.452
43.453 void write_interfaces(struct interface *iface)
43.454 {
43.455 - int input_items;
43.456 -
43.457 if (iface == NULL)
43.458 return;
43.459
43.460 - /* The list is reversed. */
43.461 + /* The list is reversed by recursing to subsequent interfaces and thus
43.462 + processing them first. */
43.463
43.464 write_interfaces(iface->tail);
43.465
43.466 - /* Write this particular interface after all referenced ones. */
43.467 -
43.468 - if (conf.verbose)
43.469 - show_interface(iface);
43.470 -
43.471 - /* Record details of this interface in the compound output. */
43.472 -
43.473 - write_compound_output(iface);
43.474 -
43.475 /* Emit function definitions. */
43.476
43.477 if (client_fp != NULL)
43.478 {
43.479 - write_functions(iface->signatures, client_fp, iface,
43.480 - write_client_function);
43.481 + /* Do not write client definitions for compound interfaces. */
43.482
43.483 - if (conf.language == C_LANGUAGE)
43.484 - write_client_interface(iface, client_fp);
43.485 + if (!is_compound_interface(iface))
43.486 + {
43.487 + write_functions(iface->signatures, client_fp, iface,
43.488 + write_client_function);
43.489 +
43.490 + if (conf.language == C_LANGUAGE)
43.491 + write_client_interface(iface, client_fp);
43.492 + }
43.493 }
43.494
43.495 if (server_fp != NULL)
43.496 {
43.497 + /* Write any includes for base interfaces. */
43.498 +
43.499 + write_server_includes(iface, server_fp);
43.500 +
43.501 + /* Write the dispatcher and handler functions. */
43.502 +
43.503 write_functions(iface->signatures, server_fp, iface,
43.504 write_server_function);
43.505
43.506 @@ -510,7 +213,7 @@
43.507 fprintf(server_fp, handle_function, iface->name);
43.508 fputs(END_FUNCTION, server_fp);
43.509
43.510 - write_dispatcher(iface->signatures, server_fp, iface);
43.511 + write_dispatcher(server_fp, iface);
43.512
43.513 /* Emit default configuration instance definition. */
43.514
43.515 @@ -523,18 +226,24 @@
43.516 if (client_header_fp != NULL)
43.517 {
43.518 /* Emit interface include to obtain the type employed by the client
43.519 - interface. */
43.520 + interface, doing this once per file. */
43.521 +
43.522 + if (iface->tail == NULL)
43.523 + write_include(iface->output_basename, "_interface.h", client_header_fp);
43.524
43.525 - write_include(output_basename, "_interface.h", client_header_fp);
43.526 + /* Do not write client definitions for compound interfaces. */
43.527
43.528 - write_interface_definition(iface, CLIENT_ROLE, client_header_fp);
43.529 + if (!is_compound_interface(iface))
43.530 + write_interface_definition(iface, CLIENT_ROLE, client_header_fp);
43.531 }
43.532
43.533 if (server_header_fp != NULL)
43.534 {
43.535 - /* Emit interface include to obtain the interface type. */
43.536 + /* Emit interface include to obtain the interface type, doing this once per
43.537 + file. */
43.538
43.539 - write_include(output_basename, "_interface.h", server_header_fp);
43.540 + if (iface->tail == NULL)
43.541 + write_include(iface->output_basename, "_interface.h", server_header_fp);
43.542
43.543 /* Emit signatures. */
43.544
43.545 @@ -556,15 +265,3 @@
43.546 if (interface_fp != NULL)
43.547 write_interface_definition(iface, SERVER_ROLE, interface_fp);
43.548 }
43.549 -
43.550 -/* Generate functions corresponding to the signatures. */
43.551 -
43.552 -void write_functions(struct signature *sig, FILE *fp, struct interface *iface,
43.553 - void (*write_function)(struct signature *, FILE *, struct interface *))
43.554 -{
43.555 - if (sig == NULL)
43.556 - return;
43.557 -
43.558 - write_function(sig, fp, iface);
43.559 - write_functions(sig->tail, fp, iface, write_function);
43.560 -}
44.1 --- a/program.h Fri Dec 09 19:33:15 2022 +0100
44.2 +++ b/program.h Sat Dec 10 01:28:22 2022 +0100
44.3 @@ -1,7 +1,7 @@
44.4 /*
44.5 - * Client code generation.
44.6 + * Code generation from interface descriptions.
44.7 *
44.8 - * Copyright (C) 2019, 2020 Paul Boddie <paul@boddie.org.uk>
44.9 + * Copyright (C) 2019, 2020, 2022 Paul Boddie <paul@boddie.org.uk>
44.10 *
44.11 * This program is free software; you can redistribute it and/or
44.12 * modify it under the terms of the GNU General Public License as
44.13 @@ -24,20 +24,7 @@
44.14 #include <stdio.h>
44.15 #include "types.h"
44.16
44.17 -/* Component-level processing. */
44.18 -
44.19 -int begin_compound_output(void);
44.20 -void write_compound_output(struct interface *iface);
44.21 -void write_compound_dispatch_include(void);
44.22 -void write_compound_interface(struct interface *iface);
44.23 -void end_compound_output(void);
44.24 -
44.25 /* Interface processing. */
44.26
44.27 void write_files(struct interface *iface);
44.28 void write_interfaces(struct interface *iface);
44.29 -
44.30 -/* Function details. */
44.31 -
44.32 -void write_functions(struct signature *sig, FILE *fp, struct interface *iface,
44.33 - void (*write_function)(struct signature *, FILE *, struct interface *));
45.1 --- a/server.c Fri Dec 09 19:33:15 2022 +0100
45.2 +++ b/server.c Sat Dec 10 01:28:22 2022 +0100
45.3 @@ -1,7 +1,7 @@
45.4 /*
45.5 * Server code generation.
45.6 *
45.7 - * Copyright (C) 2019, 2020 Paul Boddie <paul@boddie.org.uk>
45.8 + * Copyright (C) 2019, 2020, 2022 Paul Boddie <paul@boddie.org.uk>
45.9 *
45.10 * This program is free software; you can redistribute it and/or
45.11 * modify it under the terms of the GNU General Public License as
45.12 @@ -29,32 +29,6 @@
45.13
45.14
45.15
45.16 -/* Generate each component operation signature or "function prototype". */
45.17 -
45.18 -void write_server_interface_signature(struct signature *sig,
45.19 - enum signature_role role, FILE *fp,
45.20 - struct interface *iface)
45.21 -{
45.22 - write_interface_signature(sig, role, SERVER_ROLE,
45.23 - get_server_function_role(sig), fp, iface);
45.24 -}
45.25 -
45.26 -/* Generate signature declarations for each operation. */
45.27 -
45.28 -void write_server_signature(struct signature *sig, enum signature_role role,
45.29 - FILE *fp, struct interface *iface)
45.30 -{
45.31 - if (have_attribute(sig->attributes, "completion"))
45.32 - write_server_initiation_signature(sig, role, fp, iface);
45.33 - else
45.34 - write_server_wrapper_signature(sig, role, fp, iface);
45.35 -
45.36 - /* Write the appropriate completion signature even for use by conventional
45.37 - operations. */
45.38 -
45.39 - write_server_completion_signature(sig, role, fp, iface);
45.40 -}
45.41 -
45.42 /* Generic signature generation. */
45.43
45.44 static void _write_server_signature(struct signature *sig,
45.45 @@ -70,30 +44,31 @@
45.46 free(opname);
45.47 }
45.48
45.49 -/* Generate operation wrapper function details used by the server. */
45.50 +/* Generate a signature for the invocation of an operation. */
45.51
45.52 -void write_server_wrapper_signature(struct signature *sig, enum signature_role role,
45.53 +static void write_server_wrapper_signature(struct signature *sig, enum signature_role role,
45.54 FILE *fp, struct interface *iface)
45.55 {
45.56 _write_server_signature(sig, role, fp, iface, "wrap");
45.57 }
45.58
45.59 -void write_server_initiation_signature(struct signature *sig,
45.60 +/* Generate a signature for the initiation of an operation. */
45.61 +
45.62 +static void write_server_initiation_signature(struct signature *sig,
45.63 enum signature_role role,
45.64 FILE *fp, struct interface *iface)
45.65 {
45.66 _write_server_signature(sig, role, fp, iface, "initiate");
45.67 }
45.68
45.69 -void write_server_completion_signature(struct signature *sig,
45.70 +/* Generate a signature featuring an initiator reference (for genuine decoupled
45.71 + completions) and only "out" and "inout" parameters. */
45.72 +
45.73 +static void write_server_completion_signature(struct signature *sig,
45.74 enum signature_role role,
45.75 FILE *fp, struct interface *iface)
45.76 {
45.77 char *opname = get_operation_name(iface, sig);
45.78 -
45.79 - /* Generate a signature featuring an initiator reference (for genuine
45.80 - decoupled completions) and only "out" and "inout" parameters. */
45.81 -
45.82 int completion = have_attribute(sig->attributes, "completion");
45.83
45.84 char *prologue = completion ?
45.85 @@ -113,36 +88,104 @@
45.86 free(opname);
45.87 }
45.88
45.89 -/* Generate function source code for each operation, with the generated function
45.90 - unpacking a message, calling the actual operation and repacking the
45.91 - results. */
45.92 +/* Generate a cast for superfluous message structures. */
45.93 +
45.94 +static void write_superfluous_message_cast(FILE *fp, int input_words, int input_items,
45.95 + int output_words, int output_items)
45.96 +{
45.97 + if (!input_words && !input_items && !output_words && !output_items)
45.98 + fputs(server_function_body_unused_message, fp);
45.99 +}
45.100 +
45.101 +/* Generate the initialisation of input words and items. */
45.102
45.103 -void write_server_function(struct signature *sig, FILE *fp, struct interface *iface)
45.104 +static void write_input_initialisation(struct parameter *param, FILE *fp,
45.105 + const char *opname, int input_words,
45.106 + int input_items)
45.107 +{
45.108 + if (input_words)
45.109 + {
45.110 + write_accessor_initialisation(IN_PARAMETER, SERVER_ROLE, GENERAL_FUNCTION_ROLE,
45.111 + opname, fp);
45.112 + write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER,
45.113 + WORD_CLASS, fp);
45.114 + }
45.115 +
45.116 + if (input_items)
45.117 + {
45.118 + fputs("\n", fp);
45.119 + write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER,
45.120 + ITEM_CLASS, fp);
45.121 + }
45.122 +}
45.123 +
45.124 +/* Generate the initialisation of output words and items. */
45.125 +
45.126 +static void write_output_initialisation(struct parameter *param, FILE *fp,
45.127 + const char *opname, int output_words,
45.128 + int output_items, enum function_role function)
45.129 {
45.130 - if (have_attribute(sig->attributes, "completion"))
45.131 + if (output_words)
45.132 + {
45.133 + write_accessor_initialisation(OUT_PARAMETER, SERVER_ROLE, function,
45.134 + opname, fp);
45.135 + write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER,
45.136 + WORD_CLASS, fp);
45.137 + }
45.138 +
45.139 + if (output_items)
45.140 {
45.141 - write_server_initiation_signature(sig, DEFINITION_ROLE, fp, iface);
45.142 - write_server_initiation_function_body(sig->parameters, fp, iface, sig);
45.143 - fputs(END_FUNCTION, fp);
45.144 + fputs("\n", fp);
45.145 + write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER,
45.146 + ITEM_CLASS, fp);
45.147 }
45.148 +}
45.149 +
45.150 +/* Generate an invocation of the actual server operation. */
45.151 +
45.152 +static void write_server_function_call(struct parameter *param, FILE *fp,
45.153 + struct interface *iface,
45.154 + struct signature *sig,
45.155 + enum specifier specifier)
45.156 +{
45.157 + int continuing = 0;
45.158 + char *name, *addr,
45.159 + *opname = get_signature_operation_name(iface, sig, SERVER_ROLE,
45.160 + ACCESS_ROLE, conf.language);
45.161 +
45.162 + fputs("\n err = ", fp);
45.163 +
45.164 + /* Access a method when emitting C++. */
45.165 +
45.166 + if (conf.language == CPP_LANGUAGE)
45.167 + fprintf(fp, "_self->%s(", opname);
45.168 +
45.169 + /* Employ a function pointer via the object type otherwise. */
45.170 +
45.171 else
45.172 {
45.173 - write_server_wrapper_signature(sig, DEFINITION_ROLE, fp, iface);
45.174 - write_server_wrapper_function_body(sig->parameters, fp, iface, sig);
45.175 - fputs(END_FUNCTION, fp);
45.176 + fprintf(fp, "_self->iface->%s(_self->ref", opname);
45.177 + continuing = 1;
45.178 }
45.179
45.180 - /* Write the appropriate completion function even for use by conventional
45.181 - operations. */
45.182 + /* Generate the parameter list, employing addresses for output parameters. */
45.183 +
45.184 + write_parameters(param, fp, INVOCATION_ROLE, GENERAL_FUNCTION_ROLE, specifier,
45.185 + continuing);
45.186 + fputs(");\n", fp);
45.187
45.188 - write_server_completion_signature(sig, DEFINITION_ROLE, fp, iface);
45.189 - write_server_completion_function_body(sig->parameters, fp, iface, sig);
45.190 - fputs(END_FUNCTION, fp);
45.191 + /* Emit post-invocation details. */
45.192 +
45.193 + fputs(server_function_body_call, fp);
45.194 +
45.195 + /* Free allocated strings. */
45.196 +
45.197 + free(opname);
45.198 }
45.199
45.200 /* Generate a function body corresponding to an operation for server use. */
45.201
45.202 -void write_server_wrapper_function_body(struct parameter *param, FILE *fp,
45.203 +static void write_server_wrapper_function_body(struct parameter *param, FILE *fp,
45.204 struct interface *iface, struct signature *sig)
45.205 {
45.206 int input_words, input_items, output_words, output_items;
45.207 @@ -191,7 +234,7 @@
45.208
45.209 /* Generate a function body corresponding to the initiation of an operation. */
45.210
45.211 -void write_server_initiation_function_body(struct parameter *param, FILE *fp,
45.212 +static void write_server_initiation_function_body(struct parameter *param, FILE *fp,
45.213 struct interface *iface,
45.214 struct signature *sig)
45.215 {
45.216 @@ -237,7 +280,7 @@
45.217
45.218 /* Generate a function body corresponding to the completion of an operation. */
45.219
45.220 -void write_server_completion_function_body(struct parameter *param, FILE *fp,
45.221 +static void write_server_completion_function_body(struct parameter *param, FILE *fp,
45.222 struct interface *iface,
45.223 struct signature *sig)
45.224 {
45.225 @@ -280,96 +323,59 @@
45.226 free(opname);
45.227 }
45.228
45.229 -/* Generate a cast for superfluous message structures. */
45.230 +
45.231 +
45.232 +/* Public functions. */
45.233 +
45.234 +/* Generate each component operation signature or "function prototype". */
45.235
45.236 -void write_superfluous_message_cast(FILE *fp, int input_words, int input_items,
45.237 - int output_words, int output_items)
45.238 +void write_server_interface_signature(struct signature *sig,
45.239 + enum signature_role role, FILE *fp,
45.240 + struct interface *iface)
45.241 {
45.242 - if (!input_words && !input_items && !output_words && !output_items)
45.243 - fputs(server_function_body_unused_message, fp);
45.244 + write_interface_signature(sig, role, SERVER_ROLE,
45.245 + get_server_function_role(sig), fp, iface);
45.246 }
45.247
45.248 -/* Generate the initialisation of input words and items. */
45.249 +/* Generate signature declarations for each operation. */
45.250
45.251 -void write_input_initialisation(struct parameter *param, FILE *fp,
45.252 - const char *opname, int input_words,
45.253 - int input_items)
45.254 +void write_server_signature(struct signature *sig, enum signature_role role,
45.255 + FILE *fp, struct interface *iface)
45.256 {
45.257 - if (input_words)
45.258 - {
45.259 - write_accessor_initialisation(IN_PARAMETER, SERVER_ROLE, GENERAL_FUNCTION_ROLE,
45.260 - opname, fp);
45.261 - write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER,
45.262 - WORD_CLASS, fp);
45.263 - }
45.264 + if (have_attribute(sig->attributes, "completion"))
45.265 + write_server_initiation_signature(sig, role, fp, iface);
45.266 + else
45.267 + write_server_wrapper_signature(sig, role, fp, iface);
45.268
45.269 - if (input_items)
45.270 - {
45.271 - fputs("\n", fp);
45.272 - write_message_access(param, SERVER_ROLE, GENERAL_FUNCTION_ROLE, IN_PARAMETER,
45.273 - ITEM_CLASS, fp);
45.274 - }
45.275 + /* Write the appropriate completion signature even for use by conventional
45.276 + operations. */
45.277 +
45.278 + write_server_completion_signature(sig, role, fp, iface);
45.279 }
45.280
45.281 -/* Generate the initialisation of output words and items. */
45.282 +/* Generate function source code for each operation, with the generated function
45.283 + unpacking a message, calling the actual operation and repacking the
45.284 + results. */
45.285
45.286 -void write_output_initialisation(struct parameter *param, FILE *fp,
45.287 - const char *opname, int output_words,
45.288 - int output_items, enum function_role function)
45.289 +void write_server_function(struct signature *sig, FILE *fp, struct interface *iface)
45.290 {
45.291 - if (output_words)
45.292 + if (have_attribute(sig->attributes, "completion"))
45.293 {
45.294 - write_accessor_initialisation(OUT_PARAMETER, SERVER_ROLE, function,
45.295 - opname, fp);
45.296 - write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER,
45.297 - WORD_CLASS, fp);
45.298 + write_server_initiation_signature(sig, DEFINITION_ROLE, fp, iface);
45.299 + write_server_initiation_function_body(sig->parameters, fp, iface, sig);
45.300 + fputs(END_FUNCTION, fp);
45.301 + }
45.302 + else
45.303 + {
45.304 + write_server_wrapper_signature(sig, DEFINITION_ROLE, fp, iface);
45.305 + write_server_wrapper_function_body(sig->parameters, fp, iface, sig);
45.306 + fputs(END_FUNCTION, fp);
45.307 }
45.308
45.309 - if (output_items)
45.310 - {
45.311 - fputs("\n", fp);
45.312 - write_message_access(param, SERVER_ROLE, function, OUT_PARAMETER,
45.313 - ITEM_CLASS, fp);
45.314 - }
45.315 -}
45.316 -
45.317 -/* Generate an invocation of the actual server operation. */
45.318 -
45.319 -void write_server_function_call(struct parameter *param, FILE *fp,
45.320 - struct interface *iface, struct signature *sig,
45.321 - enum specifier specifier)
45.322 -{
45.323 - int continuing = 0;
45.324 - char *name, *addr,
45.325 - *opname = get_signature_operation_name(iface, sig, SERVER_ROLE,
45.326 - ACCESS_ROLE, conf.language);
45.327 -
45.328 - fputs("\n err = ", fp);
45.329 -
45.330 - /* Access a method when emitting C++. */
45.331 + /* Write the appropriate completion function even for use by conventional
45.332 + operations. */
45.333
45.334 - if (conf.language == CPP_LANGUAGE)
45.335 - fprintf(fp, "_self->%s(", opname);
45.336 -
45.337 - /* Employ a function pointer via the object type otherwise. */
45.338 -
45.339 - else
45.340 - {
45.341 - fprintf(fp, "_self->iface->%s(_self->ref", opname);
45.342 - continuing = 1;
45.343 - }
45.344 -
45.345 - /* Generate the parameter list, employing addresses for output parameters. */
45.346 -
45.347 - write_parameters(param, fp, INVOCATION_ROLE, GENERAL_FUNCTION_ROLE, specifier,
45.348 - continuing);
45.349 - fputs(");\n", fp);
45.350 -
45.351 - /* Emit post-invocation details. */
45.352 -
45.353 - fputs(server_function_body_call, fp);
45.354 -
45.355 - /* Free allocated strings. */
45.356 -
45.357 - free(opname);
45.358 + write_server_completion_signature(sig, DEFINITION_ROLE, fp, iface);
45.359 + write_server_completion_function_body(sig->parameters, fp, iface, sig);
45.360 + fputs(END_FUNCTION, fp);
45.361 }
46.1 --- a/server.h Fri Dec 09 19:33:15 2022 +0100
46.2 +++ b/server.h Sat Dec 10 01:28:22 2022 +0100
46.3 @@ -1,7 +1,7 @@
46.4 /*
46.5 * Server code generation.
46.6 *
46.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
46.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
46.9 *
46.10 * This program is free software; you can redistribute it and/or
46.11 * modify it under the terms of the GNU General Public License as
46.12 @@ -40,46 +40,3 @@
46.13 void write_server_interface_signature(struct signature *sig,
46.14 enum signature_role role, FILE *fp,
46.15 struct interface *iface);
46.16 -
46.17 -void write_server_wrapper_signature(struct signature *sig,
46.18 - enum signature_role role,
46.19 - FILE *fp, struct interface *iface);
46.20 -
46.21 -void write_server_initiation_signature(struct signature *sig,
46.22 - enum signature_role role,
46.23 - FILE *fp, struct interface *iface);
46.24 -
46.25 -void write_server_completion_signature(struct signature *sig,
46.26 - enum signature_role role,
46.27 - FILE *fp, struct interface *iface);
46.28 -
46.29 -/* Wrapper function generation. */
46.30 -
46.31 -void write_server_wrapper_function_body(struct parameter *param, FILE *fp,
46.32 - struct interface *iface,
46.33 - struct signature *sig);
46.34 -
46.35 -void write_server_initiation_function_body(struct parameter *param, FILE *fp,
46.36 - struct interface *iface,
46.37 - struct signature *sig);
46.38 -
46.39 -void write_server_completion_function_body(struct parameter *param, FILE *fp,
46.40 - struct interface *iface,
46.41 - struct signature *sig);
46.42 -
46.43 -/* Common function body code generation. */
46.44 -
46.45 -void write_superfluous_message_cast(FILE *fp, int input_words, int input_items,
46.46 - int output_words, int output_items);
46.47 -
46.48 -void write_input_initialisation(struct parameter *param, FILE *fp,
46.49 - const char *opname, int input_words,
46.50 - int input_items);
46.51 -
46.52 -void write_output_initialisation(struct parameter *param, FILE *fp,
46.53 - const char *opname, int output_words,
46.54 - int output_items, enum function_role function);
46.55 -
46.56 -void write_server_function_call(struct parameter *param, FILE *fp,
46.57 - struct interface *iface, struct signature *sig,
46.58 - enum specifier specifier);
47.1 --- a/summary.c Fri Dec 09 19:33:15 2022 +0100
47.2 +++ b/summary.c Sat Dec 10 01:28:22 2022 +0100
47.3 @@ -1,7 +1,7 @@
47.4 /*
47.5 * Interface summary generation.
47.6 *
47.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
47.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
47.9 *
47.10 * This program is free software; you can redistribute it and/or
47.11 * modify it under the terms of the GNU General Public License as
47.12 @@ -22,64 +22,49 @@
47.13 #include <stdio.h>
47.14 #include "summary.h"
47.15
47.16 -void show_interface(struct interface *iface)
47.17 +
47.18 +
47.19 +static void indent(int level)
47.20 {
47.21 - printf("Interface: %s\n", iface->name);
47.22 - show_includes(iface->includes);
47.23 - show_attributes(iface->attributes);
47.24 - show_signatures(iface->signatures);
47.25 + while (level--) putchar(' ');
47.26 }
47.27
47.28 -void show_includes(struct include *inc)
47.29 +static void show_imports(struct import *imp, int level)
47.30 +{
47.31 + if (imp == NULL)
47.32 + return;
47.33 +
47.34 + show_imports(imp->tail, level);
47.35 +
47.36 + indent(level);
47.37 + printf("%s: %s\n", "Import", imp->filename);
47.38 +}
47.39 +
47.40 +static void show_includes(struct include *inc, int level)
47.41 {
47.42 if (inc == NULL)
47.43 return;
47.44 - show_includes(inc->tail);
47.45 - printf("Include: %s\n", inc->filename);
47.46 -}
47.47 +
47.48 + show_includes(inc->tail, level);
47.49
47.50 -void show_signatures(struct signature *sig)
47.51 -{
47.52 - if (sig == NULL)
47.53 - return;
47.54 - show_signature(sig);
47.55 - show_signatures(sig->tail);
47.56 -}
47.57 -
47.58 -void show_signature(struct signature *sig)
47.59 -{
47.60 - printf("Signature: %s %s\n", sig->qualifier, sig->operation);
47.61 - show_attributes(sig->attributes);
47.62 - show_parameters(sig->parameters);
47.63 + indent(level);
47.64 + printf("%s: %s\n", "Include", inc->filename);
47.65 }
47.66
47.67 -void show_attributes(struct attribute *attr)
47.68 +static void show_identifiers(struct identifier *ident)
47.69 {
47.70 - if (attr == NULL)
47.71 - return;
47.72 - show_attribute(attr);
47.73 - show_attributes(attr->tail);
47.74 + while (ident != NULL)
47.75 + {
47.76 + printf(" %s", ident->identifier);
47.77 + ident = ident->tail;
47.78 + }
47.79 }
47.80
47.81 -void show_attribute(struct attribute *attr)
47.82 -{
47.83 - printf("Attribute: %s", attr->attribute);
47.84 - show_identifiers(attr->identifiers);
47.85 - printf("\n");
47.86 -}
47.87 -
47.88 -void show_parameters(struct parameter *param)
47.89 -{
47.90 - if (param == NULL)
47.91 - return;
47.92 - show_parameter(param);
47.93 - show_parameters(param->tail);
47.94 -}
47.95 -
47.96 -void show_parameter(struct parameter *param)
47.97 +static void show_parameter(struct parameter *param, int level)
47.98 {
47.99 char *type;
47.100
47.101 + indent(level);
47.102 printf("Parameter: %s%s", param->specifier & IN_PARAMETER ? "IN" : "",
47.103 param->specifier & OUT_PARAMETER ? "OUT" : "");
47.104
47.105 @@ -95,11 +80,86 @@
47.106 printf("\n");
47.107 }
47.108
47.109 -void show_identifiers(struct identifier *ident)
47.110 +static void show_parameters(struct parameter *param, int level)
47.111 +{
47.112 + if (param == NULL)
47.113 + return;
47.114 +
47.115 + show_parameter(param, level);
47.116 + show_parameters(param->tail, level);
47.117 +}
47.118 +
47.119 +static void show_attribute(struct attribute *attr, int level)
47.120 +{
47.121 + indent(level);
47.122 + printf("Attribute: %s", attr->attribute);
47.123 +
47.124 + show_identifiers(attr->identifiers);
47.125 + printf("\n");
47.126 +}
47.127 +
47.128 +static void show_attributes(struct attribute *attr, int level)
47.129 +{
47.130 + if (attr == NULL)
47.131 + return;
47.132 +
47.133 + show_attribute(attr, level);
47.134 + show_attributes(attr->tail, level);
47.135 +}
47.136 +
47.137 +static void show_signature(struct signature *sig, int level)
47.138 +{
47.139 + indent(level);
47.140 + printf("Signature: %s %s\n", sig->qualifier, sig->operation);
47.141 +
47.142 + show_attributes(sig->attributes, level + 2);
47.143 + show_parameters(sig->parameters, level + 2);
47.144 +}
47.145 +
47.146 +static void show_signatures(struct signature *sig, int level)
47.147 {
47.148 - while (ident != NULL)
47.149 - {
47.150 - printf(" %s", ident->identifier);
47.151 - ident = ident->tail;
47.152 - }
47.153 + if (sig == NULL)
47.154 + return;
47.155 +
47.156 + show_signature(sig, level);
47.157 + show_signatures(sig->tail, level);
47.158 +}
47.159 +
47.160 +static void show_bases(struct interface_ref *base, int level)
47.161 +{
47.162 + if (base == NULL)
47.163 + return;
47.164 +
47.165 + indent(level);
47.166 + printf("Base: %s\n", base->name);
47.167 +
47.168 + if (base->iface != NULL)
47.169 + show_interface(base->iface, level + 2);
47.170 + show_bases(base->tail, level);
47.171 }
47.172 +
47.173 +
47.174 +
47.175 +/* Public functions. */
47.176 +
47.177 +void show_interface(struct interface *iface, int level)
47.178 +{
47.179 + indent(level);
47.180 + printf("Interface: %s\n", iface->name);
47.181 + indent(level);
47.182 + printf("Basename: %s\n", iface->output_basename);
47.183 +
47.184 + show_bases(iface->bases, level + 2);
47.185 + show_imports(iface->imports, level);
47.186 + show_includes(iface->includes, level);
47.187 + show_attributes(iface->attributes, level);
47.188 + show_signatures(iface->signatures, level);
47.189 +}
47.190 +
47.191 +void show_interfaces(struct interface *iface)
47.192 +{
47.193 + if (iface->tail != NULL)
47.194 + show_interfaces(iface->tail);
47.195 +
47.196 + show_interface(iface, 0);
47.197 +}
48.1 --- a/summary.h Fri Dec 09 19:33:15 2022 +0100
48.2 +++ b/summary.h Sat Dec 10 01:28:22 2022 +0100
48.3 @@ -1,7 +1,7 @@
48.4 /*
48.5 * Interface summary generation.
48.6 *
48.7 - * Copyright (C) 2019 Paul Boddie <paul@boddie.org.uk>
48.8 + * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>
48.9 *
48.10 * This program is free software; you can redistribute it and/or
48.11 * modify it under the terms of the GNU General Public License as
48.12 @@ -23,12 +23,5 @@
48.13
48.14 #include "types.h"
48.15
48.16 -void show_interface(struct interface *iface);
48.17 -void show_includes(struct include *inc);
48.18 -void show_signatures(struct signature *sig);
48.19 -void show_signature(struct signature *sig);
48.20 -void show_attributes(struct attribute *attr);
48.21 -void show_attribute(struct attribute *attr);
48.22 -void show_parameters(struct parameter *param);
48.23 -void show_parameter(struct parameter *param);
48.24 -void show_identifiers(struct identifier *ident);
48.25 +void show_interface(struct interface *iface, int level);
48.26 +void show_interfaces(struct interface *iface);
49.1 --- a/templates.h Fri Dec 09 19:33:15 2022 +0100
49.2 +++ b/templates.h Sat Dec 10 01:28:22 2022 +0100
49.3 @@ -26,13 +26,13 @@
49.4 #define client_filename_c "%s/%s_client.c"
49.5 #define client_filename_cpp "%s/%s_client.cc"
49.6 #define client_header_filename "%s/%s_client.h"
49.7 -#define compound_interface_type_filename "%s/%s_interface_type.h"
49.8 -#define compound_interfaces_filename "%s/%s_interfaces.h"
49.9 #define interface_filename "%s/%s_interface.h"
49.10 #define server_filename_c "%s/%s_server.c"
49.11 #define server_filename_cpp "%s/%s_server.cc"
49.12 #define server_header_filename "%s/%s_server.h"
49.13
49.14 +
49.15 +
49.16 /* Client templates. */
49.17
49.18 #define client_prologue \
49.19 @@ -62,8 +62,8 @@
49.20 " : public %s"
49.21
49.22 #define client_interface_endpoint_declaration_cpp \
49.23 -"\nprotected:\n" \
49.24 -" %s _endp;\n"
49.25 +"protected:\n" \
49.26 +" %s _endp;\n\n"
49.27
49.28 #define client_interface_constructor_cpp \
49.29 "\n %s(%s endp) : _endp(endp) { }\n"
49.30 @@ -71,7 +71,10 @@
49.31 /* Client interface definitions for C. */
49.32
49.33 #define client_interface_declaration_c \
49.34 -"\nextern iface_%s client_iface_%s;"
49.35 +"\nextern iface_%s client_iface_%s;\n"
49.36 +
49.37 +#define client_interface_prologue_empty_c \
49.38 +"\niface_%s client_iface_%s;"
49.39
49.40 #define client_interface_prologue_c \
49.41 "\niface_%s client_iface_%s = {"
49.42 @@ -82,6 +85,8 @@
49.43 #define client_interface_epilogue_c \
49.44 "\n};\n"
49.45
49.46 +
49.47 +
49.48 /* Compound interface dispatcher templates. */
49.49
49.50 #define compound_dispatch_prologue \
49.51 @@ -92,49 +97,17 @@
49.52 " switch (l4_msgtag_label(msg->tag))\n" \
49.53 " {\n"
49.54
49.55 -#define compound_dispatch_epilogue \
49.56 -" default:\n" \
49.57 -" ipc_message_send_error(msg, -L4_EBADPROTO);\n" \
49.58 -" ipc_message_reply(msg);\n" \
49.59 -" break;\n" \
49.60 -" }\n"
49.61 +/* Compound interface definitions. */
49.62
49.63 -#define compound_dispatch_header_prologue \
49.64 -"#pragma once\n\n" \
49.65 -"#include <ipc/message.h>\n" \
49.66 +#define compound_interface_include \
49.67 "#include \"%s_interface.h\"\n"
49.68
49.69 -/* Compound interface class definitions. */
49.70 -
49.71 -#define compound_interface_prologue_cpp \
49.72 -"#pragma once\n\n" \
49.73 -"#include \"%s_interfaces.h\"\n\n" \
49.74 -"#ifdef __cplusplus\n\n" \
49.75 -"class %s :"
49.76 -
49.77 -#define compound_interface_prologue_c \
49.78 -"#pragma once\n\n" \
49.79 -"#include \"%s_interface_type.h\"\n\n" \
49.80 -"typedef struct\n" \
49.81 -"{\n"
49.82 -
49.83 -#define compound_interface_epilogue_cpp \
49.84 -"\n{\n};\n\n" \
49.85 -"#endif /* __cplusplus */\n"
49.86 -
49.87 -#define compound_interface_epilogue_c \
49.88 -"\n} iface_%s;\n"
49.89 -
49.90 -#define compound_interfaces_prologue \
49.91 -"#pragma once\n\n"
49.92 -
49.93 #define compound_ref_type_definition_prologue_c \
49.94 -"#pragma once\n\n" \
49.95 -"#include <l4/sys/types.h>\n" \
49.96 -"#include \"%s_interfaces.h\"\n\n" \
49.97 -"typedef union {\n" \
49.98 -" %s cap;\n" \
49.99 -" void *ptr;\n"
49.100 +"\ntypedef struct {\n" \
49.101 +" union {\n" \
49.102 +" %s cap;\n" \
49.103 +" void *ptr;\n" \
49.104 +" };\n"
49.105
49.106 #define compound_ref_type_definition_member_c \
49.107 " ref_%s as_%s;\n"
49.108 @@ -148,11 +121,44 @@
49.109 #define compound_interface_conversion_cpp \
49.110 "\n#define convert_to_%s(_self) (_self)\n"
49.111
49.112 +
49.113 +
49.114 /* Dispatch functions. */
49.115
49.116 #define dispatch_function_signature \
49.117 "\nvoid dispatch_%s(ipc_message_t *msg, %s *_self)"
49.118
49.119 +/* Dispatch templates. */
49.120 +
49.121 +#define dispatch_function_interface_case \
49.122 +" case %s:\n" \
49.123 +" dispatch_%s(msg, %s);\n" \
49.124 +" break;\n\n"
49.125 +
49.126 +#define dispatch_function_wrapper_case \
49.127 +" case %s:\n" \
49.128 +" ipc_message_send_error(msg, %s_%s(msg, %s));\n" \
49.129 +" break;\n\n"
49.130 +
49.131 +#define dispatch_function_reply_wrapper_case \
49.132 +" case %s:\n" \
49.133 +" err = %s_%s(msg, %s);\n" \
49.134 +" ipc_message_send_error(msg, err != IPC_MESSAGE_SENT ? err : (long) L4_EOK);\n" \
49.135 +" if (err != IPC_MESSAGE_SENT)\n" \
49.136 +" ipc_message_reply(msg);\n" \
49.137 +" break;\n\n"
49.138 +
49.139 +#define dispatch_function_default_case \
49.140 +" default:\n" \
49.141 +" ipc_message_send_error(msg, -L4_EBADPROTO);\n" \
49.142 +" ipc_message_reply(msg);\n" \
49.143 +" break;\n"
49.144 +
49.145 +#define dispatch_function_dispatcher_epilogue \
49.146 +" }\n"
49.147 +
49.148 +
49.149 +
49.150 /* Message handling functions. */
49.151
49.152 #define handle_function_signature \
49.153 @@ -163,6 +169,8 @@
49.154 " dispatch_%s(msg, _self);\n" \
49.155 " ipc_message_discard(msg);\n"
49.156
49.157 +
49.158 +
49.159 /* General header template. */
49.160
49.161 #define header_prologue \
49.162 @@ -170,6 +178,8 @@
49.163 "#include <l4/sys/err.h>\n" \
49.164 "#include <l4/sys/types.h>\n"
49.165
49.166 +
49.167 +
49.168 /* Server templates. */
49.169
49.170 #define server_header_prologue \
49.171 @@ -226,14 +236,7 @@
49.172 "\n ipc_message_prepare(msg);\n\n" \
49.173 " return L4_EOK;\n"
49.174
49.175 -/* Server dispatch function templates. */
49.176
49.177 -#define server_function_dispatcher_body_epilogue \
49.178 -" default:\n" \
49.179 -" ipc_message_send_error(msg, -L4_EBADPROTO);\n" \
49.180 -" ipc_message_reply(msg);\n" \
49.181 -" break;\n" \
49.182 -" }\n"
49.183
49.184 /* Interface class definitions. */
49.185
49.186 @@ -241,14 +244,20 @@
49.187 "\n#ifdef __cplusplus\n" \
49.188 "\nclass %s"
49.189
49.190 +#define interface_prologue_base_cpp \
49.191 +"%spublic %s"
49.192 +
49.193 #define interface_prologue_c \
49.194 "\ntypedef struct" \
49.195
49.196 #define interface_body_begin \
49.197 -"\n{"
49.198 +"\n{\n"
49.199 +
49.200 +#define interface_body_base_c \
49.201 +" iface_%s *to_%s;\n"
49.202
49.203 #define interface_signatures_prologue_cpp \
49.204 -"\npublic:"
49.205 +"public:"
49.206
49.207 #define interface_epilogue_cpp \
49.208 "};\n\n" \
49.209 @@ -261,7 +270,7 @@
49.210 "\n%slong %s("
49.211
49.212 #define interface_struct_member_function_signature_prologue \
49.213 -"\n long (*%s)("
49.214 +" long (*%s)("
49.215
49.216 #define interface_unimplemented_method_prologue_cpp \
49.217 "\n {"
49.218 @@ -287,6 +296,8 @@
49.219 #define expected_items_definition \
49.220 "\n#define %s_expected_items %d\n"
49.221
49.222 +
49.223 +
49.224 /* Opcode definitions. */
49.225
49.226 #define opcode_enumeration_prologue \
49.227 @@ -323,25 +334,7 @@
49.228 #define message_accessor_writing_initialiser \
49.229 " ipc_message_reserve_words(%smsg, sizeof(struct %s_words_%s));\n"
49.230
49.231 -/* Dispatch templates. */
49.232
49.233 -#define dispatch_function_interface_case \
49.234 -" case %s:\n" \
49.235 -" dispatch_%s(msg, %s);\n" \
49.236 -" break;\n\n"
49.237 -
49.238 -#define dispatch_function_wrapper_case \
49.239 -" case %s:\n" \
49.240 -" ipc_message_send_error(msg, %s_%s(msg, %s));\n" \
49.241 -" break;\n\n"
49.242 -
49.243 -#define dispatch_function_reply_wrapper_case \
49.244 -" case %s:\n" \
49.245 -" err = %s_%s(msg, %s);\n" \
49.246 -" ipc_message_send_error(msg, err != IPC_MESSAGE_SENT ? err : (long) L4_EOK);\n" \
49.247 -" if (err != IPC_MESSAGE_SENT)\n" \
49.248 -" ipc_message_reply(msg);\n" \
49.249 -" break;\n\n"
49.250
49.251 /* Tokens. */
49.252
49.253 @@ -354,6 +347,8 @@
49.254 #define COMPLETE_SIGNATURE ";\n"
49.255 #define END_SIGNATURE "\n"
49.256
49.257 +
49.258 +
49.259 /* Texts. */
49.260
49.261 #define help_text \
49.262 @@ -362,14 +357,13 @@
49.263 "The following options are supported:\n\n" \
49.264 "--all or -a Produce all kinds of output for a given language.\n\n" \
49.265 "--client or -c Generate client code.\n\n" \
49.266 -"--comp or -C Generate a compound/composite/component interface using\n" \
49.267 -" the given filename prefix.\n\n" \
49.268 "--dir or -d Create output in the indicated directory.\n\n" \
49.269 +"--files or -f Only show processed filenames, produce no files.\n\n" \
49.270 "--headers or -h Produce header files.\n\n" \
49.271 "--help or -? Show this message.\n\n" \
49.272 "--interfaces or -i Produce interface header files.\n\n" \
49.273 "--language or -l Generate code in the indicated language.\n\n" \
49.274 -"--comp-name or -N Indicate the compound/composite/component interface name.\n\n" \
49.275 +"--recursive or -R Also generate code for any base interfaces.\n\n" \
49.276 "--routines or -r Produce program routines.\n\n" \
49.277 "--server or -s Generate server code.\n\n" \
49.278 "--verbose or -v Show verbose output reporting the processed interfaces.\n\n" \