From 53126578ee08c0bd3b3987959fb7d768deb5aedc Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 1 Jan 2012 16:45:14 +0000 Subject: [PATCH] More implementation. --- .gitignore | 2 + APIs/error.api | 37 ++++++++++++- APIs/mknod.api | 5 +- configure.ac | 23 ++++++++ examples/Makefile.am | 2 + generator-lib/wrappi_accumulator.ml | 3 +- generator-lib/wrappi_types.ml | 10 ++-- generator-lib/wrappi_types.mli | 9 ++-- generator-macros/pa_wrap.ml | 7 ++- generator/wrappi_c.ml | 1 + generator/wrappi_c_impl.ml | 101 +++++++++++++++++++++++++++--------- lib/.gitignore | 6 +-- lib/Makefile.am | 4 ++ lib/connect.c | 45 ++++++++++++++++ lib/implementation_files.mk | 6 +-- lib/internal.h | 46 +++++++++++++++- lib/wrappi.c | 60 ++++++++++++++++++++- 17 files changed, 320 insertions(+), 47 deletions(-) create mode 100644 lib/connect.c diff --git a/.gitignore b/.gitignore index 545b80a..ec4a33c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,12 +22,14 @@ Makefile.in /config.sub /configure /depcomp +/examples/remote /generator-lib/config.ml /generator/generator /generator/stamp-generator /install-sh /lib/wrappi.h /libtool +/local* /ltmain.sh /m4/libtool.m4 /m4/ltoptions.m4 diff --git a/APIs/error.api b/APIs/error.api index e315338..2dd8652 100644 --- a/APIs/error.api +++ b/APIs/error.api @@ -19,13 +19,46 @@ entry_point local bool error () << - return w->error_flag; + return w->internal.error != NULL; >> entry_point local void clear_error () << - w->error_flag = 0; + free (w->internal.error); + w->internal.error = NULL; + w->internal.errnum = 0; + w->internal.error_func = NULL; +>> + +entry_point local +static_string get_error () +<< + if (!w->internal.error) { + set_error ("no error on handle: do not call this function unless 'wrap_error' returns true"); + return NULL; + } + return w->internal.error; +>> + +entry_point local +int get_errno () +<< + if (!w->internal.error) { + set_error ("no error on handle: do not call this function unless 'wrap_error' returns true"); + return -1; + } + return w->internal.errnum; +>> + +entry_point local +static_string get_error_func () +<< + if (!w->internal.error) { + set_error ("no error on handle: do not call this function unless 'wrap_error' returns true"); + return NULL; + } + return w->internal.error_func; >> (* diff --git a/APIs/mknod.api b/APIs/mknod.api index 07d2cca..a6bc8ef 100644 --- a/APIs/mknod.api +++ b/APIs/mknod.api @@ -19,11 +19,8 @@ entry_point void mknod_char (pathname path, fileperm perm, uint64 major, uint64 minor) << - if (mknod (path, S_IFCHR | perm, makedev (major, minor)) == -1) { + if (mknod (path, S_IFCHR | perm, makedev (major, minor)) == -1) set_error_errno ("mknod: %s", path); - return -1; - } - return 0; >> includes [ "sys/types.h"; "sys/stat.h"; "fcntl.h"; "unistd.h" ] diff --git a/configure.ac b/configure.ac index 79ed9c9..3cad79e 100644 --- a/configure.ac +++ b/configure.ac @@ -20,6 +20,10 @@ AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_MACRO_DIR([m4]) +dnl Allow all GNU/Linux functions. +dnl autoconf complains unless this is very early in the file. +AC_USE_SYSTEM_EXTENSIONS + AC_PROG_LIBTOOL AC_PROG_SED @@ -34,6 +38,25 @@ test "x$U" != "x" && AC_MSG_ERROR([Compiler not ANSI compliant]) AM_PROG_CC_C_O +AC_ARG_ENABLE([gcc-warnings], + [AS_HELP_STRING([--enable-gcc-warnings], + [turn on lots of GCC warnings (for developers)])], + [case $enableval in + yes|no) ;; + *) AC_MSG_ERROR([bad value $enableval for gcc-warnings option]) ;; + esac + gcc_warnings=$enableval], + [gcc_warnings=no] +) + +if test "$gcc_warnings" = yes; then + # XXX With gnulib we can improve this in future. + WARN_CFLAGS="-Wall" + AC_SUBST([WARN_CFLAGS]) + WERROR_CFLAGS="-Werror" + AC_SUBST([WERROR_CFLAGS]) +fi + dnl Check support for 64 bit file offsets. AC_SYS_LARGEFILE diff --git a/examples/Makefile.am b/examples/Makefile.am index 7fd04c1..15b68bd 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,3 +20,5 @@ noinst_PROGRAMS = remote remote_SOURCES = remote.c remote_CFLAGS = -I../lib remote_LDADD = ../lib/libwrappi.la + +CLEANFILES = *~ diff --git a/generator-lib/wrappi_accumulator.ml b/generator-lib/wrappi_accumulator.ml index ac09b99..3713d35 100644 --- a/generator-lib/wrappi_accumulator.ml +++ b/generator-lib/wrappi_accumulator.ml @@ -101,7 +101,8 @@ let rec resolve_typedefs thing name loc = function exit 1 let resolve_typedefs_in_ret thing name loc = function - | RVoid as t -> t + | (RVoid + | RStaticString) as t -> t | Return t -> Return (resolve_typedefs thing name loc t) let get_api () = diff --git a/generator-lib/wrappi_types.ml b/generator-lib/wrappi_types.ml index f738f95..998e911 100644 --- a/generator-lib/wrappi_types.ml +++ b/generator-lib/wrappi_types.ml @@ -44,11 +44,14 @@ type prec type parameter = string * ptype * prec option -type rtype = RVoid | Return of ptype +type rtype = RVoid | RStaticString | Return of ptype type ftype = rtype * parameter list * parameter list -type c_code = string +type c_code = { + cc_loc : Camlp4.PreCast.Loc.t; + cc_code : string; +} type entry_point = { ep_loc : Camlp4.PreCast.Loc.t; @@ -124,6 +127,7 @@ let rec string_of_ptype = function | TUnion name -> sprintf "union %s" name let string_of_rtype = function | RVoid -> "void" + | RStaticString -> "static_string" | Return t -> string_of_ptype t let string_of_parameter (name, t, _) = sprintf "%s %s" (string_of_ptype t) name @@ -132,7 +136,7 @@ let string_of_parameters params = let string_of_ftype (ret, req, opt) = sprintf "%s %s %s" (string_of_rtype ret) (string_of_parameters req) (string_of_parameters opt) -let string_of_c_code code = code +let string_of_c_code code = code.cc_code let string_of_typedef td = sprintf "typedef %s %s" td.td_name (string_of_ptype td.td_type) diff --git a/generator-lib/wrappi_types.mli b/generator-lib/wrappi_types.mli index 94cf371..72840fd 100644 --- a/generator-lib/wrappi_types.mli +++ b/generator-lib/wrappi_types.mli @@ -41,15 +41,18 @@ type prec type parameter = string * ptype * prec option (** API parameter (argument name, type, optional precondition). *) -type rtype = RVoid | Return of ptype +type rtype = RVoid | RStaticString | Return of ptype (** API return type. A superset of {!ptype} because we allow the - special value [RVoid] for functions that don't return any value. *) + some special return-only types. *) type ftype = rtype * parameter list * parameter list (** A function type. Return type, list of required parameters, list of optional parameters. *) -type c_code = string +type c_code = { + cc_loc : Camlp4.PreCast.Loc.t; + cc_code : string; +} (** C code. *) type entry_point = { diff --git a/generator-macros/pa_wrap.ml b/generator-macros/pa_wrap.ml index c176fe2..5ce6d08 100644 --- a/generator-macros/pa_wrap.ml +++ b/generator-macros/pa_wrap.ml @@ -89,9 +89,13 @@ let add_typedef _loc name t = let () = (* Quotation expander for C code. *) let c_quotation_expander _loc _ code = + let loc = expr_of_loc _loc _loc in + (* XXX Expand %- or $- expressions in code. *) (* XXX Escape >> in code. *) - ExStr (_loc, code) + + <:expr< { Wrappi_types.cc_loc = $loc$; + cc_code = $str:code$ } >> in Quotation.add "c" Quotation.DynAst.expr_tag c_quotation_expander; @@ -127,6 +131,7 @@ EXTEND Gram (* A return type. *) rtype: [ [ "void" -> <:expr< Wrappi_types.RVoid >> ] + | [ "static_string" -> <:expr< Wrappi_types.RStaticString >> ] | [ t = ptype -> <:expr< Wrappi_types.Return $t$ >> ] ]; diff --git a/generator/wrappi_c.ml b/generator/wrappi_c.ml index 3011ab1..7f9c1b4 100644 --- a/generator/wrappi_c.ml +++ b/generator/wrappi_c.ml @@ -44,6 +44,7 @@ let c_of_ptype ~param = function let c_of_rtype = function | RVoid -> "void" + | RStaticString -> "const char *" | Return t -> c_of_ptype ~param:false t (* Print the extern... declaration of a single entry point. *) diff --git a/generator/wrappi_c_impl.ml b/generator/wrappi_c_impl.ml index 8742fad..c3e2ed7 100644 --- a/generator/wrappi_c_impl.ml +++ b/generator/wrappi_c_impl.ml @@ -46,12 +46,19 @@ let c_of_ptype ~param = function let c_of_rtype = function | RVoid -> "void" + | RStaticString -> "const char *" | Return t -> c_of_ptype ~param:false t -let pr_decl ep = +let pr_defn ?(impl = false) ep = let ret, req, opt = ep.ep_ftype in - pr "%s\n" (c_of_rtype ret); - pr "wrap_%s (wrap_h *w" ep.ep_name; + + if not impl then ( + pr "%s\n" (c_of_rtype ret); + pr "wrap_%s (wrap_h *w" ep.ep_name + ) else ( + pr "static %s\n" (c_of_rtype ret); + pr "impl_%s (struct wrap_internal_h *w" ep.ep_name + ); (* Required parameters. *) List.iter ( @@ -73,43 +80,81 @@ let generate_implementation ep = generate_header CStyle LGPLv2plus; pr "\ +/* Automatically generated implementation of '%s'. + * This API was defined in '%s' at line %d. + */ + +" ep.ep_name (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc); + + pr "\ #include #include #include +#include +#include +#include "; List.iter (pr "#include <%s>\n") ep.ep_includes; pr "\ #include \"wrappi.h\" - #include \"internal.h\" -/* Automatically generated implementation of '%s'. - * This API was defined in '%s' at line %d. - */ +"; -" ep.ep_name (Loc.file_name ep.ep_loc) (Loc.start_line ep.ep_loc); + pr_defn ~impl:(not ep.ep_local) ep; - (* Depending on whether this is a local or remote function, include - * different definitions here. + pr "{\n"; + + (match ep.ep_code with + | None -> () (* XXX implicit code *) + | Some { cc_loc = loc; cc_code = code } -> + pr "#line %d \"%s\"\n" (Loc.start_line loc) (Loc.file_name loc); + pr "%s" code + ); + + pr "}\n"; + + (* For remote functions only, we now need to generate the + * local binding code. *) - (*if ep.ep_local then ... *) + if not ep.ep_local then ( + pr "\n"; - pr_decl ep; + pr_defn ep; - pr "\ -{ -#line %d \"%s\" -" (Loc.start_line ep.ep_loc) (Loc.file_name ep.ep_loc); + pr "{\n"; + pr " assert (w->scheme == NULL); /* XXX */;\n"; + pr "\n"; + pr " "; - (match ep.ep_code with - | None -> () - | Some code -> pr "%s" code - ); + let ret, req, opt = ep.ep_ftype in + + (match ret with + | RVoid -> () + | _ -> pr "return " + ); + + pr "impl_%s ((struct wrap_internal_h *)w" ep.ep_name; + + (* Required parameters. *) + List.iter (fun (name, _, _) -> pr ", %s" name) req; + + (* Optional parameters. *) + if opt <> [] then + assert false; (* XXX not implemented *) + + pr ");\n"; + + (match ret with + | RVoid -> pr " return;\n" + | _ -> () + ); - pr "}\n" + pr "}\n" + ) (* Make a unique, reproducible filename for each entry point. *) let filename_of_ep ep = @@ -137,7 +182,7 @@ let generate_lib_implementation_files_mk api = pr "local_implementation_files := \\\n"; - loop (List.filter (fun ep -> ep.ep_local) eps); + loop (List.filter (fun ep -> ep.ep_local && ep.ep_code <> None) eps); pr "\n"; pr "remote_implementation_files := \\\n"; @@ -149,11 +194,17 @@ let generate api = iter_entry_points api ( fun ep -> - let filename = filename_of_ep ep in + (* Local entry points which don't have associated code are + * assumed to be implemented in hand-written code elsewhere under + * lib/. + *) + if not ep.ep_local || ep.ep_code <> None then ( + let filename = filename_of_ep ep in - gitignores := ("/" ^ filename) :: !gitignores; + gitignores := ("/" ^ filename) :: !gitignores; - output_to ("lib/" ^ filename) generate_implementation ep + output_to ("lib/" ^ filename) generate_implementation ep + ) ); let gitignores = List.rev !gitignores in diff --git a/lib/.gitignore b/lib/.gitignore index 51ea85c..76d4e3e 100644 --- a/lib/.gitignore +++ b/lib/.gitignore @@ -1,8 +1,8 @@ /error-clear_error.c -/handle-connect.c /error-error.c /filesize-filesize.c +/error-get_errno.c +/error-get_error.c +/error-get_error_func.c /mkdir-mkdir.c /mknod-mknod_char.c -/handle-set_hostname.c -/handle-set_scheme.c diff --git a/lib/Makefile.am b/lib/Makefile.am index d634a20..41f197d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -29,5 +29,9 @@ libwrappi_la_LDFLAGS = -version-info $(LIB_MINOR):0:$(LIB_MINOR) libwrappi_la_SOURCES = \ wrappi.h \ wrappi.c \ + connect.c \ $(local_implementation_files) \ $(remote_implementation_files) +libwrappi_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS) + +CLEANFILES = *~ diff --git a/lib/connect.c b/lib/connect.c new file mode 100644 index 0000000..a57fcfa --- /dev/null +++ b/lib/connect.c @@ -0,0 +1,45 @@ +/* wrappi + * Copyright (C) 2011-2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include +#include + +#include "wrappi.h" +#include "internal.h" + +void +wrap_connect (wrap_h *w) +{ + /* Remote not implemented yet. */ + assert (w->scheme == NULL); +} + +void +wrap_set_scheme (wrap_h *w, const char *scheme) +{ + /* XXX */ +} + +void +wrap_set_hostname (wrap_h *w, const char *hostname) +{ + /* XXX */ +} diff --git a/lib/implementation_files.mk b/lib/implementation_files.mk index 4631ce5..04c4a17 100644 --- a/lib/implementation_files.mk +++ b/lib/implementation_files.mk @@ -21,10 +21,10 @@ local_implementation_files := \ error-clear_error.c \ - handle-connect.c \ error-error.c \ - handle-set_hostname.c \ - handle-set_scheme.c + error-get_errno.c \ + error-get_error.c \ + error-get_error_func.c remote_implementation_files := \ filesize-filesize.c \ diff --git a/lib/internal.h b/lib/internal.h index 2213d7b..b9cc57c 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -19,8 +19,52 @@ #ifndef WRAPPI_INTERNAL_H_ #define WRAPPI_INTERNAL_H_ +#include +#include + +#define STREQ(a,b) (strcmp((a),(b)) == 0) +#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) +#define STRNEQ(a,b) (strcmp((a),(b)) != 0) +#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0) +#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0) +#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0) +#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0) +#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0) +#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0) + +struct wrap_internal_h { + char *error; /* Last error on this handle, NULL is none. */ + int errnum; /* errno, or 0 if there was no errno set. */ + const char *error_func; /* Function where the error occurred, if known. */ +}; + struct wrap_h { - int error_flag; + /* The "internal" part of the handle must always appear at the + * beginning of the handle structure. For the remote case, this + * contains a cut-down handle which is what non-local entry points + * are permitted to touch. For the local case, the full handle is + * cast to (struct wrap_internal_h *). + */ + struct wrap_internal_h internal; + + /* Fields that follow the 'internal' structure only exist + * on the local side of a connection. + */ + + /* Connection URL. If scheme = NULL, it means we're using the local + * code. + */ + const char *scheme; + const char *hostname; }; +/* Declare an error, setting the error field in the handle. */ +#define set_error(fs...) \ + wrap_int_set_error ((struct wrap_internal_h *)w, __func__, fs) +#define set_error_errno(fs...) \ + wrap_int_set_error_errno ((struct wrap_internal_h *)w, (errno), __func__, fs) + +extern void wrap_int_set_error (struct wrap_internal_h *w, const char *func, const char *fs, ...); +extern void wrap_int_set_error_errno (struct wrap_internal_h *w, int errnum, const char *func, const char *fs, ...); + #endif /* WRAPPI_INTERNAL_H_ */ diff --git a/lib/wrappi.c b/lib/wrappi.c index ff223b3..0e45890 100644 --- a/lib/wrappi.c +++ b/lib/wrappi.c @@ -20,9 +20,9 @@ #include #include +#include #include "wrappi.h" - #include "internal.h" wrap_h * @@ -40,3 +40,61 @@ wrap_close (wrap_h *w) { free (w); } + +static void +set_error_buf (struct wrap_internal_h *w, + char *buf, int errnum, const char *func) +{ + free (w->error); + w->error = buf; + w->errnum = errnum; + + /* 'func' is always statically allocated, since it comes from + * C99 __func__, so this is safe. + */ + if (STRPREFIX (func, "impl_")) + func += 5; + else if (STRPREFIX (func, "wrap_")) + func += 5; + w->error_func = func; + + /* XXX This will be conditional on the user setting an error handler. */ + fprintf (stderr, "wrappi: %s: %s\n", func, buf); +} + +void +wrap_int_set_error (struct wrap_internal_h *w, + const char *func, + const char *fs, ...) +{ + va_list args; + char *msg; + int err; + + va_start (args, fs); + err = vasprintf (&msg, fs, args); + va_end (args); + + if (err < 0) return; + + set_error_buf (w, msg, 0, func); +} + +void +wrap_int_set_error_errno (struct wrap_internal_h *w, + int errnum, + const char *func, + const char *fs, ...) +{ + va_list args; + char *msg; + int err; + + va_start (args, fs); + err = vasprintf (&msg, fs, args); + va_end (args); + + if (err < 0) return; + + set_error_buf (w, msg, errnum, func); +} -- 1.8.3.1