pax_global_header00006660000000000000000000000064122170435620014514gustar00rootroot0000000000000052 comment=e45758aa9384b9740ff021ea952399fd113eb0e9 flux/000077500000000000000000000000001221704356200120365ustar00rootroot00000000000000flux/AUTHORS000066400000000000000000000001141221704356200131020ustar00rootroot00000000000000Denis Oliver Kropp Andreas Shimokawa flux/ChangeLog000066400000000000000000000437271221704356200136250ustar00rootroot00000000000000commit 31d972db1acc7d4366ca4f444cf0a0e269c54b2c Author: Andreas Shimokawa Date: Fri Jul 5 16:56:59 2013 +0200 update copyright headers commit fc92cf61051d3fd091602da67af7f9fff8f9fc1c Merge: 9062937 d3086b8 Author: Denis Oliver Kropp Date: Tue May 21 01:53:45 2013 +0200 Merge branch 'master' of git+ssh://git.directfb.org/git/directfb/core/flux commit 90629372ff74dc17f8aa76734c37883825c418dd Author: Denis Oliver Kropp Date: Tue May 21 01:53:14 2013 +0200 fluxcomp: add note to generated file that the file was generated by flux commit d3086b8e39aaddd5302de6ce16cdc300ffd3ac75 Author: Andreas Shimokawa Date: Mon Apr 15 18:28:32 2013 +0200 change version to 1.4.4 commit 6056f2a94acb380b34f637fb98b1434d5f82b2b5 Author: Denis Oliver Kropp Date: Fri Apr 12 11:14:28 2013 +0200 fluxcomp: Add option --dispatch-error-abort to add D_BREAK when object lookup fails. commit ade35ab9a8dfc95cb7c7f97b0d2f25612f119a98 Author: Denis Oliver Kropp Date: Fri Apr 12 06:38:49 2013 +0200 fluxcomp: Allow core to be set in flux file. commit 34521ce0550389138656bdc11a3203c69c2566b0 Author: Denis Oliver Kropp Date: Fri Feb 22 12:15:44 2013 +0100 flux: Connect entities with their parent in parser, print method name when lookup fails. commit 1a07adc13b12b0068413ecb37320c50ec267ea54 Author: Marek Pikarski Date: Fri Feb 15 16:00:48 2013 +0100 flux: add forgotten sizeof of local struct for call message preparation commit 643f61087bb464d9b168373fde3dbfeb44212d1b Author: Marek Pikarski Date: Wed Feb 13 18:00:38 2013 +0100 flux: fix computation of records written to fusion call message commit 6705477e78b869c3790aa71a66a33ff6d272d18c Merge: b913e87 e904b3c Author: Marek Pikarski Date: Wed Feb 13 15:21:50 2013 +0100 Merge branch 'master' of git+ssh://git.directfb.org/git/directfb/core/flux commit b913e87b4e6905be0dc22140bfe800a35d0247bb Author: Marek Pikarski Date: Wed Feb 13 15:18:54 2013 +0100 flux: support "split" of arrays i.e. support a hint parameter gives to method arguments in .flux files. Enables i.e. to call FillRectangles(..., num=100000) without errors, and all 100000 rects are split into n FusionMessages each fitting into a FusionCallMessage buffer without causing an overflow. commit e904b3cfd667f3d1c7506d942e78c8626ef47e25 Author: Andreas Shimokawa Date: Wed Feb 13 11:25:05 2013 +0100 fix c mode commit a85ab71c422d23af3cdd4261acdfe07160efe170 Author: Andreas Shimokawa Date: Fri Jan 18 15:05:31 2013 +0100 update changelog commit d10258fc92eece837491ce9afe86aed44a42e0d6 Author: Denis Oliver Kropp Date: Fri Jan 11 22:45:50 2013 +0100 flux: add 'buffer' property to methods (valid when async+queue also set) Methods being marked with 'buffer' set to 'yes' will not cause an individual fusion call. Instead all buffered methods are appending to a local buffer that is "sent" to the master object via one fusion call (using num -1). This reduces overhead in libfusion and fusion.ko when lots of buffered calls are made, e.g. via CoreGraphicsState for rendering. commit e698ce0dbeda86e95ff49e8628c4eb8a8d522fee Author: Andreas Shimokawa Date: Thu Jan 10 18:44:33 2013 +0100 flux 1.4.3 commit 52d5e1be77f64440653213d8f556e1809c6cf71c Author: Denis Oliver Kropp Date: Thu Jan 10 14:55:06 2013 +0100 flux: fix leak introduced by error propagation on Dec 15th 2012 commit 2d142a3f293de3c48108f8b370664655aacf8012 Author: Denis Oliver Kropp Date: Thu Jan 3 03:29:29 2013 +0100 flux: Return result from calls that fail on server side. commit 4be3c6791b37fd3223d312db6cd8557e34bd286a Author: Denis Oliver Kropp Date: Wed Jan 2 02:07:47 2013 +0100 flux: Add default for --static-args-bytes to help. commit 83ad7900762adf86e0cfca76280a64e2f310bc5a Author: Denis Oliver Kropp Date: Wed Jan 2 02:05:03 2013 +0100 flux: Add missing '' to help. commit 98d388f4937edd68edeb95901ad1c3dc399d337f Author: Denis Oliver Kropp Date: Wed Jan 2 02:03:53 2013 +0100 flux: Add description of options in help. commit eeb59615b38fc5aaf3e84edbeafc2df3b56290d0 Author: Denis Oliver Kropp Date: Sat Dec 15 17:10:47 2012 +0100 flux: return errors from calls commit 080f970b6ac98f0f824a7ee8ae8aed0e1aa2d665 Author: Marek Pikarski Date: Mon Oct 22 13:38:02 2012 +0200 flux: fix potential memleak commit afdd61798313a84f0a0700731e41d81ce2144855 Author: Marek Pikarski Date: Thu Oct 11 16:59:58 2012 +0200 flux: use direct macros instead of direct functions (fixes rare compilation issues) commit d22c6931e0336c06e6b34ad249513702d40f38bc Merge: df0a8e4 8fd3efc Author: Denis Oliver Kropp Date: Mon Oct 8 20:36:21 2012 +0200 Merge branch 'master' of git+ssh://git.directfb.org/git/directfb/core/flux commit df0a8e407e13229e2722e7a8f4a3fb8629017c89 Author: Denis Oliver Kropp Date: Mon Oct 8 20:35:23 2012 +0200 flux: allow strings for --static-args-bytes option (1.4.2) commit 8fd3efc945d5370e76dbd97f904dd3888840fea1 Author: Andreas Shimokawa Date: Thu Sep 20 16:18:24 2012 +0200 update changelog commit 65e576eef6a624ea399e2b6a77313c97d6a6a61a Author: Andreas Shimokawa Date: Thu Sep 20 16:16:48 2012 +0200 version 1.4.2 commit 43a7f399ddc43212cac2e8e2cb8f74c1cc886467 Author: Denis Oliver Kropp Date: Sat Sep 15 16:02:17 2012 +0200 flux: Remove alloca() usage. Add --static-args-bytes= argument. Use direct_malloc/free() for bigger blocks. commit bdcb3c60acd682ce6f803da0820b30915a5d9fc4 Author: Denis Oliver Kropp Date: Thu Jun 14 18:17:23 2012 +0200 update ChangeLog commit 5c2dd79d43ad6027a870b358869d4dc519e76f34 Author: Denis Oliver Kropp Date: Wed Jun 6 23:30:52 2012 +0200 version: 1.4.1 commit 16d588254e54b457843a6fba5064784ec0548acb Author: Denis Oliver Kropp Date: Wed Jun 6 23:29:20 2012 +0200 flux: Handle multiple variable length output arrays properly. commit 96abe92e94b658b081afa8747a006ba681e7a599 Author: Denis Oliver Kropp Date: Mon Jun 4 22:10:15 2012 +0200 Flux: Fix multiple output array code. commit 2e427e334cdf8efbd8b32bc3b74606e5ad42b287 Author: Denis Oliver Kropp Date: Wed May 23 22:57:14 2012 +0200 fluxcomp: Add --object-ptrs option to add object pointers used to return objects. In addition to the object id, the master directly returns the shared memory address of the object. That way the slave does not need to lookup the object in the pool and we can convert all object pool skirmishs to mutexes! commit 8d59f18314b65422c2e28b1031d160994ad70ca6 Author: Andreas Shimokawa Date: Tue May 22 18:17:19 2012 +0200 update changelog commit 38e47f9e4be7ae2bcf368921c9c5d453f6f087d4 Author: Andreas Shimokawa Date: Tue May 22 18:16:25 2012 +0200 flux: increase version to 1.3.0 commit 2298fa4698b81f58b1f180840a1091b63bfbe932 Author: Andreas Shimokawa Date: Tue May 22 15:50:34 2012 +0200 fluxcomp: add option -V / --version-code to output a version code to stdout version code is MAJOR*1000000+MINOR*1000+MICRO commit bf4e2ea9b536b68f65e48c22728048627905793d Author: Andreas Shimokawa Date: Mon May 21 16:10:02 2012 +0200 fluxcomp: support optional output parameters commit e5e84a89e5a981c981ea96778b68492d2ae0dd03 Author: Denis Oliver Kropp Date: Thu Apr 5 12:48:35 2012 +0200 flux: fix missing semicolon commit de1fd95b8588e38979da0cbef4f5ad9acf07efdc Author: Andreas Shimokawa Date: Wed Apr 4 14:57:06 2012 +0200 fluxcomp: compile fix commit 01b96ee4bbbe0ca404e2848e3942cfde6313d247 Author: Andreas Shimokawa Date: Wed Apr 4 14:56:23 2012 +0200 generate Core_PopCalling() and Core_PushCalling() calls commit e795734fb28a707a21fdca85bb8c9a52c6ee1f0a Author: Andreas Shimokawa Date: Tue Apr 3 14:04:24 2012 +0200 fluxcomp: prepare for DirectFB-1.6 and DirectFB 1.4.17 The generated code now uses CoreDFB_CallMode() to determinate if calls should be direct, indirect or denied commit 01cd3b0f3d8ec1cf16fdd9e3cc35e535044c4c11 Author: Andreas Shimokawa Date: Tue Mar 20 15:51:37 2012 +0100 update ChangeLog commit 6e369b8690574d473b2b5a6db92cadc3041d7918 Author: Andreas Shimokawa Date: Tue Mar 20 14:39:06 2012 +0100 fluxcomp: increase version to 1.2.0 commit c0a5e9a3d9f2858ad9579c315bc49312e2e39bcd Author: Denis Oliver Kropp Date: Sun Nov 13 13:33:01 2011 +0100 Flux: Add property "queue" to methods, used with "async" it makes usage of FCEF_QUEUE. commit 4b0dc49ac6717c0fce0b07eece53b414d88ca33a Author: Denis Oliver Kropp Date: Sun Nov 13 10:41:45 2011 +0100 flux: Fix generated debug code for optional arguments. commit 860bd89b68a25de603fa4e8439018799404b2521 Author: Denis Oliver Kropp Date: Sun Oct 23 02:46:56 2011 +0200 Flux: Don't print errors in requestor functions that are not on flux/fusion layer. commit 800e0e8475e6bcbd765fdcdbfb7314844cc1a22a Author: Denis Oliver Kropp Date: Sun Oct 23 02:39:49 2011 +0200 Flux: Add simple input argument logging code generation. commit ed1df2d3a6c7bb523fb941f929ee3bd054bf075d Author: Denis Oliver Kropp Date: Sat Oct 22 23:09:02 2011 +0200 Flux: Allow usage of input argument for 'count' of an output argument. commit a9ce29b2b2e6a858c3a8998bb1d1482021c6c548 Author: Denis Oliver Kropp Date: Sat Oct 22 16:20:38 2011 +0200 Flux: Don't add direct shortcut calls when dispatch is different from object type. commit 3211a95544091244ce9866284d066fba1924c1a3 Author: Denis Oliver Kropp Date: Wed Oct 12 19:54:10 2011 +0200 Flux: Option --no-direct to drop shortcuts, 'dispatch' object property for interfaces With 'object' the local and remote object is defined, e.g. CoreWindow, but for non-shared objects, the 'dispatch' property changes the object on dispatcher side. commit edb991c0f6840e6b025e49925bbcf4e62a76c52f Author: Denis Oliver Kropp Date: Sat Oct 8 23:02:38 2011 +0200 Flux: Fix Method::ArgumentsOutputObjectCatch() as well commit d6d502ed59cfbc2df855339b6122effc9a61e70e Author: Denis Oliver Kropp Date: Sat Oct 8 22:02:47 2011 +0200 Flux: Fix Method::ArgumentsSizeReturn() from previous commit. commit c8d6c78553e9ad70d1b0764fcff5e0970a6020ba Author: Denis Oliver Kropp Date: Sat Oct 8 21:18:28 2011 +0200 Flux: Implement variable length array output args with new 'max' specifier. commit d7b4d522546f5675f568dd011122e727febc82aa Author: Andreas Shimokawa Date: Mon Sep 26 18:17:25 2011 +0200 change version to 1.1.0 commit 66ae11e60bd1ae2ad75204e5e1a76a78ebf6a3b8 Author: Denis Oliver Kropp Date: Sat Sep 24 13:04:04 2011 +0200 Flux: Add Core_Push/PopIdentity() calls when parameter "-i" is used. Move options and parsing into new FluxConfig object. commit eaa11776b07720d665f8d54c9eb1f6ba834c759c Author: Andreas Shimokawa Date: Thu Sep 22 16:56:51 2011 +0200 flux: build with libdirect if available commit 9b73c276557eeff2ec7182fdd3e970cee6255a5a Author: Andreas Shimokawa Date: Thu Sep 22 15:51:30 2011 +0200 flux: add changelog commit 6588579c368b85a91032ea3dcef7712f0632686e Author: Andreas Shimokawa Date: Thu Sep 22 15:46:00 2011 +0200 flux: add autofoo stuff commit 8c97bdb4020539c90e632c1cf07a8005d5aeeb5f Author: Andreas Shimokawa Date: Thu Sep 22 15:45:48 2011 +0200 flux: make libdirect optional commit c61d2180ea469aa2c6d14c39277b9b10d777c03f Author: Andreas Shimokawa Date: Thu Sep 22 15:17:26 2011 +0200 rename flux->src commit 2623d3516003e90cb0b24e2c9776ce763edab716 Author: Andreas Shimokawa Date: Tue Sep 20 13:00:50 2011 +0200 flux: remove workaround for c-mode (dummy data for fusion_call_execute3) Requires new linux-fusion commit 78899458988ab47ed805402db172022c722ab145 Author: Andreas Shimokawa Date: Mon Sep 19 18:55:44 2011 +0200 core: remove Dispatch class, use functions instead (even in C++ mode) This patch also adds _Deinit_Dispatch() calls which were missing before (fixes leaks) commit d244d2640cc3d73850dc0a431ca9fd3c12a43331 Author: Andreas Shimokawa Date: Thu Sep 15 14:24:45 2011 +0200 flux: added option --include-prefix= to fix build of external projects(e.g sawman) commit 7cd5d0ffbe22ad33ff5066f1b725d1fa4cffd722 Author: Andreas Shimokawa Date: Wed Sep 14 14:58:25 2011 +0200 build: fix out-of-tree builds commit 7c1ec2586048dff0f8a6e357605461019d619b73 Author: Andreas Shimokawa Date: Thu Sep 8 18:37:44 2011 +0200 fluxcomp: added semicolon to fix warning in generated C code commit aa272a05bb7203770f6069933ca3002073a44aae Author: Andreas Shimokawa Date: Thu Sep 8 18:21:38 2011 +0200 fluxcomp: added C mode for generation C instead of C++ commit 6273735d7c2fce16f578ab52da9a829e9b430498 Author: Andreas Shimokawa Date: Mon Sep 5 16:19:32 2011 +0200 build: set CXX=g++ for fluxcomp, to avoid the cross compiler from being used commit b4c8915ed373877c1b6b9b18b6195fd8aa148442 Author: Denis Oliver Kropp Date: Fri Jul 29 14:44:30 2011 +0200 Flux: Generate TypeName_GetID( ptr ) instead of ptr->object.id. commit 362367383001b932886301301275920721b2c086 Author: Denis Oliver Kropp Date: Wed Jul 6 12:50:55 2011 +0200 Flux: Check fusion_config->secure_fusion to use real interface in slaves as well when false. commit 6368c4c1ae4c39d7e67473c91660938aa96e46f2 Author: Denis Oliver Kropp Date: Wed Jul 6 11:30:11 2011 +0200 Flux: Added TODO for types/structs. commit c337d30d2652c55f32e1203bea9ff036ba16fb01 Author: Denis Oliver Kropp Date: Sat Jul 2 09:06:56 2011 +0200 Flux: Implement async calls, comments, reference passing, int/enum array input, optional arrays commit d5ce4f9fc45ed30865de996f93702bddbc2a5334 Author: Denis Oliver Kropp Date: Tue Jun 21 19:35:22 2011 +0200 Flux: Fix optional object passing commit 005e354fceec235edd9105b00565dc5dd918bd64 Author: Denis Oliver Kropp Date: Tue Jun 21 18:12:37 2011 +0200 Flux: Implement 'optional' flag, e.g. for FlipUpdate() with NULL region commit db7255265b1c9b5af02fc1b94fe6f7097774a918 Author: Denis Oliver Kropp Date: Mon Jun 20 22:05:57 2011 +0200 Flux: Implement variable sized array arguments, e.g. BatchBlit(rects,points,num) commit 30ea240d8e2b8a48526519575326ceef45886f7b Author: Denis Oliver Kropp Date: Mon May 16 21:51:24 2011 +0200 Flux: On successful dispatch of a request, copy inout arguments from request to return structure. commit 01bc50a5a66706133422651084b0e81569304fce Author: Denis Oliver Kropp Date: Mon May 16 21:39:10 2011 +0200 Flux: Add TODO file - Generate stub real implementation optionally in a serate file. - Generate proper cleanup code in case of multiple object lookups etc. commit 9ee53d9f4b115b48ae41ab97caa36e9c05c62150 Author: Denis Oliver Kropp Date: Mon May 16 21:28:01 2011 +0200 Flux: Few fixes for return values (struct,enums...) and inout arguments. commit 93663bad789f002a24be564affbcda530d55f10d Author: Denis Oliver Kropp Date: Mon May 16 18:38:54 2011 +0200 Core: Use Flux to generate all code for hiding FusionCalls behind local/proxy interfaces. This is limited to CoreDFB and CoreWindow at the moment. The Flux compiler generates .cpp and .h containing abstract interface definition and two implementations, one generated 'requestor' implementation making FusionCalls and one 'real' implementation only being declared, implemented manually in _real.cpp file. Next to these there's code generated to dispatch incoming FusionCalls to the real implementation. A C wrapper is also generated for minimizing code changes outside of new files, but the new C++ API will be used in 1.6 branch, when Secure Fusion has stabilized in 1.5 branch. commit e61ba7b5ef17f28ba2741df997638432547deea3 Author: Denis Oliver Kropp Date: Mon May 16 18:31:09 2011 +0200 Flux: Introduce new language for interfaces, with parser/code generator. Input looks like this: interface { name IWindow version 1.0 object CoreWindow method { name Repaint arg { name left direction input type struct typename DFBRegion } arg { name right direction input type struct typename DFBRegion } arg { name flags direction input type enum typename DFBSurfaceFlipFlags } } method { name Restack arg { name relative direction input type object typename CoreWindow optional yes } arg { name relation direction input type int typename int } } ... flux/Makefile.am000066400000000000000000000000161221704356200140670ustar00rootroot00000000000000SUBDIRS = src flux/NEWS000066400000000000000000000000001221704356200125230ustar00rootroot00000000000000flux/README000066400000000000000000000002461221704356200127200ustar00rootroot00000000000000flux is an interface description language used by DirectFB fluxcomp compiles .flux files to .cpp or .c files You need this package when compiling DirectFB from git flux/TODO000066400000000000000000000013771221704356200125360ustar00rootroot00000000000000 - Only allow certain typenames for "int" type, e.g. u32, s32, u16... - Generate stub real implementation optionally in a separate file. - Generate proper cleanup code in case of multiple object lookups - Add async and queue flag a la Voodoo request flags Definition of structs for - endianness conversion - debugging purposes - serialisation E.g.: type { name DFBRectangle member { name x type s32 } member { name y type s32 } member { name width type s32 } member { name height type s32 } } Flux Environment / Runtime - make independent from CoreDFB - [make independent from Fusion] - support async returns foo->retained = Flux_RetainCall(); ... Flux_ReturnCall( foo->retained, ptr, length ); flux/autogen.sh000077500000000000000000000002031221704356200140320ustar00rootroot00000000000000#!/bin/sh echo "WARNING: You have called autogen.sh, use autoreconf -fi instead, I will do it for you this time :)" autoreconf -fi flux/configure.in000066400000000000000000000035171221704356200143550ustar00rootroot00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT(src/fluxcomp.cpp) AC_PREREQ(2.52) FLUXCOMP_MAJOR_VERSION=1 FLUXCOMP_MINOR_VERSION=4 FLUXCOMP_MICRO_VERSION=4 FLUXCOMP_INTERFACE_AGE=0 FLUXCOMP_BINARY_AGE=0 FLUXCOMP_VERSION=$FLUXCOMP_MAJOR_VERSION.$FLUXCOMP_MINOR_VERSION.$FLUXCOMP_MICRO_VERSION AC_SUBST(FLUXCOMP_MAJOR_VERSION) AC_SUBST(FLUXCOMP_MINOR_VERSION) AC_SUBST(FLUXCOMP_MICRO_VERSION) AC_SUBST(FLUXCOMP_INTERFACE_AGE) AC_SUBST(FLUXCOMP_BINARY_AGE) AC_SUBST(FLUXCOMP_VERSION) AC_DEFINE_UNQUOTED(FLUXCOMP_VERSION,"$FLUXCOMP_VERSION",[The fluxcomp version]) AC_DEFINE_UNQUOTED(FLUXCOMP_MAJOR_VERSION,$FLUXCOMP_MAJOR_VERSION,[The fluxcomp major version]) AC_DEFINE_UNQUOTED(FLUXCOMP_MINOR_VERSION,$FLUXCOMP_MINOR_VERSION,[The fluxcomp minor version]) AC_DEFINE_UNQUOTED(FLUXCOMP_MICRO_VERSION,$FLUXCOMP_MICRO_VERSION,[The fluxcomp micro version]) # libtool versioning LT_RELEASE=$FLUXCOMP_MAJOR_VERSION.$FLUXCOMP_MINOR_VERSION LT_CURRENT=`expr $FLUXCOMP_MICRO_VERSION - $FLUXCOMP_INTERFACE_AGE` LT_REVISION=$FLUXCOMP_INTERFACE_AGE LT_AGE=`expr $FLUXCOMP_BINARY_AGE - $FLUXCOMP_INTERFACE_AGE` AC_SUBST(LT_RELEASE) AC_SUBST(LT_CURRENT) AC_SUBST(LT_REVISION) AC_SUBST(LT_AGE) # For automake. VERSION=$FLUXCOMP_VERSION PACKAGE=flux AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE AC_DISABLE_STATIC AM_PROG_LIBTOOL AM_SANITY_CHECK AC_ISC_POSIX AM_PROG_CC_STDC AC_PROG_INSTALL AC_PROG_MAKE_SET AC_HEADER_STDC AC_PROG_CPP AC_PROG_CXX PKG_CHECK_MODULES([libdirect], [direct], [enable_libdirect="yes"], [enable_libdirect="no" AC_MSG_WARN([*** libdirect not found -- building without libdirect, debug output will be disabled])]) if test "$enable_libdirect" = "yes"; then AC_DEFINE(USE_LIBDIRECT,1,[Define to 1 if you are compiling with libdirect.]) fi AC_OUTPUT([ Makefile src/Makefile ]) flux/src/000077500000000000000000000000001221704356200126255ustar00rootroot00000000000000flux/src/.gitignore000066400000000000000000000000111221704356200146050ustar00rootroot00000000000000fluxcomp flux/src/Makefile.am000066400000000000000000000004331221704356200146610ustar00rootroot00000000000000## Makefile.am for DirectFB/flux INCLUDES = \ -I$(top_builddir)/lib \ -I$(top_builddir)/include \ -I$(top_srcdir)/include \ -I$(top_srcdir)/lib \ @libdirect_CFLAGS@ bin_PROGRAMS = \ fluxcomp libdirect = fluxcomp_SOURCES = fluxcomp.cpp fluxcomp_LDADD = @libdirect_LIBS@ flux/src/TODO000066400000000000000000000010461221704356200133160ustar00rootroot00000000000000 - Only allow certain typenames for "int" type, e.g. u32, s32, u16... - Generate stub real implementation optionally in a separate file. - Generate proper cleanup code in case of multiple object lookups - Add async and queue flag a la Voodoo request flags Definition of structs for - endianness conversion - debugging purposes - serialisation E.g.: type { name DFBRectangle member { name x type s32 } member { name y type s32 } member { name width type s32 } member { name height type s32 } } flux/src/fluxcomp.cpp000066400000000000000000003166611221704356200152030ustar00rootroot00000000000000/* (c) Copyright 2012-2013 DirectFB integrated media GmbH (c) Copyright 2001-2013 The world wide DirectFB Open Source Community (directfb.org) (c) Copyright 2000-2004 Convergence (integrated media) GmbH All rights reserved. Written by Denis Oliver Kropp , Andreas Shimokawa , Marek Pikarski , Sven Neumann , Ville Syrjälä and Claudio Ciccani . This file is subject to the terms and conditions of the MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ //#define DIRECT_ENABLE_DEBUG #include #include #include #include #include extern "C" { #include #include #include #include #include #include #include #include #ifdef USE_LIBDIRECT #include #include #include #include #include #include #include #endif } #ifdef USE_LIBDIRECT D_DEBUG_DOMAIN( fluxcomp, "fluxcomp", "Flux Compression Tool" ); #define FLUX_D_DEBUG_AT(x...) D_DEBUG_AT(x); #else /* fake macros */ #define FLUX_D_DEBUG_AT(x...) #define D_ASSERT(x...) #define D_PERROR(x...) #define D_WARN(x...) \ do { \ printf( x ); \ printf( "\n" ); \ sleep(5); \ } while (0) #define D_UNIMPLEMENTED(x...) #define DR_OK 0 #define DR_FAILURE 1 /* fake types */ typedef int DirectResult; /* fake functions */ DirectResult errno2result( int erno ) { if (!errno) return DR_OK; return DR_FAILURE; } void direct_initialize() {}; void direct_shutdown() {}; void direct_print_memleaks() {}; #define direct_log_printf(x...) #endif /**********************************************************************************************************************/ static const char *license = "/*\n" " (c) Copyright 2012-2013 DirectFB integrated media GmbH\n" " (c) Copyright 2001-2013 The world wide DirectFB Open Source Community (directfb.org)\n" " (c) Copyright 2000-2004 Convergence (integrated media) GmbH\n" "\n" " All rights reserved.\n" "\n" " Written by Denis Oliver Kropp ,\n" " Andreas Shimokawa ,\n" " Marek Pikarski ,\n" " Sven Neumann ,\n" " Ville Syrjälä and\n" " Claudio Ciccani .\n" "\n" " This library is free software; you can redistribute it and/or\n" " modify it under the terms of the GNU Lesser General Public\n" " License as published by the Free Software Foundation; either\n" " version 2 of the License, or (at your option) any later version.\n" "\n" " This library is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" " Lesser General Public License for more details.\n" "\n" " You should have received a copy of the GNU Lesser General Public\n" " License along with this library; if not, write to the\n" " Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n" " Boston, MA 02111-1307, USA.\n" "*/\n"; static const char *filename; /**********************************************************************************************************************/ class FluxConfig { public: bool c_mode; bool identity; std::string include_prefix; bool no_direct; bool call_mode; bool object_ptrs; std::string static_args_bytes; bool dispatch_error_abort; std::string output_dir; public: FluxConfig() : c_mode( false ), identity( false ), no_direct( false ), call_mode( false ), object_ptrs( false ), static_args_bytes( "1000" ), dispatch_error_abort( false ), output_dir("") { } bool parse_command_line( int argc, char *argv[] ) { int n; for (n = 1; n < argc; n++) { const char *arg = argv[n]; if (strcmp (arg, "-h") == 0 || strcmp (arg, "--help") == 0) { print_usage( argv[0] ); return false; } if (strcmp (arg, "-v") == 0 || strcmp (arg, "--version") == 0) { fprintf( stderr, "fluxcomp version %s\n", FLUXCOMP_VERSION ); return false; } if (strcmp (arg, "-V") == 0 || strcmp (arg, "--version-code") == 0) { fprintf( stdout, "%d", FLUXCOMP_MAJOR_VERSION*1000000 + FLUXCOMP_MINOR_VERSION*1000 + FLUXCOMP_MICRO_VERSION ); return false; } if (strcmp (arg, "-c") == 0 || strcmp (arg, "--generate-c") == 0) { c_mode = true; continue; } if (strcmp (arg, "-i") == 0 || strcmp (arg, "--identity") == 0) { identity = true; continue; } if (strcmp (arg, "--object-ptrs") == 0) { object_ptrs = true; continue; } if (strcmp (arg, "--no-direct") == 0) { no_direct = true; continue; } if (strcmp (arg, "--call-mode") == 0) { call_mode = true; continue; } if (strncmp (arg, "-p=",3) == 0) { include_prefix = std::string(&arg[3]); continue; } if (strncmp (arg, "--include-prefix=", 17) == 0) { include_prefix = std::string(&arg[17]); continue; } if (strncmp (arg, "--static-args-bytes=", 20) == 0) { static_args_bytes = &arg[20]; continue; } if (strcmp (arg, "--dispatch-error-abort") == 0) { dispatch_error_abort = true; continue; } if (strncmp (arg, "-o=", 3) == 0) { output_dir = std::string(&arg[3]) + "/"; continue; } if (filename || access( arg, R_OK )) { print_usage( argv[0] ); return false; } filename = arg; } if (!filename) { print_usage (argv[0]); return false; } return true; } void print_usage( const char *prg_name ) { fprintf( stderr, "\nFlux Compiler Tool (version %s)\n\n", FLUXCOMP_VERSION ); fprintf( stderr, "Usage: %s [options] \n\n", prg_name ); fprintf( stderr, "Options:\n" ); fprintf( stderr, " -h, --help Show this help message\n" ); fprintf( stderr, " -v, --version Print version information\n" ); fprintf( stderr, " -V, --version-code Output version code to stdout\n" ); fprintf( stderr, " -c, --generate-c Generate C instead of C++ code\n" ); fprintf( stderr, " -i, --identity Generate caller identity tracking code\n" ); fprintf( stderr, " --object-ptrs Return object pointers rather than IDs\n" ); fprintf( stderr, " --call-mode Use call mode function to determine call mode\n" ); fprintf( stderr, " -p=, --include-prefix= Override standard include prefix for includes\n" ); fprintf( stderr, " --static-args-bytes= Override standard limit (1000) for stack based arguments\n" ); fprintf( stderr, " --dispatch-error-abort Abort execution when object lookups etc fail\n" ); fprintf( stderr, " -o= write to output directory\n" ); fprintf( stderr, "\n" ); } }; /**********************************************************************************************************************/ class Entity { public: Entity( Entity *parent ) : parent( parent ) { } typedef std::list list; typedef std::vector vector; typedef enum { ENTITY_NONE, ENTITY_INTERFACE, ENTITY_METHOD, ENTITY_ARG } Type; virtual Type GetType() const = 0; virtual void Dump() const; virtual void SetProperty( const std::string &name, const std::string &value ); private: const char *buf; size_t length; public: Entity::vector entities; Entity *parent; void Open( const char *buf ) { this->buf = buf; } void Close( size_t length ) { this->length = length; GetEntities( buf, length, entities, this ); } static void GetEntities( const char *buf, size_t length, Entity::vector &out_vector, Entity *parent ); static DirectResult GetEntities( const char *filename, Entity::vector &out_vector ); }; class Interface : public Entity { public: Interface( Entity *parent ) : Entity( parent ), buffered( false ), core( "CoreDFB" ) { } virtual Type GetType() const { return ENTITY_INTERFACE; } virtual void Dump() const; virtual void SetProperty( const std::string &name, const std::string &value ); std::string name; std::string version; std::string object; std::string dispatch; bool buffered; std::string core; }; class Method : public Entity { public: Method( Entity *parent ) : Entity( parent ), indirect( false ), async( false ), queue( false ), buffer( false ) { } virtual Type GetType() const { return ENTITY_METHOD; } virtual void Dump() const; virtual void SetProperty( const std::string &name, const std::string &value ); std::string name; bool indirect; bool async; bool queue; bool buffer; public: static std::string PrintParam( std::string string_buffer, std::string type, std::string ptr, std::string name, bool first ) { char buf[1000]; snprintf( buf, sizeof(buf), "%s %-40s %2s%s", first ? "" : ",\n", type.c_str(), ptr.c_str(), name.c_str() ); return string_buffer + buf; } static std::string PrintMember( std::string string_buffer, std::string type, std::string ptr, std::string name ) { char buf[1000]; snprintf( buf, sizeof(buf), " %-40s %2s%s;\n", type.c_str(), ptr.c_str(), name.c_str() ); return string_buffer + buf; } std::string ArgumentsAsParamDecl() const; std::string ArgumentsAsMemberDecl() const; std::string ArgumentsOutputAsMemberDecl( const FluxConfig &config ) const; std::string ArgumentsAsMemberParams() const; std::string ArgumentsInputAssignments() const; std::string ArgumentsOutputAssignments() const; std::string ArgumentsAssertions() const; std::string ArgumentsOutputObjectDecl() const; std::string ArgumentsOutputTmpDecl() const; std::string ArgumentsInputObjectDecl() const; std::string ArgumentsOutputObjectCatch( const FluxConfig &config ) const; std::string ArgumentsOutputObjectThrow( const FluxConfig &config ) const; std::string ArgumentsInoutReturn() const; std::string ArgumentsOutputTmpReturn() const; std::string ArgumentsInputObjectLookup( const FluxConfig &config ) const; std::string ArgumentsInputObjectUnref() const; std::string ArgumentsInputDebug( const FluxConfig &config, const Interface *face ) const; std::string ArgumentsNames() const; std::string ArgumentsSize( const Interface *face, bool output ) const; std::string ArgumentsSizeReturn( const Interface *face ) const; std::string OpenSplitArgumentsIfRequired() const; std::string CloseSplitArgumentsIfRequired() const; }; class Arg : public Entity { public: Arg( Entity *parent ) : Entity( parent ), optional( false ), array( false ), split( false ) { } virtual Type GetType() const { return ENTITY_ARG; } virtual void Dump() const; virtual void SetProperty( const std::string &name, const std::string &value ); std::string name; std::string direction; std::string type; std::string type_name; bool optional; bool array; std::string count; std::string max; bool split; public: std::string param_name() const { if (direction == "output") return std::string("ret_") + name; return name; } std::string formatCharacter() const { if (type == "int") { if (type_name == "u8" || type_name == "u16" || type_name == "u32") return "u"; if (type_name == "s8" || type_name == "s16" || type_name == "s32") return "d"; if (type_name == "u64") return "llu"; if (type_name == "s64") return "lld"; if (type_name == "void*") return "p"; D_WARN( "unrecognized integer type '%s'", type_name.c_str() ); return "lu"; } if (type == "enum") return "x"; D_WARN( "unsupported type '%s'", type.c_str() ); D_UNIMPLEMENTED(); return "x"; } std::string typeCast() const { if (type == "int") { if (type_name == "u64") return "(unsigned long long) "; if (type_name == "s64") return "(long long) "; return ""; } return ""; } std::string size( bool use_args ) const { if (array) { if (use_args) return std::string("args->") + count + " * sizeof(" + type_name + ")"; else return (split ? std::string( "num_records" ) : count) + " * sizeof(" + type_name + ")"; } return std::string("sizeof(") + type_name + ")"; } std::string sizeReturn( const Method *method ) const { if (array) { /* Lookup 'count' argument */ for (Entity::vector::const_iterator iter = method->entities.begin(); iter != method->entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->name == count) { if (arg->direction == "input") return std::string("args->") + count + " * sizeof(" + type_name + ")"; return std::string("return_args->") + count + " * sizeof(" + type_name + ")"; } } } return std::string("sizeof(") + type_name + ")"; } std::string sizeMax( bool use_args ) const { if (array) { if (use_args) return std::string("args->") + max + " * sizeof(" + type_name + ")"; else return max + " * sizeof(" + type_name + ")"; } return std::string("sizeof(") + type_name + ")"; } std::string offset( const Method *method, bool use_args, bool output ) const { D_ASSERT( array == true ); std::string result; for (Entity::vector::const_iterator iter = method->entities.begin(); iter != method->entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg == this) break; if (output) { if (arg->direction == "output" || arg->direction == "inout") result += std::string(" + return_args->") + arg->size( false ); } else { if (arg->direction == "input") result += std::string(" + ") + arg->size( use_args ); } } return result; } }; /**********************************************************************************************************************/ void Entity::Dump() const { direct_log_printf( NULL, "\n" ); direct_log_printf( NULL, "Entity (TYPE %d)\n", GetType() ); direct_log_printf( NULL, " Buffer at %p [%zu]\n", buf, length ); } void Interface::Dump() const { Entity::Dump(); direct_log_printf( NULL, " Name %s\n", name.c_str() ); direct_log_printf( NULL, " Version %s\n", version.c_str() ); direct_log_printf( NULL, " Object %s\n", object.c_str() ); direct_log_printf( NULL, " Dispatch %s\n", dispatch.c_str() ); } void Method::Dump() const { Entity::Dump(); direct_log_printf( NULL, " Name %s\n", name.c_str() ); } void Arg::Dump() const { Entity::Dump(); direct_log_printf( NULL, " Name %s\n", name.c_str() ); direct_log_printf( NULL, " Direction %s\n", direction.c_str() ); direct_log_printf( NULL, " Type %s\n", type.c_str() ); direct_log_printf( NULL, " Typename %s\n", type_name.c_str() ); } /**********************************************************************************************************************/ void Entity::SetProperty( const std::string &name, const std::string &value ) { } void Interface::SetProperty( const std::string &name, const std::string &value ) { if (name == "name") { this->name = value; return; } if (name == "version") { version = value; return; } if (name == "object") { object = value; dispatch = value; return; } if (name == "dispatch") { dispatch = value; return; } if (name == "core") { core = value; return; } } void Method::SetProperty( const std::string &name, const std::string &value ) { if (name == "name") { this->name = value; return; } if (name == "indirect") { indirect = value == "yes"; return; } if (name == "async") { async = value == "yes"; return; } if (name == "queue") { queue = value == "yes"; return; } if (name == "buffer") { buffer = value == "yes"; return; } } void Arg::SetProperty( const std::string &name, const std::string &value ) { if (name == "name") { this->name = value; return; } if (name == "direction") { direction = value; return; } if (name == "type") { type = value; return; } if (name == "typename") { type_name = value; return; } if (name == "optional") { optional = value == "yes"; return; } if (name == "count") { array = true; count = value; return; } if (name == "max") { max = value; return; } if (name == "split" && value == "yes") { split = true; return; } } /**********************************************************************************************************************/ void Entity::GetEntities( const char *buf, size_t length, Entity::vector &out_vector, Entity *parent ) { size_t i; unsigned int level = 0; bool quote = false; bool comment = false; std::string name; std::map names; Entity *entity = NULL; FLUX_D_DEBUG_AT( fluxcomp, "%s( buf %p, length %zu )\n", __func__, buf, length ); for (i=0; i '%c' <-\n", level*2, "", level, buf[i] ); if (comment) { switch (buf[i]) { case '\n': comment = false; break; default: break; } } else if (quote) { switch (buf[i]) { // TODO: implement escaped quotes in strings case '"': quote = false; break; default: name += buf[i]; } } else { switch (buf[i]) { case '"': quote = true; break; case '#': comment = true; break; case '.': case '-': case '_': case 'a' ... 'z': case 'A' ... 'Z': case '0' ... '9': name += buf[i]; break; default: if (!name.empty()) { FLUX_D_DEBUG_AT( fluxcomp, "%*s=-> name = '%s'\n", level*2, "", name.c_str() ); if (!names[level].empty()) { switch (level) { case 1: FLUX_D_DEBUG_AT( fluxcomp, "%*s#### setting property '%s' = '%s'\n", level*2, "", names[level].c_str(), name.c_str() ); D_ASSERT( entity != NULL ); entity->SetProperty( names[level], name ); break; default: break; } name = ""; } names[level] = name; name = ""; } switch (buf[i]) { case '{': case '}': switch (buf[i]) { case '{': switch (level) { case 0: if (names[level] == "interface") { D_ASSERT( entity == NULL ); entity = new Interface( parent ); entity->Open( &buf[i + 1] ); FLUX_D_DEBUG_AT( fluxcomp, "%*s#### open entity %p (Interface)\n", level*2, "", entity ); } if (names[level] == "method") { D_ASSERT( entity == NULL ); entity = new Method( parent ); entity->Open( &buf[i + 1] ); FLUX_D_DEBUG_AT( fluxcomp, "%*s#### open entity %p (Method)\n", level*2, "", entity ); } if (names[level] == "arg") { D_ASSERT( entity == NULL ); entity = new Arg( parent ); entity->Open( &buf[i + 1] ); FLUX_D_DEBUG_AT( fluxcomp, "%*s#### open entity %p (Arg)\n", level*2, "", entity ); } break; default: break; } names[level] = ""; level++; break; case '}': D_ASSERT( names[level].empty() ); level--; switch (level) { case 0: FLUX_D_DEBUG_AT( fluxcomp, "%*s#### close entity %p\n", level*2, "", entity ); D_ASSERT( entity != NULL ); entity->Close( &buf[i-1] - entity->buf ); out_vector.push_back( entity ); entity = NULL; break; case 1: break; default: break; } break; } FLUX_D_DEBUG_AT( fluxcomp, "%*s=-> level => %u\n", level*2, "", level ); break; case ' ': case '\t': case '\n': case '\r': break; default: break; } break; } } } } DirectResult Entity::GetEntities( const char *filename, Entity::vector &out_vector ) { int ret = DR_OK; int fd; struct stat stat; void *ptr = MAP_FAILED; /* Open the file. */ fd = open( filename, O_RDONLY ); if (fd < 0) { ret = errno2result( errno ); D_PERROR( "GetEntities: Failure during open() of '%s'!\n", filename ); return (DirectResult) ret; } /* Query file size etc. */ if (fstat( fd, &stat ) < 0) { ret = errno2result( errno ); D_PERROR( "GetEntities: Failure during fstat() of '%s'!\n", filename ); goto out; } /* Memory map the file. */ ptr = mmap( NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if (ptr == MAP_FAILED) { ret = errno2result( errno ); D_PERROR( "GetEntities: Failure during mmap() of '%s'!\n", filename ); goto out; } Entity::GetEntities( (const char*) ptr, stat.st_size, out_vector, NULL ); out: if (ptr != MAP_FAILED) munmap( ptr, stat.st_size ); close( fd ); return (DirectResult) ret; } /**********************************************************************************************************************/ std::string Method::ArgumentsAsParamDecl() const { std::string result; bool first = true; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "struct") { if (arg->direction == "input") result = PrintParam( result, std::string("const ") + arg->type_name, "*", arg->param_name(), first ); else result = PrintParam( result, arg->type_name, "*", arg->param_name(), first ); } else if (arg->type == "enum" || arg->type == "int") { if (arg->direction == "input") { if (arg->array) result = PrintParam( result, std::string("const ") + arg->type_name, "*", arg->param_name(), first ); else result = PrintParam( result, arg->type_name, "", arg->param_name(), first ); } else result = PrintParam( result, arg->type_name, "*", arg->param_name(), first ); } else if (arg->type == "object") { if (arg->direction == "input") result = PrintParam( result, arg->type_name, "*", arg->param_name(), first ); else result = PrintParam( result, arg->type_name, "**", arg->param_name(), first ); } if (first) first = false; } return result; } std::string Method::ArgumentsAsMemberDecl() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result = PrintMember( result, "bool", "", arg->name + "_set" ); if (arg->type == "struct") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "enum") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "int") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "object") result = PrintMember( result, "u32", "", arg->name + "_id" ); } } for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { char buf[300]; const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result = PrintMember( result, "bool", "", arg->name + "_set" ); snprintf( buf, sizeof(buf), " /* '%s' %s follow (%s) */\n", arg->count.c_str(), arg->type_name.c_str(), arg->name.c_str() ); result += buf; } } return result; } std::string Method::ArgumentsOutputAsMemberDecl( const FluxConfig &config ) const { std::string result; result = PrintMember( result, "DFBResult", "", "result" ); for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" || arg->direction == "inout") { if (arg->type == "struct") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "enum") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "int") result = PrintMember( result, arg->type_name, "", arg->name ); else if (arg->type == "object") { result = PrintMember( result, "u32", "", arg->name + "_id" ); if (config.object_ptrs) result = PrintMember( result, "void*", "", arg->name + "_ptr" ); } } } for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { char buf[300]; const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" || arg->direction == "inout") { if (arg->optional) result = PrintMember( result, "bool", "", arg->name + "_set" ); snprintf( buf, sizeof(buf), " /* '%s' %s follow (%s) */\n", arg->count.c_str(), arg->type_name.c_str(), arg->name.c_str() ); result += buf; } } return result; } std::string Method::ArgumentsAsMemberParams() const { std::string result; bool first = true; bool second_output_array = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (first) first = false; else result += ", "; if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result += std::string("args->") + arg->name + "_set ? "; if (arg->array) { if (arg->type == "struct" || arg->type == "enum" || arg->type == "int") result += std::string("(") + arg->type_name + "*) ((char*)(args + 1)" + arg->offset( this, true, false ) + ")"; else if (arg->type == "object") D_UNIMPLEMENTED(); } else { if (arg->type == "struct") result += std::string("&args->") + arg->name; else if (arg->type == "enum") result += std::string("args->") + arg->name; else if (arg->type == "int") result += std::string("args->") + arg->name; else if (arg->type == "object") result += arg->name; } if (arg->optional) result += std::string(" : NULL"); } if (arg->direction == "output") { if (arg->optional) D_UNIMPLEMENTED(); if (arg->array) { if (second_output_array) { result += "tmp_" + arg->name; } else { if (arg->type == "struct" || arg->type == "enum" || arg->type == "int") result += std::string("(") + arg->type_name + "*) ((char*)(return_args + 1)" + arg->offset( this, true, true ) + ")"; else if (arg->type == "object") D_UNIMPLEMENTED(); second_output_array = true; } } else { if (arg->type == "struct") result += std::string("&return_args->") + arg->name; else if (arg->type == "enum") result += std::string("&return_args->") + arg->name; else if (arg->type == "int") result += std::string("&return_args->") + arg->name; else if (arg->type == "object") result += std::string("&") + arg->name; } } } return result; } std::string Method::ArgumentsInputAssignments() const { std::string result; bool split = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->split) { split = true; break; } } for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result += std::string(" if (") + arg->name + ") {\n"; if (arg->type == "struct") result += std::string(" args->") + arg->name + " = *" + arg->name + ";\n"; else if (arg->type == "enum") result += std::string(" args->") + arg->name + " = " + arg->name + ";\n"; else if (arg->type == "int") result += std::string(" args->") + arg->name + " = " + (split ? (arg->name == "num" ? std::string( "num_records" ) : arg->name) : arg->name) + ";\n"; else if (arg->type == "object") result += std::string(" args->") + arg->name + "_id = " + arg->type_name + "_GetID( " + arg->name + " );\n"; if (arg->optional) { result += std::string(" args->") + arg->name + "_set = true;\n"; result += std::string(" }\n"); result += std::string(" else\n"); result += std::string(" args->") + arg->name + "_set = false;\n"; } } } for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result += std::string(" if (") + arg->name + ") {\n"; if (arg->type == "struct" || arg->type == "enum" || arg->type == "int") result += std::string(" direct_memcpy( (char*) (args + 1)") + arg->offset( this, false, false ) + ", " + arg->name + ", " + arg->size( false ) + " );\n"; else if (arg->type == "object") D_UNIMPLEMENTED(); if (arg->optional) { result += std::string(" args->") + arg->name + "_set = true;\n"; result += std::string(" }\n"); result += std::string(" else {\n"); result += std::string(" args->") + arg->name + "_set = false;\n"; result += std::string(" ") + arg->name + " = 0;\n"; // FIXME: this sets num to 0 to avoid dispatch errors, but what if num is before this? result += std::string(" }\n"); } } } return result; } std::string Method::ArgumentsOutputAssignments() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" || arg->direction == "inout") { if (arg->type == "struct" || arg->type == "enum" || arg->type == "int") { if (arg->optional) result += std::string(" if (") + arg->param_name() + ")\n"; result += std::string( arg->optional ? " *" : " *") + arg->param_name() + " = return_args->" + arg->name + ";\n"; } } } for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" || arg->direction == "inout") { if (arg->optional) D_UNIMPLEMENTED(); if (arg->type == "struct" || arg->type == "enum" || arg->type == "int") result += std::string(" direct_memcpy( ret_") + arg->name + ", (char*) (return_args + 1)" + arg->offset( this, false, true ) + ", " + arg->sizeReturn( this ) + " );\n"; else if (arg->type == "object") D_UNIMPLEMENTED(); } } return result; } std::string Method::OpenSplitArgumentsIfRequired() const { std::string result; std::string record_sizes; int split = 0; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->split) { if (split) record_sizes += std::string( " + " ); record_sizes += std::string( "sizeof(" ) + arg->type_name + std::string( ")" ); split++; } } if (!split) return result; result += std::string( "const u32 record_size = " ) + record_sizes + std::string( ";\n" ); result += std::string( "const u32 max_records = " ) + std::string( "CALLBUFFER_FUSION_MESSAGE_SIZE / record_size;\n" ); result += std::string( "for (u32 i = 0; i < num; i+= max_records) {\n" ); result += std::string( " const u32 num_records = num > max_records ? max_records : num;\n" ); return result; } std::string Method::CloseSplitArgumentsIfRequired() const { std::string result; bool split = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->split) { split = true; break; } } if (split) result += "}"; return result; } std::string Method::ArgumentsAssertions() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if ((arg->type == "struct" || arg->type == "object") && !arg->optional) result += std::string(" D_ASSERT( ") + arg->param_name() + " != NULL );\n"; } return result; } std::string Method::ArgumentsOutputObjectDecl() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "output") result += std::string(" ") + arg->type_name + " *" + arg->name + " = NULL;\n"; } return result; } std::string Method::ArgumentsOutputTmpDecl() const { std::string result; bool second = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" && arg->array) { if (second) result += std::string(" ") + arg->type_name + " tmp_" + arg->name + "[" + arg->max + "];\n"; else second = true; } } return result; } std::string Method::ArgumentsInputObjectDecl() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "input") result += std::string(" ") + arg->type_name + " *" + arg->name + " = NULL;\n"; } return result; } std::string Method::ArgumentsOutputObjectCatch( const FluxConfig &config ) const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "output") { char buf[1000]; snprintf( buf, sizeof(buf), " ret = (DFBResult) %s_Catch( %s, return_args->%s%s, &%s );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s: Catching %s by ID %%u failed!\\n\", __FUNCTION__, return_args->%s_id );\n" " goto out;\n" " }\n" "\n" " *%s = %s;\n" "\n", arg->type_name.c_str(), config.c_mode ? "core_dfb" : "core", arg->name.c_str(), config.object_ptrs ? "_ptr" : "_id", arg->name.c_str(), arg->name.c_str(), arg->name.c_str(), arg->param_name().c_str(), arg->name.c_str() ); result += buf; } } return result; } std::string Method::ArgumentsOutputObjectThrow( const FluxConfig &config ) const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "output") { char buf[1000]; snprintf( buf, sizeof(buf), " %s_Throw( %s, caller, &return_args->%s_id );\n", arg->type_name.c_str(), arg->name.c_str(), arg->name.c_str() ); result += buf; if (config.object_ptrs) { snprintf( buf, sizeof(buf), " return_args->%s_ptr = (void*) %s;\n", arg->name.c_str(), arg->name.c_str() ); result += buf; } } } return result; } std::string Method::ArgumentsInoutReturn() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "inout") { char buf[1000]; snprintf( buf, sizeof(buf), " return_args->%s = args->%s;\n", arg->name.c_str(), arg->name.c_str() ); result += buf; } } return result; } std::string Method::ArgumentsOutputTmpReturn() const { std::string result; bool second_output_array = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" && arg->array) { if (second_output_array) { char buf[1000]; std::string dst = std::string("(char*) ((char*)(return_args + 1)") + arg->offset( this, true, true ) + ")"; snprintf( buf, sizeof(buf), " direct_memcpy( %s, tmp_%s, return_args->%s_size );\n", dst.c_str(), arg->name.c_str(), arg->name.c_str() ); result += buf; } else second_output_array = true; } } return result; } std::string Method::ArgumentsInputObjectLookup( const FluxConfig &config ) const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "input") { char buf[1000]; if (arg->optional) { snprintf( buf, sizeof(buf), " if (args->%s_set) {\n" " ret = (DFBResult) %s_Lookup( core_dfb, args->%s_id, caller, &%s );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s(%s): Looking up %s by ID %%u failed!\\n\", __FUNCTION__, args->%s_id );\n" "%s" "%s" " return ret;\n" " }\n" " }\n" "\n", arg->name.c_str(), arg->type_name.c_str(), arg->name.c_str(), arg->name.c_str(), name.c_str(), arg->name.c_str(), arg->name.c_str(), async ? "" : " return_args->result = ret;\n", config.dispatch_error_abort ? " D_BREAK( \"could not lookup object\" );\n" : "" ); } else { snprintf( buf, sizeof(buf), " ret = (DFBResult) %s_Lookup( core_dfb, args->%s_id, caller, &%s );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s(%s): Looking up %s by ID %%u failed!\\n\", __FUNCTION__, args->%s_id );\n" "%s" "%s" " return ret;\n" " }\n" "\n", arg->type_name.c_str(), arg->name.c_str(), arg->name.c_str(), name.c_str(), arg->name.c_str(), arg->name.c_str(), async ? "" : " return_args->result = ret;\n", config.dispatch_error_abort ? " D_BREAK( \"could not lookup object\" );\n" : "" ); } result += buf; } } return result; } std::string Method::ArgumentsInputDebug( const FluxConfig &config, const Interface *face ) const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "input" || arg->direction == "inout") { if (arg->optional) result += std::string(" if (args->") + arg->name + "_set)\n"; if (arg->type == "struct") result += std::string(" ; // TODO: ") + arg->type_name + "_debug args->" + arg->name + ";\n"; else if (arg->type == "object") { char buf[1000]; snprintf( buf, sizeof(buf), " D_DEBUG_AT( DirectFB_%s, \" -> %s = %%d\\n\", args->%s_id );\n", face->object.c_str(), arg->name.c_str(), arg->name.c_str() ); result += buf; } else if (arg->type == "enum" || arg->type == "int") { char buf[1000]; snprintf( buf, sizeof(buf), " D_DEBUG_AT( DirectFB_%s, \" -> %s = %%%s\\n\", %sargs->%s );\n", face->object.c_str(), arg->name.c_str(), arg->formatCharacter().c_str(), arg->typeCast().c_str(), arg->name.c_str() ); result += buf; } else result += std::string(" ; // TODO: ") + arg->type + " debug\n"; } } return result; } std::string Method::ArgumentsInputObjectUnref() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->type == "object" && arg->direction == "input") { char buf[1000]; snprintf( buf, sizeof(buf), " if (%s)\n" " %s_Unref( %s );\n" "\n", arg->name.c_str(), arg->type_name.c_str(), arg->name.c_str() ); result += buf; } } return result; } std::string Method::ArgumentsNames() const { std::string result; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); bool last = arg == entities[entities.size()-1]; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); result += arg->param_name(); if (!last) result += ", "; } return result; } std::string Method::ArgumentsSize( const Interface *face, bool output ) const { std::string result = "sizeof("; bool split = false; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (arg->split) { split = true; break; } } if (output) result += face->object + name + "Return)"; else result += face->object + name + ")"; if (split) return result += std::string( " + record_size * num_records" ); for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (output) { if (arg->direction == "output" || arg->direction == "inout") result += " + " + arg->sizeMax( false ); } else { if (arg->direction == "input" || arg->direction == "inout") result += " + " + arg->size( false ); } } return result; } std::string Method::ArgumentsSizeReturn( const Interface *face ) const { std::string result = "sizeof("; result += face->object + name + "Return)"; for (Entity::vector::const_iterator iter = entities.begin(); iter != entities.end(); iter++) { const Arg *arg = dynamic_cast( *iter ); if (!arg->array) continue; FLUX_D_DEBUG_AT( fluxcomp, "%s( %p )\n", __FUNCTION__, arg ); if (arg->direction == "output" || arg->direction == "inout") result += " + " + arg->sizeReturn( this ); } return result; } /**********************************************************************************************************************/ /**********************************************************************************************************************/ class FluxComp { public: void GenerateHeader( const Interface *face, const FluxConfig &config ); void GenerateSource( const Interface *face, const FluxConfig &config ); void PrintInterface( FILE *file, const Interface *face, const std::string &name, const std::string &super, bool abstract ); }; /**********************************************************************************************************************/ void FluxComp::GenerateHeader( const Interface *face, const FluxConfig &config ) { FILE *file; std::string filename = config.output_dir + face->object + ".h"; file = fopen( filename.c_str(), "w" ); if (!file) { D_PERROR( "FluxComp: fopen( '%s' ) failed!\n", filename.c_str() ); return; } fprintf( file, "/*\n" " * This file was automatically generated by fluxcomp; DO NOT EDIT!\n" " */\n" "%s\n" "#ifndef ___%s__H___\n" "#define ___%s__H___\n" "\n" "#include %s%s%s%s_includes.h%s\n" "\n" "/**********************************************************************************************************************\n" " * %s\n" " */\n" "\n" "#ifdef __cplusplus\n" "#include \n" "\n" "extern \"C\" {\n" "#endif\n" "\n" "\n", license, face->object.c_str(), face->object.c_str(), config.include_prefix.empty() ? "\"" : "<", config.include_prefix.c_str(), config.include_prefix.empty() ? "" : "/", face->object.c_str(), config.include_prefix.empty() ? "\"" : ">", face->object.c_str() ); /* C Wrappers */ for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); fprintf( file, "DFBResult %s_%s(\n" " %-40s *obj%s\n" "%s" ");\n" "\n", face->object.c_str(), method->name.c_str(), face->object.c_str(), method->entities.empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); } fprintf( file, "\n" "void %s_Init_Dispatch(\n" " %-20s *core,\n" " %-20s *obj,\n" " FusionCall *call\n" ");\n" "\n", face->object.c_str(), face->core.c_str(), face->dispatch.c_str() ); fprintf( file, "void %s_Deinit_Dispatch(\n" " FusionCall *call\n" ");\n" "\n", face->object.c_str() ); fprintf( file, "\n" "#ifdef __cplusplus\n" "}\n" "%s" "\n" "\n" "%s" "\n" "\n" "/*\n" " * %s Calls\n" " */\n" "typedef enum {\n", config.c_mode ? "#endif\n" : "", !config.c_mode ? "namespace DirectFB {\n" : "", face->object.c_str() ); /* Method IDs */ int index = 1; for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); fprintf( file, " %s%s_%s = %d,\n", config.c_mode ? "_" : "", face->object.c_str(), method->name.c_str(), index++ ); } fprintf( file, "} %sCall;\n" "\n", face->object.c_str() ); /* Method Argument Structures */ for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); fprintf( file, "/*\n" " * %s_%s\n" " */\n" "typedef struct {\n" "%s" "} %s%s;\n" "\n" "typedef struct {\n" "%s" "} %s%sReturn;\n" "\n" "\n", face->object.c_str(), method->name.c_str(), method->ArgumentsAsMemberDecl().c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsOutputAsMemberDecl( config ).c_str(), face->object.c_str(), method->name.c_str() ); } /* Abstract Interface */ if (!config.c_mode) { PrintInterface( file, face, face->name, "Interface", true ); /* Real Interface */ fprintf( file, "\n" "\n" "\n" "class %s_Real : public %s\n" "{\n" "private:\n" " %s *obj;\n" "\n" "public:\n" " %s_Real( %s *core, %s *obj )\n" " :\n" " %s( core ),\n" " obj( obj )\n" " {\n" " }\n" "\n", face->name.c_str(), face->name.c_str(), face->dispatch.c_str(), face->name.c_str(), face->core.c_str(), face->dispatch.c_str(), face->name.c_str() ); } for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); if (!config.c_mode) { fprintf( file, " virtual DFBResult %s(\n" "%s\n" " );\n" "\n", method->name.c_str(), method->ArgumentsAsParamDecl().c_str() ); } else { fprintf( file, "DFBResult %s_Real__%s( %s *obj%s\n" "%s );\n" "\n", face->name.c_str(), method->name.c_str(), face->dispatch.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); } } if (!config.c_mode) { fprintf( file, "};\n" ); /* Requestor Interface */ fprintf( file, "\n" "\n" "\n" "class %s_Requestor : public %s%s\n" "{\n" "private:\n" " %s *obj;\n" "\n" "public:\n" " %s_Requestor( %s *core, %s *obj )\n" " :\n" " %s( core ),\n" "%s" " obj( obj )\n" " {\n" " }\n" "\n", face->name.c_str(), face->name.c_str(), face->buffered ? ", public CallBuffer" : "", face->object.c_str(), face->name.c_str(), face->core.c_str(), face->object.c_str(), face->name.c_str(), face->buffered ? " CallBuffer( 16000 ),\n" : "" ); } if (face->buffered) fprintf( file, "protected:\n" " virtual DFBResult flushCalls();\n" "\n" ); if (!config.c_mode) fprintf( file, "public:\n" ); for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); if (!config.c_mode) { fprintf( file, " virtual DFBResult %s(\n" "%s\n" " );\n" "\n", method->name.c_str(), method->ArgumentsAsParamDecl().c_str() ); } else { fprintf( file, "DFBResult %s_Requestor__%s( %s *obj%s\n" "%s );\n" "\n", face->name.c_str(), method->name.c_str(), face->object.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); } } if (!config.c_mode) fprintf( file, "};\n" "\n" ); fprintf( file, "\n" "DFBResult %sDispatch__Dispatch( %s *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length );\n", face->object.c_str(), face->dispatch.c_str() ); if (!config.c_mode) fprintf( file, "\n" "}\n" ); fprintf( file, "\n" "\n" "#endif\n" ); if (!config.c_mode) fprintf( file, "\n" "#endif\n" ); fclose( file ); } void FluxComp::GenerateSource( const Interface *face, const FluxConfig &config ) { FILE *file; std::string filename = config.output_dir + face->object; bool direct = true; if (!config.c_mode) filename += ".cpp"; else filename += ".c"; if (config.no_direct || face->object != face->dispatch) direct = false; file = fopen( filename.c_str(), "w" ); if (!file) { D_PERROR( "FluxComp: fopen( '%s' ) failed!\n", filename.c_str() ); return; } fprintf( file, "/*\n" " * This file was automatically generated by fluxcomp; DO NOT EDIT!\n" " */\n" "%s\n" "#include \n" "\n" "#include \"%s.h\"\n" "\n", license, face->object.c_str() ); if (!config.c_mode) fprintf( file, "extern \"C\" {\n" ); fprintf( file, "#include \n" "\n" "#include \n" "#include \n" "#include \n" "#include \n" "\n" "#include \n" "\n" "#include \n" ); if (config.call_mode) fprintf( file, "\n" "#include \n" ); if (!config.c_mode) fprintf( file, "}\n" ); fprintf( file, "\n" "D_DEBUG_DOMAIN( DirectFB_%s, \"DirectFB/%s\", \"DirectFB %s\" );\n" "\n" "/*********************************************************************************************************************/\n" "\n", face->object.c_str(), face->object.c_str(), face->object.c_str() ); /* C Wrappers */ for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); if (!config.c_mode) { fprintf( file, "DFBResult\n" "%s_%s(\n" " %-40s *obj%s\n" "%s\n" ")\n" "{\n", face->object.c_str(), method->name.c_str(), face->object.c_str(), method->entities.empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); if (config.call_mode) { fprintf( file, " DFBResult ret;\n" "\n" " switch (CoreDFB_CallMode( core_dfb )) {\n" " case COREDFB_CALL_DIRECT:" ); if (direct && !method->indirect) fprintf( file, "{\n" " DirectFB::%s_Real real( core_dfb, obj );\n" "\n" " Core_PushCalling();\n" " ret = real.%s( %s );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }", face->name.c_str(), method->name.c_str(), method->ArgumentsNames().c_str() ); fprintf( file, "\n case COREDFB_CALL_INDIRECT: {\n" " DirectFB::%s_Requestor requestor( core_dfb, obj );\n" "\n" " Core_PushCalling();\n" " ret = requestor.%s( %s );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }\n" " case COREDFB_CALL_DENY:\n" " return DFB_DEAD;\n" " }\n" "\n" " return DFB_UNIMPLEMENTED;\n" "}\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsNames().c_str() ); } else { if (direct) fprintf( file, " if (!fusion_config->secure_fusion || dfb_core_is_master( core_dfb )) {\n" " DirectFB::%s_Real real( core_dfb, obj );\n" "\n" " return real.%s( %s );\n" " }\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsNames().c_str() ); fprintf( file, " DirectFB::%s_Requestor requestor( core_dfb, obj );\n" "\n" " return requestor.%s( %s );\n" "}\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsNames().c_str() ); } } else { fprintf( file, "DFBResult\n" "%s_%s(\n" " %-40s *obj%s\n" "%s\n" ")\n" "{\n", face->object.c_str(), method->name.c_str(), face->object.c_str(), method->entities.empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); if (config.call_mode) { fprintf( file, " DFBResult ret;\n" "\n" " switch (CoreDFB_CallMode( core_dfb )) {\n" " case COREDFB_CALL_DIRECT:" ); if (direct && !method->indirect) fprintf( file, "{\n" " Core_PushCalling();\n" " ret = %s_Real__%s( obj%s%s );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsNames().c_str() ); fprintf( file, "\n case COREDFB_CALL_INDIRECT: {\n" " Core_PushCalling();\n" " ret = %s_Requestor__%s( obj%s%s );\n" " Core_PopCalling();\n" "\n" " return ret;\n" " }\n" " case COREDFB_CALL_DENY:\n" " return DFB_DEAD;\n" " }\n" "\n" " return DFB_UNIMPLEMENTED;\n" "}\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsNames().c_str() ); } else { if (direct) fprintf( file, " if (!fusion_config->secure_fusion || dfb_core_is_master( core_dfb )) {\n" " return %s_Real__%s( obj%s%s );\n" " }\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsNames().c_str() ); fprintf( file, " return %s_Requestor__%s( obj%s%s );\n" "}\n" "\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsNames().c_str() ); } } } fprintf( file, "/*********************************************************************************************************************/\n" "\n" "static FusionCallHandlerResult\n" "%s_Dispatch( int caller, /* fusion id of the caller */\n" " int call_arg, /* optional call parameter */\n" " void *ptr, /* optional call parameter */\n" " unsigned int length,\n" " void *ctx, /* optional handler context */\n" " unsigned int serial,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n", face->object.c_str() ); fprintf( file, " %s *obj = (%s*) ctx;" "\n" " %s%sDispatch__Dispatch( obj, caller, call_arg, ptr, length, ret_ptr, ret_size, ret_length );\n" "\n" " return FCHR_RETURN;\n" "}\n" "\n", face->dispatch.c_str(), face->dispatch.c_str(), config.c_mode ? "" : "DirectFB::", face->object.c_str() ); fprintf( file, "void %s_Init_Dispatch(\n" " %-20s *core,\n" " %-20s *obj,\n" " FusionCall *call\n" ")\n" "{\n", face->object.c_str(), face->core.c_str(), face->dispatch.c_str() ); fprintf( file, " fusion_call_init3( call, %s_Dispatch, obj, core->world );\n" "}\n" "\n", face->object.c_str() ); fprintf( file, "void %s_Deinit_Dispatch(\n" " FusionCall *call\n" ")\n" "{\n" " fusion_call_destroy( call );\n" "}\n" "\n", face->object.c_str() ); fprintf( file, "/*********************************************************************************************************************/\n" "\n" ); if (!config.c_mode) { fprintf( file, "namespace DirectFB {\n" "\n" "\n" ); } /* Requestor Methods */ fprintf( file, "static __inline__ void *args_alloc( void *static_buffer, size_t size )\n" "{\n" " void *buffer = static_buffer;\n" "\n" " if (size > %s) {\n" " buffer = D_MALLOC( size );\n" " if (!buffer)\n" " return NULL;\n" " }\n" "\n" " return buffer;\n" "}\n" "\n", config.static_args_bytes.c_str() ); fprintf( file, "static __inline__ void args_free( void *static_buffer, void *buffer )\n" "{\n" " if (buffer != static_buffer)\n" " D_FREE( buffer );\n" "}\n" "\n" ); if (face->buffered) { fprintf( file, "\n" "DFBResult\n" "%s_Requestor::flushCalls()\n" "{\n" " DFBResult ret;\n" "\n" " ret = (DFBResult) %s_Call( obj, (FusionCallExecFlags)(FCEF_ONEWAY | FCEF_QUEUE), -1, buffer, buffer_len, NULL, 0, NULL );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s: %s_Call( -1 ) failed!\\n\", __FUNCTION__ );\n" " return ret;\n" " }\n" "\n" " return DFB_OK;\n" "}\n", face->name.c_str(), face->object.c_str(), face->object.c_str() ); } for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); if (!config.c_mode) { fprintf( file, "\n" "DFBResult\n" "%s_Requestor::%s(\n" "%s\n" ")\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().c_str() ); } else { fprintf( file, "\n" "DFBResult\n" "%s_Requestor__%s( %s *obj%s\n" "%s\n" ")\n", face->name.c_str(), method->name.c_str(), face->object.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ",", method->ArgumentsAsParamDecl().c_str() ); } if (method->buffer && face->buffered) { fprintf( file, "{\n" "%s" " %s%s *args = (%s%s*) prepare( %s%s_%s, %s );\n" "\n" " if (!args)\n" " return (DFBResult) D_OOM();\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"%s_Requestor::%%s()\\n\", __FUNCTION__ );\n" "\n" "%s" "\n" "%s" "\n" " commit();\n" "\n" "%s" "\n" "%s" "%s" "\n" " return DFB_OK;\n" "}\n" "\n", method->OpenSplitArgumentsIfRequired().c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), config.c_mode ? "_" : "", face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, false ).c_str(), face->object.c_str(), face->name.c_str(), method->ArgumentsAssertions().c_str(), method->ArgumentsInputAssignments().c_str(), method->ArgumentsOutputAssignments().c_str(), method->ArgumentsOutputObjectCatch( config ).c_str(), method->CloseSplitArgumentsIfRequired().c_str() ); } else if (method->async) { fprintf( file, "{\n" " DFBResult ret = DFB_OK;\n" "%s" " char args_static[%s];\n" " %s%s *args = (%s%s*) args_alloc( args_static, %s );\n" "\n" " if (!args)\n" " return (DFBResult) D_OOM();\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"%s_Requestor::%%s()\\n\", __FUNCTION__ );\n" "\n" "%s" "\n" "%s" "\n" "%s" " ret = (DFBResult) %s_Call( obj, (FusionCallExecFlags)(FCEF_ONEWAY%s%s), %s%s_%s, args, %s, NULL, 0, NULL );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s: %s_Call( %s_%s ) failed!\\n\", __FUNCTION__ );\n" " goto out;\n" " }\n" "\n" "%s" "\n" "%s" "\n" "out:\n" " args_free( args_static, args );\n" " return ret;\n" "}\n" "\n", method->ArgumentsOutputObjectDecl().c_str(), config.static_args_bytes.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, false ).c_str(), face->object.c_str(), face->name.c_str(), method->ArgumentsAssertions().c_str(), method->ArgumentsInputAssignments().c_str(), face->buffered ? " flush();\n\n" : "", face->object.c_str(), method->queue ? " | FCEF_QUEUE" : "", method->indirect ? " | FCEF_NODIRECT" : "", config.c_mode ? "_" : "", face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, false ).c_str(), face->object.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsOutputAssignments().c_str(), method->ArgumentsOutputObjectCatch( config ).c_str() ); } else { fprintf( file, "{\n" " DFBResult ret = DFB_OK;\n" "%s" " char args_static[%s];\n" " char return_args_static[%s];\n" " %s%s *args = (%s%s*) args_alloc( args_static, %s );\n" " %s%sReturn *return_args;\n" "\n" " if (!args)\n" " return (DFBResult) D_OOM();\n" "\n" " return_args = (%s%sReturn*) args_alloc( return_args_static, %s );\n" "\n" " if (!return_args) {\n" " args_free( args_static, args );\n" " return (DFBResult) D_OOM();\n" " }\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"%s_Requestor::%%s()\\n\", __FUNCTION__ );\n" "\n" "%s" "\n" "%s" "\n" "%s" " ret = (DFBResult) %s_Call( obj, %s, %s%s_%s, args, %s, return_args, %s, NULL );\n" " if (ret) {\n" " D_DERROR( ret, \"%%s: %s_Call( %s_%s ) failed!\\n\", __FUNCTION__ );\n" " goto out;\n" " }\n" "\n" " if (return_args->result) {\n" " /*D_DERROR( return_args->result, \"%%s: %s_%s failed!\\n\", __FUNCTION__ );*/\n" " ret = return_args->result;\n" " goto out;\n" " }\n" "\n" "%s" "\n" "%s" "\n" "out:\n" " args_free( return_args_static, return_args );\n" " args_free( args_static, args );\n" " return ret;\n" "}\n" "\n", method->ArgumentsOutputObjectDecl().c_str(), config.static_args_bytes.c_str(), config.static_args_bytes.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, false ).c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, true ).c_str(), face->object.c_str(), face->name.c_str(), method->ArgumentsAssertions().c_str(), method->ArgumentsInputAssignments().c_str(), face->buffered ? " flush();\n\n" : "", face->object.c_str(), method->indirect ? "(FusionCallExecFlags)FCEF_NODIRECT" : "FCEF_NONE", config.c_mode ? "_" : "", face->object.c_str(), method->name.c_str(), method->ArgumentsSize( face, false ).c_str(), method->ArgumentsSize( face, true ).c_str(), face->object.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsOutputAssignments().c_str(), method->ArgumentsOutputObjectCatch( config ).c_str() ); } } /* Dispatch Object */ fprintf( file, "/*********************************************************************************************************************/\n" "\n" "static DFBResult\n" "__%sDispatch__Dispatch( %s *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n" " D_UNUSED\n" " DFBResult ret;\n" "\n", face->object.c_str(), face->dispatch.c_str() ); if (!config.c_mode) fprintf( file, "\n" " DirectFB::%s_Real real( core_dfb, obj );\n" "\n", face->name.c_str() ); fprintf( file, "\n" " switch (method) {\n" ); /* Dispatch Methods */ for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); if (!config.c_mode) fprintf( file, " case %s_%s: {\n", face->object.c_str(), method->name.c_str() ); else fprintf( file, " case _%s_%s: {\n", face->object.c_str(), method->name.c_str() ); if (method->async) { fprintf( file, "%s" "%s" " D_UNUSED\n" " %s%s *args = (%s%s *) ptr;\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"=-> %s_%s\\n\" );\n" "\n" "%s" "\n" "%s", method->ArgumentsInputObjectDecl().c_str(), method->ArgumentsOutputObjectDecl().c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsInputDebug( config, face ).c_str(), method->ArgumentsInputObjectLookup( config ).c_str() ); if (!config.c_mode) fprintf( file, " real.%s( %s );\n", method->name.c_str(), method->ArgumentsAsMemberParams().c_str() ); else fprintf( file, " %s_Real__%s( obj%s%s );\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsAsMemberParams().c_str() ); fprintf( file, "\n" "%s" " return DFB_OK;\n" " }\n" "\n", method->ArgumentsInputObjectUnref().c_str() ); } else { fprintf( file, "%s" "%s" "%s" " D_UNUSED\n" " %s%s *args = (%s%s *) ptr;\n" " %s%sReturn *return_args = (%s%sReturn *) ret_ptr;\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"=-> %s_%s\\n\" );\n" "\n" "%s", method->ArgumentsInputObjectDecl().c_str(), method->ArgumentsOutputObjectDecl().c_str(), method->ArgumentsOutputTmpDecl().c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), method->name.c_str(), face->object.c_str(), face->object.c_str(), method->name.c_str(), method->ArgumentsInputObjectLookup( config ).c_str() ); if (!config.c_mode) fprintf( file, " return_args->result = real.%s( %s );\n", method->name.c_str(), method->ArgumentsAsMemberParams().c_str() ); else fprintf( file, " return_args->result = %s_Real__%s( obj%s%s );\n", face->name.c_str(), method->name.c_str(), method->ArgumentsAsParamDecl().empty() ? "" : ", ", method->ArgumentsAsMemberParams().c_str() ); fprintf( file, " if (return_args->result == DFB_OK) {\n" "%s" "%s" "%s" " }\n" "\n" " *ret_length = %s;\n" "\n" "%s" " return DFB_OK;\n" " }\n" "\n", method->ArgumentsOutputObjectThrow( config ).c_str(), method->ArgumentsInoutReturn().c_str(), method->ArgumentsOutputTmpReturn().c_str(), method->ArgumentsSizeReturn( face ).c_str(), method->ArgumentsInputObjectUnref().c_str() ); } } fprintf( file, " }\n" "\n" " return DFB_NOSUCHMETHOD;\n" "}\n" ); fprintf( file, "/*********************************************************************************************************************/\n" "\n" "DFBResult\n" "%sDispatch__Dispatch( %s *obj,\n" " FusionID caller,\n" " int method,\n" " void *ptr,\n" " unsigned int length,\n" " void *ret_ptr,\n" " unsigned int ret_size,\n" " unsigned int *ret_length )\n" "{\n" " DFBResult ret = DFB_OK;\n" "\n" " D_DEBUG_AT( DirectFB_%s, \"%sDispatch::%%s( %%p )\\n\", __FUNCTION__, obj );\n", face->object.c_str(), face->dispatch.c_str(), face->object.c_str(), face->object.c_str()); if (config.identity) fprintf( file, "\n" " Core_PushIdentity( caller );\n" ); if (face->buffered) { fprintf( file, "\n" " if (method == -1) {\n" " unsigned int consumed = 0;\n" "\n" " while (consumed < length) {\n" " u32 *p = (u32*)( (u8*) ptr + consumed );\n" "\n" " if ((p[0] > length - consumed) || (consumed + p[0] > length)) {\n" " D_WARN( \"invalid data from caller %%lu\", caller );\n" " break;\n" " }\n" "\n" " consumed += p[0];\n" "\n" " ret = __%sDispatch__Dispatch( obj, caller, p[1], p + 2, p[0] - sizeof(int) * 2, NULL, 0, NULL );\n" " if (ret)\n" " break;\n" " }\n" " }\n" " else\n", face->object.c_str() ); } fprintf( file, "\n" " ret = __%sDispatch__Dispatch( obj, caller, method, ptr, length, ret_ptr, ret_size, ret_length );\n", face->object.c_str() ); if (config.identity) fprintf( file, "\n" " Core_PopIdentity();\n" ); fprintf( file, "\n" " return ret;\n" "}\n" ); if (!config.c_mode) fprintf( file, "\n" "}\n" ); fclose( file ); } void FluxComp::PrintInterface( FILE *file, const Interface *face, const std::string &name, const std::string &super, bool abstract ) { fprintf( file, "\n" "\n" "\n" "class %s : public %s\n" "{\n" "public:\n" " %s( %s *core )\n" " :\n" " %s( core )\n" " {\n" " }\n" "\n" "public:\n", name.c_str(), super.c_str(), name.c_str(), face->core.c_str(), super.c_str() ); for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { const Method *method = dynamic_cast( *iter ); fprintf( file, " virtual DFBResult %s(\n" "%s\n" " )%s;\n" "\n", method->name.c_str(), method->ArgumentsAsParamDecl().c_str(), abstract ? " = 0" : "" ); } fprintf( file, "};\n" ); } /**********************************************************************************************************************/ /**********************************************************************************************************************/ int main( int argc, char *argv[] ) { DirectResult ret; Entity::vector faces; FluxConfig config; direct_initialize(); // direct_debug_config_domain( "fluxcomp", true ); // direct_config->debug = true; // direct_config->debugmem = true; /* Parse the command line. */ if (!config.parse_command_line( argc, argv )) return -1; ret = Entity::GetEntities( filename, faces ); if (ret == DR_OK) { FluxComp fc; for (Entity::vector::const_iterator iter = faces.begin(); iter != faces.end(); iter++) { Interface *face = dynamic_cast( *iter ); for (Entity::vector::const_iterator iter = face->entities.begin(); iter != face->entities.end(); iter++) { Method *method = dynamic_cast( *iter ); if (!method->async || !method->queue) method->buffer = false; if (method->buffer) { face->buffered = true; break; } } fc.GenerateHeader( face, config ); fc.GenerateSource( face, config ); } } direct_print_memleaks(); direct_shutdown(); return ret; }