/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
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;
>>
(*
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" ]
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
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
remote_SOURCES = remote.c
remote_CFLAGS = -I../lib
remote_LDADD = ../lib/libwrappi.la
+
+CLEANFILES = *~
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 () =
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;
| 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
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)
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 = {
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;
(* A return type. *)
rtype: [
[ "void" -> <:expr< Wrappi_types.RVoid >> ]
+ | [ "static_string" -> <:expr< Wrappi_types.RStaticString >> ]
| [ t = ptype -> <:expr< Wrappi_types.Return $t$ >> ]
];
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. *)
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 (
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 <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
";
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 =
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";
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
/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
libwrappi_la_SOURCES = \
wrappi.h \
wrappi.c \
+ connect.c \
$(local_implementation_files) \
$(remote_implementation_files)
+libwrappi_la_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
+
+CLEANFILES = *~
--- /dev/null
+/* 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#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 */
+}
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 \
#ifndef WRAPPI_INTERNAL_H_
#define WRAPPI_INTERNAL_H_
+#include <string.h>
+#include <errno.h>
+
+#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_ */
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include "wrappi.h"
-
#include "internal.h"
wrap_h *
{
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);
+}