diff options
author | Jonathan Pryor <jpryor@novell.com> | 2006-10-25 02:20:30 +0400 |
---|---|---|
committer | Jonathan Pryor <jpryor@novell.com> | 2006-10-25 02:20:30 +0400 |
commit | 03011bd1c784bf8b340b3b52417f4fb20df1de1f (patch) | |
tree | b51f42319583070960016d41e0386f67af43aba9 | |
parent | 25cdedfc03df9f63b2574cddb441add78cbcf909 (diff) |
* configure.in: Add create-native-map program.
* Makefile.am: Build create-native-map.
* create-native-map/Makefile.am, lib/Makefile.am: Added; build subdirectories.
* create-native-map/bin/create-native-map: Script to startup
`dirname`/../lib/create-native-map/create-native-map.exe.
* create-native-map/bin/Makefile.am: Added; install $bindir/create-native-map.
* create-native-map/lib/create-native-map/Makefile.am: Added; present to
make sure $top_builddir/lib/create-native-map is created.
* create-native-map/lib/pkgconfig/create-native-map.pc.in: Aded; pkgconfig
file to copy an installed version of create-native-map.exe &
MapAttribute.cs.
* create-native-map/lib/pkgconfig/Makfile.am: Added; install the
create-native-map.pc file.
* create-native-map/man/create-native-map.1: Man page for create-native-map.
* create-native-map/man/Makefile.am: Added; install the man page.
* create-native-map/src/create-native-map.cs:
- Moved from mcs/class/Mono.Posix/Mono.Unix.Native/make-map.cs
- check for t.Namespace==null before looking using
Configuration.NamespaceRenames (Dictionary`2 doesn't like null keys);
- HeaderFileGenerator needs to know about member renames (so it uses the
renamed member in conversion code);
- Clean up enumeration generation for readablility.
- Generate structure declarations for [Map]-decorated types and types used
within a [DllImport]-marked method.
- Warnings should be prefixed with "warning: ".
- Don't generate function prototypes for already-generated functions (e.g.
if we emit a prototype for Mono_Posix_ToFilePermissions, don't
re-declare that function later because we found a DllImport for it).
- Add new arguments: --autoconf-member, --exclude-native-symbol,
--library, --rename-member, --rename-namespace.
These are to:
- Allow native structure members to only be accessed if an Autoconf
macro is defined (--autoconf-member)
- Modify the C "namespace" of types/functions (--rename-namespace)
- Specify the DllImport library that prototypes should be generated for
(--library)
- Exclude symbols from the function declaration system
(--exclude-native-symbol)
- Member renaming (--rename-member).
(Curse you glibc making st_atime a macro!)
* create-native-map/src/Makefile.am: Added; build create-native-map.exe;
test cases.
* create-native-map/src/MapAttribute.cs: Added; the attribute that
create-native-map looks
for, and should be copied into projects using create-native-map.
* create-native-map/src/TestMap.cs: Added; test case for create-native-map.exe
* create-native-map/src/test.c.ref, src/test.cs.ref, src/test.h.ref,
src/test.xml.ref: Added; expected create-native-map.exe output for
TestMap.cs.
* create-native-map/ChangeLog: Started.
svn path=/trunk/mono-tools/; revision=66944
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | configure.in | 8 | ||||
-rw-r--r-- | create-native-map/ChangeLog | 46 | ||||
-rw-r--r-- | create-native-map/Makefile.am | 1 | ||||
-rw-r--r-- | create-native-map/bin/Makefile.am | 7 | ||||
-rwxr-xr-x | create-native-map/bin/create-native-map | 7 | ||||
-rw-r--r-- | create-native-map/lib/Makefile.am | 1 | ||||
-rw-r--r-- | create-native-map/lib/create-native-map/Makefile.am | 2 | ||||
-rw-r--r-- | create-native-map/lib/pkgconfig/Makefile.am | 8 | ||||
-rw-r--r-- | create-native-map/lib/pkgconfig/create-native-map.pc.in | 13 | ||||
-rw-r--r-- | create-native-map/man/Makefile.am | 5 | ||||
-rw-r--r-- | create-native-map/man/create-native-map.1 | 559 | ||||
-rw-r--r-- | create-native-map/src/Makefile.am | 61 | ||||
-rw-r--r-- | create-native-map/src/MapAttribute.cs | 54 | ||||
-rw-r--r-- | create-native-map/src/TestMap.cs | 93 | ||||
-rw-r--r-- | create-native-map/src/create-native-map.cs | 1679 | ||||
-rw-r--r-- | create-native-map/src/test.c.ref | 285 | ||||
-rw-r--r-- | create-native-map/src/test.cs.ref | 123 | ||||
-rw-r--r-- | create-native-map/src/test.h.ref | 147 | ||||
-rw-r--r-- | create-native-map/src/test.xml.ref | 225 |
20 files changed, 3329 insertions, 0 deletions
@@ -1,3 +1,8 @@ +2006-10-24 Jonathan Pryor <jonpryor@vt.edu> + + * configure.in: Add create-native-map program. + * Makefile.am: Build create-native-map. + 2006-01-16 Rafael Ferreira <raf@ophion.org> * configure.in: updated to use gtk-sharp-2.0/gecko-sharp-2.0 this fixes bugs# 76054 & 76544 related to Pango bugs. diff --git a/configure.in b/configure.in index 98c5bc83..c231519f 100644 --- a/configure.in +++ b/configure.in @@ -88,6 +88,14 @@ asn1view/Makefile asn1view/art/Makefile asn1view/gtk/Makefile asn1view/common/Makefile +create-native-map/Makefile +create-native-map/bin/Makefile +create-native-map/lib/Makefile +create-native-map/lib/create-native-map/Makefile +create-native-map/lib/pkgconfig/Makefile +create-native-map/lib/pkgconfig/create-native-map.pc +create-native-map/man/Makefile +create-native-map/src/Makefile ]) echo "---" diff --git a/create-native-map/ChangeLog b/create-native-map/ChangeLog new file mode 100644 index 00000000..37d0a118 --- /dev/null +++ b/create-native-map/ChangeLog @@ -0,0 +1,46 @@ +2006-10-24 Jonathan Pryor <jonpryor@vt.edu> + + * Makefile.am, lib/Makefile.am: Added; build subdirectories. + * bin/create-native-map: Script to startup + `dirname`/../lib/create-native-map/create-native-map.exe. + * bin/Makefile.am: Added; install $bindir/create-native-map. + * lib/create-native-map/Makefile.am: Added; present to make sure + $top_builddir/lib/create-native-map is created. + * lib/pkgconfig/create-native-map.pc.in: Aded; pkgconfig file to copy an + installed version of create-native-map.exe & MapAttribute.cs. + * lib/pkgconfig/Makfile.am: Added; install the create-native-map.pc file. + * man/create-native-map.1: Man page for create-native-map. + * man/Makefile.am: Added; install the man page. + * src/create-native-map.cs: + - Moved from mcs/class/Mono.Posix/Mono.Unix.Native/make-map.cs + - check for t.Namespace==null before looking using + Configuration.NamespaceRenames (Dictionary`2 doesn't like null keys); + - HeaderFileGenerator needs to know about member renames (so it uses the + renamed member in conversion code); + - Clean up enumeration generation for readablility. + - Generate structure declarations for [Map]-decorated types and types used + within a [DllImport]-marked method. + - Warnings should be prefixed with "warning: ". + - Don't generate function prototypes for already-generated functions (e.g. + if we emit a prototype for Mono_Posix_ToFilePermissions, don't + re-declare that function later because we found a DllImport for it). + - Add new arguments: --autoconf-member, --exclude-native-symbol, + --library, --rename-member, --rename-namespace. + These are to: + - Allow native structure members to only be accessed if an Autoconf + macro is defined (--autoconf-member) + - Modify the C "namespace" of types/functions (--rename-namespace) + - Specify the DllImport library that prototypes should be generated for + (--library) + - Exclude symbols from the function declaration system + (--exclude-native-symbol) + - Member renaming (--rename-member). + (Curse you glibc making st_atime a macro!) + * src/Makefile.am: Added; build create-native-map.exe; test cases. + * src/MapAttribute.cs: Added; the attribute that create-native-map looks + for, and should be copied into projects using create-native-map. + * src/TestMap.cs: Added; test case for create-native-map.exe + * src/test.c.ref, src/test.cs.ref, src/test.h.ref, src/test.xml.ref: Added; + expected create-native-map.exe output for TestMap.cs. + * ChangeLog: Started. + diff --git a/create-native-map/Makefile.am b/create-native-map/Makefile.am new file mode 100644 index 00000000..b27b72f2 --- /dev/null +++ b/create-native-map/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = bin src lib man diff --git a/create-native-map/bin/Makefile.am b/create-native-map/bin/Makefile.am new file mode 100644 index 00000000..cc10fc2d --- /dev/null +++ b/create-native-map/bin/Makefile.am @@ -0,0 +1,7 @@ + +bin_SCRIPTS = create-native-map + +create-native-map: + cp $(srcdir)/create-native-map . + chmod +x $@ + diff --git a/create-native-map/bin/create-native-map b/create-native-map/bin/create-native-map new file mode 100755 index 00000000..aca489f5 --- /dev/null +++ b/create-native-map/bin/create-native-map @@ -0,0 +1,7 @@ +#!/bin/sh + +bindir=`dirname "$0"` +libdir="$bindir/../lib/create-native-map" + +exec mono "$libdir/create-native-map.exe" "$@" + diff --git a/create-native-map/lib/Makefile.am b/create-native-map/lib/Makefile.am new file mode 100644 index 00000000..64b088bd --- /dev/null +++ b/create-native-map/lib/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = create-native-map pkgconfig diff --git a/create-native-map/lib/create-native-map/Makefile.am b/create-native-map/lib/create-native-map/Makefile.am new file mode 100644 index 00000000..0718ba0f --- /dev/null +++ b/create-native-map/lib/create-native-map/Makefile.am @@ -0,0 +1,2 @@ +# do nothing + diff --git a/create-native-map/lib/pkgconfig/Makefile.am b/create-native-map/lib/pkgconfig/Makefile.am new file mode 100644 index 00000000..2fcb9aa7 --- /dev/null +++ b/create-native-map/lib/pkgconfig/Makefile.am @@ -0,0 +1,8 @@ + +pkgconfigdir = $(prefix)/lib/pkgconfig +pkgconfig_DATA = create-native-map.pc + +DISTCLEANFILES = create-native-map.pc + +EXTRA_DIST = create-native-map.pc.in + diff --git a/create-native-map/lib/pkgconfig/create-native-map.pc.in b/create-native-map/lib/pkgconfig/create-native-map.pc.in new file mode 100644 index 00000000..0e711359 --- /dev/null +++ b/create-native-map/lib/pkgconfig/create-native-map.pc.in @@ -0,0 +1,13 @@ +prefix=${pcfiledir}/../.. +exec_prefix=${pcfiledir}/../.. +libdir=@libdir@ +includedir=${prefix}/include +assemblies_dir=${libdir}/create-native-map +Sources=${assemblies_dir}/MapAttribute.cs +Programs=${assemblies_dir}/create-native-map.exe + +Name: create-native-map +Description: C/C# Mapping Generator +Version: @VERSION@ +Requires: +Libs: diff --git a/create-native-map/man/Makefile.am b/create-native-map/man/Makefile.am new file mode 100644 index 00000000..67e968d4 --- /dev/null +++ b/create-native-map/man/Makefile.am @@ -0,0 +1,5 @@ + +man_MANS = create-native-map.1 + +EXTRA_DIST = $(man_MANS) + diff --git a/create-native-map/man/create-native-map.1 b/create-native-map/man/create-native-map.1 new file mode 100644 index 00000000..9c856e77 --- /dev/null +++ b/create-native-map/man/create-native-map.1 @@ -0,0 +1,559 @@ +.\" +.\" create-native-map manual page. +.\" (C) 2006 Jonathan Pryor +.\" Author: +.\" Jonathan Pryor (jonpryor@vt.edu) +.\" +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.TH "create-native-map" 1 +.SH NAME +create-native-map \- C/C# Mapping Creator +.SH SYNOPSIS +.B create-native-map +[OPTIONS]* ASSEMBLY-FILE-NAME OUPUT-PREFIX +.SH OPTIONS +.TP +.I \--autoconf-header=HEADER +.I HEADER +is a header file name in the syntax typically used with the C +.I #include +statement, e.g. +.I "#include <stdio.h>" +or +.I "#include ""local.h""" +\. +.Sp +An Autoconf-formatted macro is generated from the include name, and a +.I #include +directive is wrapped within a +.I #ifdef +block for the Autoconf macro within the generated +.I .c +file. +.Sp +For example, +.I "--autoconf-header=<stdio.h>" +would generate the code: +.nf + + #ifndef HAVE_STDIO_H + #include <stdio.h> + #endif /* ndef HAVE_STDIO_H */ + +.fi +.TP +.I \--autoconf-member=MEMBER +Specify that any access to +.I MEMBER +should be wrapped within a +.I #ifdef HAVE_MEMBER +block. +.I MEMBER +can be either a +.I field-name +or a +.I class-name +\. +.I field-name +combination. +.Sp +For example, given the C# declaration: +.nf + + [Mono.Unix.Native.Map ("struct dirent")] + struct Dirent { + public long d_off; + } + +.fi +then +.I "--autoconf-member=d_off" +would generate the code similar to: +.nf + + int + ToDirent (struct dirent *from, struct Dirent *to) + { + #ifdef HAVE_STRUCT_DIRENT_D_OFF + to->d_off = from->d_off; + #endif /* ndef HAVE_STRUCT_DIRENT_D_OFF */ + } + +.fi +.TP +.I \--exclude-native-symbol=SYMBOL +.I SYMBOL +is a +.I [DllImport] +-marked method that should +.I not +have a prototype generated for it. +.TP +.I \--impl-header=HEADER +Insert a +.I #include +statement within the generated +.I .c +file for +.I HEADER +\. +.Sp +For example, +.I "--impl-header=<stdlib.h>" +generates +.nf + + #include <stdlib.h> + +.fi +.TP +.I \--impl-macro=MACRO +Insert a +.I #define +statement within the generated +.I .c +file. +.I MACRO +can contain a +.I "=" +to separate the macro name from the macro value. +.Sp +For example, +.I "--impl-macro=FOO=42" +generates +.nf + + #define FOO 42 + +.fi +.TP +.I \--library=LIBRARY +Create prototypes for +.I [DllImport] +-marked methods which reference the native library +.I LIBRARY +into the generated +.I .h +file. +.TP +.I \--public-header=HEADER +Insert a +.I #include +statement within the generated +.I .h +file for +.I HEADER +\. +.Sp +For example, +.I "--public-header=<stdlib.h>" +generates +.nf + + #include <stdlib.h> + +.fi +.TP +.I \--public-macro=MACRO +Insert a +.I #define +statement within the generated +.I .h +file. +.I MACRO +can contain a +.I "=" +to separate the macro name from the macro value. +.Sp +For example, +.I "--public-macro=FOO=42" +generates +.nf + + #define FOO 42 + +.fi +.TP +.I \--rename-member=FROM=TO +This is used when +.I FROM +is a C macro, and thus must be altered in order to be used sanely. All +generated references to the managed representation will use +.I TO +instead of +.I FROM +\. +.Sp +For example, given the C# declaration: +.nf + + [Mono.Unix.Native.Map ("struct stat")] + struct Stat { + public long st_atime; + } + +.fi +and the argument +.I "--rename-member=st_atime=st_atime_" +, the generated +.I .h +file would contain: +.nf + + struct Stat { + gint64 st_atime_; + }; + +.fi +(note the altered field name), while the generated +.I .c +file would contain: +.nf + + ToStat (struct stat *from, struct Stat *to) + { + to->st_atime_ = from->st_atime; + } + +.fi +.TP +.I \--rename-namespace=FROM=TO +By default, the C "namespace" (symbol prefix) is the C# namespace; types +within the C# namespace +.I Mono.Unix.Native +would be in the C "namespace" +.I Mono_Unix_Native +\. +Use +.I "--rename-namespace" +to modify the default, e.g. +.I "--rename-namespace=Mono.Unix.Native=Mono_Posix" +\. +This should be avoided if possible. You should instead use the +.I Mono.Unix.Native.MapAttribute.NativeSymbolPrefix +property instead, e.g. +.nf + + [Mono.Unix.Native.Map (NativeSymbolPrefix="Mono_Posix")] + struct Stat { + public long st_atime; + } + +.fi +.PP +.SH DESCRIPTION +.I create-native-map +is a program for a specific scenario: keeping code which is tightly coupled +between C and C# in sync with each other, based upon the C# types. +.PP +Platform Invoke is only useful if the managed code knows the exact types +and layout of all unmanaged structures it uses. This is usually the case +on Windows, but it is +.I not +the case on Unix. For example, +.I "struct stat" +makes use of types with sizes that will vary from platform to platform +(or even based on the compiler macros defined!). For example, +.I off_t +is usually a signed 32-bit integer on ILP32 platforms, but may be a +signed 64-bit integer on LP64 platforms, but may also be a 64-bit signed +integer on ILP32 platforms if the +.I "_FILE_OFFSET_BITS" +macro has the value 64. +In short, everything is flexible within Unix, and managed code can't deal +with such flexibility. +.PP +Thus, the niche for +.I create-native-map +: assume a fixed ABI that managed code can target, and generate code to +"thunk" the managed representations to the corresponding native representations. +This needs to be done for +.I everything +that can vary between platforms and compiler flags, from enumeration values +( +.I SIGBUS +has the value 10 on FreeBSD but 7 on Linux) to structure members (how big is +.I off_t +?). +.PP +.I create-native-map +will inspect +.I ASSEMBLY-FILE-NAME +and output the following files: +.RS +.ne 8 +.TP +.I OUTPUT-PREFIX.h +Contains enumeration values, class and structure declarations, +delegate declarations, and +.I [DllImport] +-marked methods (from the library specified by +.I \--library +) within the assembly +.I ASSEMBLY-FILE-NAME +\. +.TP +.I OUTPUT-PREFIX.c +Contains the implementation of enumeration and structure conversion functions. +.TP +.I OUTPUT-PREFIX.cs +Contains a partial class +.I NativeConvert +containing enumeration translation methods. +.TP +.I OUTPUT-PREFIX.xml +Generates ECMA XML documentation stubs for the enumeration translation methods in +.I OUTPUT-PREFIX.cs +\. +.ne +.RE +.PP +.I create-native-map +primarily looks for +.I Mono.Unix.Native.MapAttribute +-decorated types, and makes use of two +.I MapAttribute +properties: +.RS +.ne 8 +.TP +.I NativeType +Contains the corresponding C type. Only useful if applied to classes, structures, +and fields. +.TP +.I NativeSymbolPrefix +Contains the C "namespace" for generated enumerations, structures, and functions. +If this is not specified, the C "namespace" defaults to the managed namespace +or the appropriate namespace rename provided by +.I "--rename-namespace" +.. +.ne +.RE +.PP +The +.I MapAttribute +attribute can be specified on classes, structures, delegates, fields, and +enumerations. +.TP +Delegates +Code generation for delegates ignores the +.I MapAttribute.NativeType +property, and generates a function pointer +.I typedef +that best matches the delegate declaration into the +.I .h +file. +.Sp +For example, +.nf + + [Map (NativeSymbolPrefix="Foo")] + delegate string MyCallback (string s); + +.fi +generates the +.I typedef +: +.nf + + typedef char* (*Foo_MyCallback) (const char *s); + +.fi +.TP +Classes and Structures +A +.I [Map] +-decorated class or structure will get a C structure declaration within the +.I .h +file: +.nf + + [Map] + struct Foo { + public int i; + } + +.fi +becomes +.nf + + struct Foo { + public int i; + }; + +.fi +If the +.I MapAttribute.NativeType +property is set, then conversion functions will be declared within the +.I .h +file and created within the +.I .c +file: +.nf + + [Map ("struct stat", NativeSymbolPrefix="Foo")] + struct Stat { + public uint st_uid; + } + +.fi +becomes +.nf + + /* The .h file */ + struct Foo_Stat { + unsigned int st_uid; + }; + int + Foo_FromStat (struct Foo_Stat *from, struct stat *to); + int + Foo_ToStat (struct stat *to, sxtruct Foo_Stat *to); + + /* The .c file */ + int + Foo_FromStat (struct Foo_Stat *from, struct stat *to) + { + memset (to, 0, sizeof(*to); + to->st_uid = from->st_uid; + return 0; + } + + int + Foo_ToStat (struct stat *to, sxtruct Foo_Stat *to) + { + memset (to, 0, sizeof(*to); + to->st_uid = from->st_uid; + return 0; + } + +.fi +.TP +Fields +If a field (1) has the +.I MapAttribute +attribute, and (2) has the +.I MapAttribute.NativeType +property set, then the specified native type will be used for overflow +checking. For example: +.nf + + [Map ("struct stat", NativeSymbolPrefix="Foo")] + struct Stat { + [Map ("off_t")] public long st_size; + } + +.fi +generates +.nf + + /* The .h file */ + struct Foo_Stat { + gint64 st_size; + }; + int + Foo_FromStat (struct Foo_Stat *from, struct stat *to); + int + Foo_ToStat (struct stat *to, sxtruct Foo_Stat *to); + + /* The .c file */ + int + Foo_FromStat (struct Foo_Stat *from, struct stat *to) + { + _cnm_return_val_if_overflow (off_t, from->st_size, -1); + + memset (to, 0, sizeof(*to); + to->st_size = from->st_size; + return 0; + } + + int + Foo_ToStat (struct stat *to, sxtruct Foo_Stat *to) + { + _cnm_return_val_if_overflow (gint64, from->st_size, -1); + + memset (to, 0, sizeof(*to); + to->st_size = from->st_size; + return 0; + } + +.fi +This is useful for better error checking within the conversion functions. +.I MapAttribute.NativeType +is required for this as there is no other way to know what the native type is +(without parsing the system header files...). +.TP +Enumerations +Generates a C enumeration and macros for each of the members within the enumeration. +.I To +and +.I From +functions are also declared in the +.I .h +file and implemented in the +.I .c +file. +.Sp +For example, +.nf + + [Map (NativeSymbolPrefix="Foo")] + enum Errno { + EINVAL + } + +.fi +would generate the following in the +.I .h +file: +.nf + + enum Foo_Errno { + Foo_Errno_EINVAL = 0, + #define Foo_Errno_EINVAL Foo_Errno_EINVAL + }; + int Foo_FromErrno (int from, int *to); + int Foo_ToErrno (int from, int *to); + +.fi +and generates the following in the the +.I .c +file: +.nf + + int + Foo_FromErrno (int from, int *to) + { + *to = 0; + if (from == Foo_Errno_EPERM) + #ifdef EINVAL + {*to = EINVAL;} + #else + {errno = EINVAL; return -1;} + #endif + return 0; + } + + int + Foo_ToErrno (int from, int *to) + { + *to = 0; + #ifdef EINVAL + if (from == EINVAL) + {*to = Foo_Errno_EPERM; return 0;} + #endif + return -1; + } + +.fi +Different code will be generated if the managed enum is a +.I [Flags] +-decorated enumeration (to account for bitwise flags), but +this is the basic idea. +.PP +.SH MAILING LISTS +Visit http://lists.ximian.com/mailman/listinfo/mono-devel-list for details. +.SH WEB SITE +Visit http://www.mono-project.com for details diff --git a/create-native-map/src/Makefile.am b/create-native-map/src/Makefile.am new file mode 100644 index 00000000..04b342fb --- /dev/null +++ b/create-native-map/src/Makefile.am @@ -0,0 +1,61 @@ + +CNM_FILES = \ + create-native-map.cs \ + MapAttribute.cs + +TM_FILES = \ + MapAttribute.cs \ + TestMap.cs + +cnm_build_sources = $(addprefix $(srcdir)/, $(CNM_FILES)) +tm_build_sources = $(addprefix $(srcdir)/, $(TM_FILES)) + +EXE = ../lib/create-native-map/create-native-map.exe + +REFS = -r:Mono.Posix.dll + +all: $(EXE) + +$(EXE) : $(cnm_build_sources) + $(GMCS) $(MCS_FLAGS) -d:TRACE -debug+ -out:$@ -target:exe $(REFS) $(cnm_build_sources) + +assemblydir = $(prefix)/lib/create-native-map +assembly_DATA = $(EXE) MapAttribute.cs + +check: $(PROGRAM) TestMap.dll + +TestMap.dll: $(tm_build_sources) $(PROGRAM) + $(MCS) -debug+ -out:$@ -t:library $(tm_build_sources) + +test_output = test.c test.h test.cs test.xml + +$(test_output): TestMap.dll $(EXE) + ../bin/create-native-map \ + --autoconf-member autoconf_me \ + --autoconf-header='<unistd.h>' \ + --public-header='<stdlib.h>' \ + --public-macro=DefineMe=42 \ + --impl-header='<stdio.h>' \ + --impl-header='"foo.h"' \ + --impl-macro='FOO="foo"' \ + --exclude-native-symbol=exclude_native_symbol \ + --library=NativeLib \ + --rename-member=st_atime=st_atime_ \ + --rename-namespace=MakeMap.ToBeRenamed=MakeMap_Rename \ + $< test + +check: $(test_output) + for f in test.c test.h test.cs test.xml ; do \ + diff -rup $$f.ref $$f ; \ + done + +check-update: + for f in test.c test.h test.cs test.xml ; do \ + mv $$f $$f.ref ; \ + done + +libtest.so: test.c + gcc -shared -o $@ $^ -I.. `pkg-config --libs --cflags glib-2.0` + +CLEANFILES = $(EXE) $(EXE).mdb TestMap.dll TestMap.dll.mdb libtest.so + diff --git a/create-native-map/src/MapAttribute.cs b/create-native-map/src/MapAttribute.cs new file mode 100644 index 00000000..a628a27f --- /dev/null +++ b/create-native-map/src/MapAttribute.cs @@ -0,0 +1,54 @@ +// +// MapAttribute.cs +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) Novell, Inc. +// + +// +// 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. +// +using System; + +[AttributeUsage ( + AttributeTargets.Class | + AttributeTargets.Delegate | + AttributeTargets.Enum | + AttributeTargets.Field | + AttributeTargets.Struct)] +internal class MapAttribute : Attribute { + private string nativeType; + + public MapAttribute () + { + } + + public MapAttribute (string nativeType) + { + this.nativeType = nativeType; + } + + public string NativeType { + get {return nativeType;} + } +} + diff --git a/create-native-map/src/TestMap.cs b/create-native-map/src/TestMap.cs new file mode 100644 index 00000000..298cd67b --- /dev/null +++ b/create-native-map/src/TestMap.cs @@ -0,0 +1,93 @@ +// Test file for make-map.cs +using System; +using System.Runtime.InteropServices; +using System.Text; + +// Make sure that a null namespace doesn't kill make-map +class GlobalClass {} + +namespace MakeMap.Test { + struct ForDelegate {int i;} + [Map] + delegate string MyDelegate ( + bool b1, byte b2, sbyte b3, short s1, ushort us1, + int i1, uint ui1, long l1, ulong ul1, + IntPtr p1, UIntPtr p2, string s2, StringBuilder sb1, + HandleRef h, ForDelegate fd); + + [Map] + enum TestEnum { + Foo, + Bar, + Baz, + Qux, + } + + [Map ("struct foo")] + struct Foo { + public int foo; + + public IntPtr p; + + // this should be within a #ifdef HAVE_AUTOCONF_ME block, due to + // --autoconf-member. + public long autoconf_me; + } + + [Map ("struct foo_holder")] + struct FooHolder { + public Foo foo; + public TestEnum mode; + } + + delegate void DelFoo (int i, Foo f); + delegate void DelRefFoo (int i, ref Foo f); + delegate void DelArrayFoo (int i, Foo[] f); + delegate void DelRefArrayFoo (int i, ref Foo[] f); + delegate void DelBaz (int i, Baz b); + delegate void DelRefBaz (int i, ref Baz b); + delegate void DelArrayBaz (int i, Baz[] b); + delegate void DelRefArrayBaz (int i, ref Baz[] b); + + [StructLayout (LayoutKind.Sequential)] + class Baz { + public DelFoo b1; + public DelRefFoo b2; + public DelArrayFoo b3; + public DelRefArrayFoo b4; + public DelBaz b5; + public DelRefBaz b6; + public DelArrayBaz b7; + public DelRefArrayBaz b8; + } + + [StructLayout (LayoutKind.Sequential)] + class Qux { + public int i; + public Baz b; + } + + class NativeMethods { + [DllImport ("NativeLib")] + private static extern void UseQux (DelFoo b, ref Qux q); + + // This shouldn't appear in test.h, due to --exclude-native-symbol + [DllImport ("NativeLib")] + private static extern void exclude_native_symbol (); + } +} + +// Testing namespace renaming; this should be NSTo within test.h +namespace MakeMap.ToBeRenamed { + [Map] + class Stat { + // this should be st_atime_ in test.h due to --rename-member. + [Map ("time_t")] public long st_atime; + } + + [Map] + enum Colors { + Red, Blue, Green + } +} + diff --git a/create-native-map/src/create-native-map.cs b/create-native-map/src/create-native-map.cs new file mode 100644 index 00000000..459c7fba --- /dev/null +++ b/create-native-map/src/create-native-map.cs @@ -0,0 +1,1679 @@ +// +// create-native-map.cs: Builds a C map of constants defined on C# land +// +// Authors: +// Miguel de Icaza (miguel@novell.com) +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2003 Novell, Inc. +// (C) 2004-2005 Jonathan Pryor +// + +// +// 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. +// +using System; +using System.Collections.Generic; +using System.IO; +using System.Globalization; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; +using System.Text.RegularExpressions; + +using Mono.Unix.Native; + +delegate void CreateFileHandler (string assembly_name, string file_prefix); +delegate void AssemblyAttributesHandler (Assembly assembly); +delegate void TypeHandler (Type t, string ns, string fn); +delegate void CloseFileHandler (string file_prefix); + +class MakeMap { + + public static int Main (string [] args) + { + FileGenerator[] generators = new FileGenerator[]{ + new HeaderFileGenerator (), + new SourceFileGenerator (), + new ConvertFileGenerator (), + new ConvertDocFileGenerator (), + }; + + Configuration config = new Configuration (); + bool exit = false; + try { + exit = !config.Parse (args); + } + catch (Exception e) { + Console.WriteLine ("{0}: error: {1}", + Environment.GetCommandLineArgs () [0], e.Message); + exit = true; + } + if (exit) { + Configuration.ShowHelp (); + return 1; + } + + MapUtils.config = config; + + MakeMap composite = new MakeMap (); + foreach (FileGenerator g in generators) { + g.Configuration = config; + composite.FileCreators += new CreateFileHandler (g.CreateFile); + composite.AssemblyAttributesHandler += + new AssemblyAttributesHandler (g.WriteAssemblyAttributes); + composite.TypeHandler += new TypeHandler (g.WriteType); + composite.FileClosers += new CloseFileHandler (g.CloseFile); + } + + return composite.Run (config); + } + + event CreateFileHandler FileCreators; + event AssemblyAttributesHandler AssemblyAttributesHandler; + event TypeHandler TypeHandler; + event CloseFileHandler FileClosers; + + int Run (Configuration config) + { + FileCreators (config.AssemblyFileName, config.OutputPrefix); + + Assembly assembly = Assembly.LoadFrom (config.AssemblyFileName); + AssemblyAttributesHandler (assembly); + + Type [] exported_types = assembly.GetTypes (); + Array.Sort (exported_types, new TypeFullNameComparer ()); + + foreach (Type t in exported_types) { + string ns = MapUtils.GetNamespace (t); + /* + if (ns == null || !ns.StartsWith ("Mono")) + continue; + */ + string fn = MapUtils.GetManagedType (t); + + TypeHandler (t, ns, fn); + } + FileClosers (config.OutputPrefix); + + return 0; + } + + private class TypeFullNameComparer : IComparer<Type> { + public int Compare (Type t1, Type t2) + { + if (t1 == t2) + return 0; + if (t1 == null) + return 1; + if (t2 == null) + return -1; + return CultureInfo.InvariantCulture.CompareInfo.Compare ( + t1.FullName, t2.FullName, CompareOptions.Ordinal); + } + } +} + +class Configuration { + Dictionary<string, string> renameMembers = new Dictionary<string, string> (); + Dictionary<string, string> renameNamespaces = new Dictionary<string, string> (); + List<string> libraries = new List<string>(); + List<string> optionals = new List<string> (); + List<string> excludes = new List<string> (); + List<string> iheaders = new List<string> (); + List<string> pheaders = new List<string> (); + List<string> imacros = new List<string> (); + List<string> pmacros = new List<string> (); + string assembly_name; + string output; + + delegate void ArgumentHandler (Configuration c, string name, string value); + static Dictionary<string, ArgumentHandler> handlers; + + static Configuration () + { + handlers = new Dictionary <string, ArgumentHandler> (); + handlers ["autoconf-header"] = delegate (Configuration c, string name, string value) { + c.iheaders.Add ("ah:" + name); + }; + handlers ["autoconf-member"] = delegate (Configuration c, string name, string value) { + c.optionals.Add (name); + }; + handlers ["impl-header"] = delegate (Configuration c, string name, string value) { + c.iheaders.Add (name); + }; + handlers ["impl-macro"] = delegate (Configuration c, string name, string value) { + if (value != null) + name += "=" + value; + c.imacros.Add (name); + }; + handlers ["library"] = delegate (Configuration c, string name, string value) { + c.libraries.Add (name); + }; + handlers ["exclude-native-symbol"] = delegate (Configuration c, string name, string value) { + c.excludes.Add (name); + }; + handlers ["public-header"] = delegate (Configuration c, string name, string value) { + c.pheaders.Add (name); + }; + handlers ["public-macro"] = delegate (Configuration c, string name, string value) { + if (value != null) + name += "=" + value; + c.pmacros.Add (name); + }; + handlers ["rename-member"] = delegate (Configuration c, string name, string value) { + if (value == null) { + throw new Exception ("missing rename value"); + } + c.renameMembers [name] = value; + }; + handlers ["rename-namespace"] = delegate (Configuration c, string name, string value) { + if (value == null) { + throw new Exception ("missing rename value"); + } + value = value.Replace (".", "_"); + c.renameNamespaces [name] = value; + }; + } + + public Configuration () + { + } + + public List<string> NativeLibraries { + get {return libraries;} + } + + public List<string> AutoconfMembers { + get {return optionals;} + } + + public List<string> NativeExcludeSymbols { + get {return excludes;} + } + + public List<string> PublicHeaders { + get {return pheaders;} + } + + public List<string> PublicMacros { + get {return pmacros;} + } + + public List<string> ImplementationHeaders { + get {return iheaders;} + } + + public List<string> ImplementationMacros { + get {return imacros;} + } + + public IDictionary<string, string> MemberRenames { + get {return renameMembers;} + } + + public IDictionary<string, string> NamespaceRenames { + get {return renameNamespaces;} + } + + public string AssemblyFileName { + get {return assembly_name;} + } + + public string OutputPrefix { + get {return output;} + } + + const string NameValue = @"(?<Name>[^=]+)(=(?<Value>.*))?"; + const string Argument = @"^--(?<Argument>[\w-]+)([=:]" + NameValue + ")?$"; + + public bool Parse (string[] args) + { + Regex argRE = new Regex (Argument); + Regex valRE = new Regex (NameValue); + + for (int i = 0; i < args.Length; ++i) { + Match m = argRE.Match (args [i]); + if (m.Success) { + string arg = m.Groups ["Argument"].Value; + if (arg == "help") + return false; + if (!m.Groups ["Name"].Success) { + if ((i+1) >= args.Length) + throw new Exception ( + string.Format ("missing value for argument {0}", args [i])); + m = valRE.Match (args [++i]); + if (!m.Success) { + throw new Exception ( + string.Format ("invalid value for argument {0}: {1}", + args [i-1], args[i])); + } + } + string name = m.Groups ["Name"].Value; + string value = m.Groups ["Value"].Success ? m.Groups ["Value"].Value : null; + if (handlers.ContainsKey (arg)) { + handlers [arg] (this, name, value); + } + else { + throw new Exception ("invalid argument " + arg); + } + } + else if (assembly_name == null) { + assembly_name = args [i]; + } + else { + output = args [i]; + } + } + + if (assembly_name == null) + throw new Exception ("missing ASSEMBLY"); + if (output == null) + throw new Exception ("missing OUTPUT-PREFIX"); + + libraries.Sort (); + optionals.Sort (); + excludes.Sort (); + + return true; + } + + public static void ShowHelp () + { + Console.WriteLine ( + "Usage: create-native-map \n" + + "\t[--autoconf-header=HEADER]* \n" + + "\t[--autoconf-member=MEMBER]* \n" + + "\t[--exclude-native-symbol=SYMBOL]*\n" + + "\t[--impl-header=HEADER]* \n" + + "\t[--impl-macro=MACRO]* \n" + + "\t[--library=LIBRARY]+ \n" + + "\t[--public-header=HEADER]* \n" + + "\t[--public-macro=MACRO]* \n" + + "\t[--rename-member=FROM=TO]* \n" + + "\t[--rename-namespace=FROM=TO]*\n" + + "\tASSEMBLY OUTPUT-PREFIX" + ); + } +} + +static class MapUtils { + internal static Configuration config; + + public static T GetCustomAttribute <T> (MemberInfo element) where T : Attribute + { + return (T) Attribute.GetCustomAttribute (element, typeof(T), true); + } + + public static T GetCustomAttribute <T> (Assembly assembly) where T : Attribute + { + return (T) Attribute.GetCustomAttribute (assembly, typeof(T), true); + } + + public static T[] GetCustomAttributes <T> (MemberInfo element) where T : Attribute + { + return (T[]) Attribute.GetCustomAttributes (element, typeof(T), true); + } + + public static T[] GetCustomAttributes <T> (Assembly assembly) where T : Attribute + { + return (T[]) Attribute.GetCustomAttributes (assembly, typeof(T), true); + } + + public static MapAttribute GetMapAttribute (ICustomAttributeProvider element) + { + foreach (object o in element.GetCustomAttributes (true)) { + if (!IsMapAttribute (o)) + continue; + string nativeType = GetPropertyValue (o, "NativeType"); + MapAttribute map = nativeType == null + ? new MapAttribute () + : new MapAttribute (nativeType); + return map; + } + return null; + } + + private static bool IsMapAttribute (object o) + { + Type t = o.GetType (); + do { + if (t.Name == "MapAttribute") { + return true; + } + t = t.BaseType; + } while (t != null); + return false; + } + + private static string GetPropertyValue (object o, string property) + { + PropertyInfo p = o.GetType().GetProperty (property); + if (p == null) + return null; + if (!p.CanRead) + return null; + object v = p.GetValue (o, new object[0]); + string s = v == null ? null : v.ToString (); + if (s != null) + return s.Length == 0 ? null : s; + return null; + } + + public static bool IsIntegralType (Type t) + { + return t == typeof(byte) || t == typeof(sbyte) || t == typeof(char) || + t == typeof(short) || t == typeof(ushort) || + t == typeof(int) || t == typeof(uint) || + t == typeof(long) || t == typeof(ulong); + } + + public static bool IsBlittableType (Type t) + { + return IsIntegralType (t) || t == typeof(IntPtr) || t == typeof(UIntPtr); + } + + public static string GetNativeType (Type t) + { + Type et = GetElementType (t); + string ut = et.Name; + if (et.IsEnum) + ut = Enum.GetUnderlyingType (et).Name; + + string type = null; + + switch (ut) { + case "Boolean": type = "int"; break; + case "Byte": type = "unsigned char"; break; + case "SByte": type = "signed char"; break; + case "Int16": type = "short"; break; + case "UInt16": type = "unsigned short"; break; + case "Int32": type = "int"; break; + case "UInt32": type = "unsigned int"; break; + case "Int64": type = "gint64"; break; + case "UInt64": type = "guint64"; break; + case "IntPtr": type = "void*"; break; + case "UIntPtr": type = "void*"; break; + case "String": type = "const char"; break; /* ref type */ + case "StringBuilder": type = "char"; break; /* ref type */ + case "Void": type = "void"; break; + case "HandleRef": type = "void*"; break; + } + bool isDelegate = IsDelegate (t); + if (type == null) + type = isDelegate ? t.Name : GetStructName (t); + if (!et.IsValueType && !isDelegate) { + type += "*"; + } + while (t.HasElementType) { + t = t.GetElementType (); + type += "*"; + } + return type; + //return (t.IsByRef || t.IsArray || (!t.IsValueType && !isDelegate)) ? type + "*" : type; + } + + public static bool IsDelegate (Type t) + { + return typeof(Delegate).IsAssignableFrom (t); + } + + private static string GetStructName (Type t) + { + t = GetElementType (t); + return "struct " + GetManagedType (t); + } + + public static Type GetElementType (Type t) + { + while (t.HasElementType) { + t = t.GetElementType (); + } + return t; + } + + public static string GetNamespace (Type t) + { + if (t.Namespace == null) + return ""; + if (config.NamespaceRenames.ContainsKey (t.Namespace)) + return config.NamespaceRenames [t.Namespace]; +#if false + /* this is legacy behavior; Mono.Posix.dll should be fixed to use + * MapAttribute.ExportPrefix so we don't need this hack anymore */ + if (t.Namespace == "Mono.Unix.Native" || t.Namespace == "Mono.Unix") + return "Mono_Posix"; +#endif + return t.Namespace.Replace ('.', '_'); + } + + public static string GetManagedType (Type t) + { + string ns = GetNamespace (t); + string tn = + (t.DeclaringType != null ? t.DeclaringType.Name + "_" : "") + t.Name; + return ns + "_" + tn; + } + + public static string GetNativeType (FieldInfo field) + { + MapAttribute map = + GetMapAttribute (field) + ?? + GetMapAttribute (field.FieldType); + if (map != null) + return map.NativeType; + return null; + } + + public static string GetFunctionDeclaration (string name, MethodInfo method) + { + StringBuilder sb = new StringBuilder (); +#if false + Console.WriteLine (t); + foreach (object o in t.GetMembers ()) + Console.WriteLine ("\t" + o); +#endif + sb.Append (method.ReturnType == typeof(string) + ? "char*" + : MapUtils.GetNativeType (method.ReturnType)); + sb.Append (" ").Append (name).Append (" ("); + + + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length == 0) { + sb.Append ("void"); + } + else { + if (parameters.Length > 0) { + WriteParameterDeclaration (sb, parameters [0]); + } + for (int i = 1; i < parameters.Length; ++i) { + sb.Append (", "); + WriteParameterDeclaration (sb, parameters [i]); + } + } + sb.Append (")"); + return sb.ToString (); + } + + private static void WriteParameterDeclaration (StringBuilder sb, ParameterInfo pi) + { + // DumpTypeInfo (pi.ParameterType); + string nt = GetNativeType (pi.ParameterType); + sb.AppendFormat ("{0} {1}", nt, pi.Name); + } + + internal class _MemberNameComparer : IComparer<MemberInfo>, IComparer <FieldInfo> { + public int Compare (FieldInfo m1, FieldInfo m2) + { + return Compare ((MemberInfo) m1, (MemberInfo) m2); + } + + public int Compare (MemberInfo m1, MemberInfo m2) + { + if (m1 == m2) + return 0; + if (m1 == null) + return 1; + if (m2 == null) + return -1; + return CultureInfo.InvariantCulture.CompareInfo.Compare ( + m1.Name, m2.Name, CompareOptions.Ordinal); + } + } + + private class _OrdinalStringComparer : IComparer<string> { + public int Compare (string s1, string s2) + { + if (object.ReferenceEquals (s1, s2)) + return 0; + if (s1 == null) + return 1; + if (s2 == null) + return -1; + return CultureInfo.InvariantCulture.CompareInfo.Compare (s1, s2, + CompareOptions.Ordinal); + } + } + + internal static _MemberNameComparer MemberNameComparer = new _MemberNameComparer (); + internal static IComparer<string> OrdinalStringComparer = new _OrdinalStringComparer (); +} + +abstract class FileGenerator { + private Configuration config; + + public Configuration Configuration { + get {return config;} + set {config = value;} + } + + public abstract void CreateFile (string assembly_name, string file_prefix); + + public virtual void WriteAssemblyAttributes (Assembly assembly) + { + } + + public abstract void WriteType (Type t, string ns, string fn); + public abstract void CloseFile (string file_prefix); + + protected static void WriteHeader (StreamWriter s, string assembly) + { + WriteHeader (s, assembly, false); + } + + protected static void WriteHeader (StreamWriter s, string assembly, bool noConfig) + { + s.WriteLine ( + "/*\n" + + " * This file was automatically generated by create-native-map from {0}.\n" + + " *\n" + + " * DO NOT MODIFY.\n" + + " */", + assembly); + if (!noConfig) { + s.WriteLine ("#ifdef HAVE_CONFIG_H"); + s.WriteLine ("#include <config.h>"); + s.WriteLine ("#endif /* ndef HAVE_CONFIG_H */"); + } + s.WriteLine (); + } + + protected static bool CanMapType (Type t) + { + return MapUtils.GetMapAttribute (t) != null; + } + + protected static bool IsFlagsEnum (Type t) + { + return t.IsEnum && + MapUtils.GetCustomAttributes <FlagsAttribute> (t).Length > 0; + } + + protected static void SortFieldsInOffsetOrder (Type t, FieldInfo[] fields) + { + Array.Sort (fields, delegate (FieldInfo f1, FieldInfo f2) { + long o1 = (long) Marshal.OffsetOf (f1.DeclaringType, f1.Name); + long o2 = (long) Marshal.OffsetOf (f2.DeclaringType, f2.Name); + return o1.CompareTo (o2); + }); + } + + protected static void WriteMacroDefinition (TextWriter writer, string macro) + { + if (macro == null || macro.Length == 0) + return; + string[] val = macro.Split ('='); + writer.WriteLine ("#ifndef {0}", val [0]); + writer.WriteLine ("#define {0}{1}", val [0], + val.Length > 1 ? " " + val [1] : ""); + writer.WriteLine ("#endif /* ndef {0} */", val [0]); + writer.WriteLine (); + } + + private static Regex includeRegex = new Regex (@"^(?<AutoHeader>ah:)?(?<Include>(""|<)(?<IncludeFile>.*)(""|>))$"); + + protected static void WriteIncludeDeclaration (TextWriter writer, string inc) + { + if (inc == null || inc.Length == 0) + return; + Match m = includeRegex.Match (inc); + if (!m.Groups ["Include"].Success) { + Console.WriteLine ("warning: invalid PublicIncludeFile: {0}", inc); + return; + } + if (m.Success && m.Groups ["AutoHeader"].Success) { + string i = m.Groups ["IncludeFile"].Value; + string def = "HAVE_" + i.ToUpper ().Replace ("/", "_").Replace (".", "_"); + writer.WriteLine ("#ifdef {0}", def); + writer.WriteLine ("#include {0}", m.Groups ["Include"]); + writer.WriteLine ("#endif /* ndef {0} */", def); + } + else + writer.WriteLine ("#include {0}", m.Groups ["Include"]); + } + + protected string GetNativeMemberName (FieldInfo field) + { + if (!Configuration.MemberRenames.ContainsKey (field.Name)) + return field.Name; + return Configuration.MemberRenames [field.Name]; + } +} + +class HeaderFileGenerator : FileGenerator { + StreamWriter sh; + string assembly_file; + Dictionary<string, MethodInfo> methods = new Dictionary <string, MethodInfo> (); + Dictionary<string, Type> structs = new Dictionary <string, Type> (); + Dictionary<string, MethodInfo> delegates = new Dictionary <string, MethodInfo> (); + List<string> decls = new List <string> (); + + public override void CreateFile (string assembly_name, string file_prefix) + { + sh = File.CreateText (file_prefix + ".h"); + file_prefix = file_prefix.Replace ("../", "").Replace ("/", "_"); + this.assembly_file = assembly_name = Path.GetFileName (assembly_name); + WriteHeader (sh, assembly_name, true); + assembly_name = assembly_name.Replace (".dll", "").Replace (".", "_"); + sh.WriteLine ("#ifndef INC_" + assembly_name + "_" + file_prefix + "_H"); + sh.WriteLine ("#define INC_" + assembly_name + "_" + file_prefix + "_H\n"); + sh.WriteLine ("#include <glib.h>\n"); + sh.WriteLine ("G_BEGIN_DECLS\n"); + + // Kill warning about unused method + DumpTypeInfo (null); + } + + public override void WriteAssemblyAttributes (Assembly assembly) + { + sh.WriteLine ("/*\n * Public Macros\n */"); + foreach (string def in Configuration.PublicMacros) { + WriteMacroDefinition (sh, def); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Public Includes\n */"); + foreach (string inc in Configuration.PublicHeaders) { + WriteIncludeDeclaration (sh, inc); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Enumerations\n */"); + } + + public override void WriteType (Type t, string ns, string fn) + { + WriteEnum (t, ns, fn); + CacheStructs (t, ns, fn); + CacheExternalMethods (t, ns, fn); + } + + private void WriteEnum (Type t, string ns, string fn) + { + if (!CanMapType (t) || !t.IsEnum) + return; + + string etype = MapUtils.GetNativeType (t); + + WriteLiteralValues (sh, t, fn); + sh.WriteLine ("int {1}_From{2} ({0} x, {0} *r);", etype, ns, t.Name); + sh.WriteLine ("int {1}_To{2} ({0} x, {0} *r);", etype, ns, t.Name); + Configuration.NativeExcludeSymbols.Add ( + string.Format ("{1}_From{2}", etype, ns, t.Name)); + Configuration.NativeExcludeSymbols.Add ( + string.Format ("{1}_To{2}", etype, ns, t.Name)); + Configuration.NativeExcludeSymbols.Sort (); + sh.WriteLine (); + } + + static void WriteLiteralValues (StreamWriter sh, Type t, string n) + { + object inst = Activator.CreateInstance (t); + int max_field_length = 0; + FieldInfo[] fields = t.GetFields (); + Array.Sort (fields, delegate (FieldInfo f1, FieldInfo f2) { + max_field_length = Math.Max (max_field_length, f1.Name.Length); + max_field_length = Math.Max (max_field_length, f2.Name.Length); + return MapUtils.MemberNameComparer.Compare (f1, f2); + }); + max_field_length += 1 + n.Length; + sh.WriteLine ("enum {0} {{", n); + foreach (FieldInfo fi in fields) { + if (!fi.IsLiteral) + continue; + string e = n + "_" + fi.Name; + sh.WriteLine ("\t{0,-" + max_field_length + "} = 0x{1:x},", + e, fi.GetValue (inst)); + sh.WriteLine ("\t#define {0,-" + max_field_length + "} {0}", e); + } + sh.WriteLine ("};"); + } + + + private void CacheStructs (Type t, string ns, string fn) + { + if (t.IsEnum) + return; + MapAttribute map = MapUtils.GetMapAttribute (t); + if (map != null) { + if (map.NativeType != null && map.NativeType.Length > 0) + decls.Add (map.NativeType); + RecordTypes (t); + } + } + + private void CacheExternalMethods (Type t, string ns, string fn) + { + BindingFlags bf = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + foreach (MethodInfo m in t.GetMethods (bf)) { + if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) + continue; + DllImportAttribute dia = GetDllImportInfo (m); + if (dia == null) { + Console.WriteLine ("warning: unable to emit native prototype for P/Invoke " + + "method: {0}", m); + continue; + } + // we shouldn't declare prototypes for POSIX, etc. functions. + if (Configuration.NativeLibraries.BinarySearch (dia.Value) < 0 || + IsOnExcludeList (dia.EntryPoint)) + continue; + methods [dia.EntryPoint] = m; + RecordTypes (m); + } + } + + private static DllImportAttribute GetDllImportInfo (MethodInfo method) + { + // .NET 2.0 synthesizes pseudo-attributes such as DllImport + DllImportAttribute dia = MapUtils.GetCustomAttribute <DllImportAttribute> (method); + if (dia != null) + return dia; + + // We're not on .NET 2.0; assume we're on Mono and use some internal + // methods... + Type MonoMethod = Type.GetType ("System.Reflection.MonoMethod", false); + if (MonoMethod == null) { + Console.WriteLine ("warning: cannot find MonoMethod"); + return null; + } + MethodInfo GetDllImportAttribute = + MonoMethod.GetMethod ("GetDllImportAttribute", + BindingFlags.Static | BindingFlags.NonPublic); + if (GetDllImportAttribute == null) { + Console.WriteLine ("warning: cannot find GetDllImportAttribute"); + return null; + } + IntPtr mhandle = method.MethodHandle.Value; + return (DllImportAttribute) GetDllImportAttribute.Invoke (null, + new object[]{mhandle}); + } + + private bool IsOnExcludeList (string method) + { + int idx = Configuration.NativeExcludeSymbols.BinarySearch (method); + return (idx < 0) ? false : true; + } + + private void RecordTypes (MethodInfo method) + { + ParameterInfo[] parameters = method.GetParameters (); + foreach (ParameterInfo pi in parameters) { + RecordTypes (pi.ParameterType); + } + } + + private void RecordTypes (Type st) + { + if (typeof(Delegate).IsAssignableFrom (st) && !delegates.ContainsKey (st.Name)) { + MethodInfo mi = st.GetMethod ("Invoke"); + delegates [st.Name] = mi; + RecordTypes (mi); + return; + } + Type et = MapUtils.GetElementType (st); + string s = MapUtils.GetNativeType (et); + if (s.StartsWith ("struct ") && !structs.ContainsKey (et.Name)) { + structs [et.Name] = et; + foreach (FieldInfo fi in et.GetFields (BindingFlags.Instance | + BindingFlags.Public | BindingFlags.NonPublic)) { + RecordTypes (fi.FieldType); + } + } + } + + public override void CloseFile (string file_prefix) + { + IEnumerable<string> structures = Sort (structs.Keys); + sh.WriteLine (); + sh.WriteLine ("/*\n * Managed Structure Declarations\n */\n"); + foreach (string s in structures) { + sh.WriteLine ("struct {0};", MapUtils.GetManagedType (structs [s])); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Inferred Structure Declarations\n */\n"); + foreach (string s in decls) { + sh.WriteLine ("{0};", s); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Delegate Declarations\n */\n"); + foreach (string s in Sort (delegates.Keys)) { + sh.WriteLine ("typedef {0};", + MapUtils.GetFunctionDeclaration ("(*" + s + ")", delegates [s])); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Structures\n */\n"); + foreach (string s in structures) { + WriteStructDeclarations (s); + } + sh.WriteLine (); + + sh.WriteLine ("/*\n * Functions\n */"); + foreach (string method in Configuration.NativeExcludeSymbols) { + if (methods.ContainsKey (method)) + methods.Remove (method); + } + foreach (string method in Sort (methods.Keys)) { + WriteMethodDeclaration ((MethodInfo) methods [method], method); + } + + sh.WriteLine ("\nG_END_DECLS\n"); + sh.WriteLine ("#endif /* ndef INC_Mono_Posix_" + file_prefix + "_H */\n"); + sh.Close (); + } + + private static IEnumerable<string> Sort (ICollection<string> c) + { + List<string> al = new List<string> (c); + al.Sort (MapUtils.OrdinalStringComparer); + return al; + } + + private void WriteStructDeclarations (string s) + { + Type t = structs [s]; +#if false + if (!t.Assembly.CodeBase.EndsWith (this.assembly_file)) { + return; + } +#endif + sh.WriteLine ("struct {0} {{", MapUtils.GetManagedType (t)); + FieldInfo[] fields = t.GetFields (BindingFlags.Instance | + BindingFlags.Public | BindingFlags.NonPublic); + int max_type_len = 0, max_name_len = 0, max_native_len = 0; + Array.ForEach (fields, delegate (FieldInfo f) { + max_type_len = Math.Max (max_type_len, HeaderFileGenerator.GetType (f.FieldType).Length); + max_name_len = Math.Max (max_name_len, GetNativeMemberName (f).Length); + string native_type = MapUtils.GetNativeType (f); + if (native_type != null) + max_native_len = Math.Max (max_native_len, native_type.Length); + }); + SortFieldsInOffsetOrder (t, fields); + foreach (FieldInfo field in fields) { + string fname = GetNativeMemberName (field); + sh.Write ("\t{0,-" + max_type_len + "} {1};", + GetType (field.FieldType), fname); + string native_type = MapUtils.GetNativeType (field); + if (native_type != null) { + sh.Write (new string (' ', max_name_len - fname.Length)); + sh.Write (" /* {0,-" + max_native_len + "} */", native_type); + } + sh.WriteLine (); + } + sh.WriteLine ("};"); + MapAttribute map = MapUtils.GetMapAttribute (t); + if (map != null && map.NativeType != null && map.NativeType.Length != 0 && + t.Assembly.CodeBase.EndsWith (this.assembly_file)) { + sh.WriteLine (); + sh.WriteLine ( + "int\n{0}_From{1} ({3}{4} from, {2} *to);\n" + + "int\n{0}_To{1} ({2} *from, {3}{4} to);\n", + MapUtils.GetNamespace (t), t.Name, map.NativeType, + MapUtils.GetNativeType (t), t.IsValueType ? "*" : ""); + Configuration.NativeExcludeSymbols.Add ( + string.Format ("{0}_From{1}", MapUtils.GetNamespace (t), t.Name)); + Configuration.NativeExcludeSymbols.Add ( + string.Format ("{0}_To{1}", MapUtils.GetNamespace (t), t.Name)); + Configuration.NativeExcludeSymbols.Sort (); + } + sh.WriteLine (); + } + + private static string GetType (Type t) + { + if (typeof(Delegate).IsAssignableFrom (t)) + return t.Name; + return MapUtils.GetNativeType (t); + } + + private void WriteMethodDeclaration (MethodInfo method, string entryPoint) + { + if (method.ReturnType.IsClass) { + Console.WriteLine ("warning: {0} has a return type of {1}, which is a reference type", + entryPoint, method.ReturnType.FullName); + } + sh.Write (MapUtils.GetFunctionDeclaration (entryPoint, method)); + sh.WriteLine (";"); + +#if false + sh.WriteLine ("{0} ", method.ReturnType == typeof(string) + ? "char*" + : MapUtils.GetNativeType (method.ReturnType)); + sh.Write ("{0} ", entryPoint); + ParameterInfo[] parameters = method.GetParameters(); + if (parameters.Length == 0) { + sh.WriteLine ("(void);"); + return; + } + if (parameters.Length > 0) { + sh.Write ("("); + WriteParameterDeclaration (parameters [0]); + } + for (int i = 1; i < parameters.Length; ++i) { + sh.Write (", "); + WriteParameterDeclaration (parameters [i]); + } + sh.WriteLine (");"); +#endif + } + + private void DumpTypeInfo (Type t) + { + if (t == null) + return; + + sh.WriteLine ("\t\t/* Type Info for " + t.FullName + ":"); + foreach (MemberInfo mi in typeof(Type).GetMembers()) { + sh.WriteLine ("\t\t\t{0}={1}", mi.Name, GetMemberValue (mi, t)); + } + sh.WriteLine ("\t\t */"); + } + + private static string GetMemberValue (MemberInfo mi, Type t) + { + try { + switch (mi.MemberType) { + case MemberTypes.Constructor: + case MemberTypes.Method: { + MethodBase b = (MethodBase) mi; + if (b.GetParameters().Length == 0) + return b.Invoke (t, new object[]{}).ToString(); + return "<<cannot invoke>>"; + } + case MemberTypes.Field: + return ((FieldInfo) mi).GetValue (t).ToString (); + case MemberTypes.Property: { + PropertyInfo pi = (PropertyInfo) mi; + if (!pi.CanRead) + return "<<cannot read>>"; + return pi.GetValue (t, null).ToString (); + } + default: + return "<<unknown value>>"; + } + } + catch (Exception e) { + return "<<exception reading member: " + e.Message + ">>"; + } + } + + private void WriteParameterDeclaration (ParameterInfo pi) + { + // DumpTypeInfo (pi.ParameterType); + string nt = MapUtils.GetNativeType (pi.ParameterType); + sh.Write ("{0} {1}", nt, pi.Name); + } +} + +class SourceFileGenerator : FileGenerator { + StreamWriter sc; + string file_prefix; + + public override void CreateFile (string assembly_name, string file_prefix) + { + sc = File.CreateText (file_prefix + ".c"); + WriteHeader (sc, assembly_name); + + if (file_prefix.IndexOf ("/") != -1) + file_prefix = file_prefix.Substring (file_prefix.IndexOf ("/") + 1); + this.file_prefix = file_prefix; + sc.WriteLine ("#include <stdlib.h>"); + sc.WriteLine ("#include <string.h>"); + sc.WriteLine (); + } + + public override void WriteAssemblyAttributes (Assembly assembly) + { + sc.WriteLine ("/*\n * Implementation Macros\n */"); + foreach (string def in Configuration.ImplementationMacros) { + WriteMacroDefinition (sc, def); + } + sc.WriteLine (); + + sc.WriteLine ("/*\n * Implementation Includes\n */"); + foreach (string inc in Configuration.ImplementationHeaders) { + WriteIncludeDeclaration (sc, inc); + } + sc.WriteLine (); + + sc.WriteLine ("#include \"{0}.h\"", file_prefix); + + sc.WriteLine (@" +#include <errno.h> /* errno, EOVERFLOW */ +#include <glib.h> /* g* types, g_assert_not_reached() */ + +/* returns TRUE if @type is an unsigned type */ +#define _cnm_integral_type_is_unsigned(type) \ + (sizeof(type) == sizeof(gint8) \ + ? (((type)-1) > G_MAXINT8) \ + : sizeof(type) == sizeof(gint16) \ + ? (((type)-1) > G_MAXINT16) \ + : sizeof(type) == sizeof(gint32) \ + ? (((type)-1) > G_MAXINT32) \ + : sizeof(type) == sizeof(gint64) \ + ? (((type)-1) > G_MAXINT64) \ + : (g_assert_not_reached (), 0)) + +/* returns the minimum value of @type as a gint64 */ +#define _cnm_integral_type_min(type) \ + (_cnm_integral_type_is_unsigned (type) \ + ? 0 \ + : sizeof(type) == sizeof(gint8) \ + ? G_MININT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MININT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MININT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MININT64 \ + : (g_assert_not_reached (), 0)) + +/* returns the maximum value of @type as a guint64 */ +#define _cnm_integral_type_max(type) \ + (_cnm_integral_type_is_unsigned (type) \ + ? sizeof(type) == sizeof(gint8) \ + ? G_MAXUINT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MAXUINT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MAXUINT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MAXUINT64 \ + : (g_assert_not_reached (), 0) \ + : sizeof(type) == sizeof(gint8) \ + ? G_MAXINT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MAXINT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MAXINT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MAXINT64 \ + : (g_assert_not_reached (), 0)) + +#ifdef DEBUG +#define _cnm_dump_(to_t,from) \ + printf (""# %s -> %s: min=%llx; max=%llx; value=%llx; lt=%i; l0=%i; gt=%i; e=%i\n"", \ + #from, #to_t, \ + (gint64) (_cnm_integral_type_min(to_t)), \ + (gint64) (_cnm_integral_type_max (to_t)), \ + (gint64) (from), \ + (_cnm_integral_type_min (to_t) <= from), \ + (from < 0), \ + /* (_cnm_integral_type_max (to_t) >= from) */ \ + (from <= _cnm_integral_type_max (to_t)), \ + ((_cnm_integral_type_min(to_t) >= from) && \ + ((from < 0) ? 1 : (from <= _cnm_integral_type_max(to_t)))) \ + ) +#else +#define _cnm_dump_(to_t, from) do {} while (0) +#endif + +#define _cnm_return_val_if_overflow(to_t,from,val) G_STMT_START { \ + if (!(_cnm_integral_type_min(to_t) <= from && \ + ((from < 0) || (from <= _cnm_integral_type_max(to_t))))) { \ + _cnm_dump_(to_t, from); \ + errno = EOVERFLOW; \ + return (val); \ + } \ + } G_STMT_END +"); + } + + public override void WriteType (Type t, string ns, string fn) + { + if (!CanMapType (t)) + return; + + string etype = MapUtils.GetNativeType (t); + + if (t.IsEnum) { + bool bits = IsFlagsEnum (t); + + WriteFromManagedEnum (t, ns, fn, etype, bits); + WriteToManagedEnum (t, ns, fn, etype, bits); + } + else { + WriteFromManagedClass (t, ns, fn, etype); + WriteToManagedClass (t, ns, fn, etype); + } + } + + private void WriteFromManagedEnum (Type t, string ns, string fn, string etype, bool bits) + { + sc.WriteLine ("int {1}_From{2} ({0} x, {0} *r)", etype, ns, t.Name); + sc.WriteLine ("{"); + sc.WriteLine ("\t*r = 0;"); + FieldInfo[] fields = t.GetFields (); + Array.Sort<FieldInfo> (fields, MapUtils.MemberNameComparer); + foreach (FieldInfo fi in fields) { + if (!fi.IsLiteral) + continue; + if (MapUtils.GetCustomAttribute<ObsoleteAttribute> (fi) != null) { + sc.WriteLine ("\t/* {0}_{1} is obsolete or optional; ignoring */", fn, fi.Name); + continue; + } + if (bits) + // properly handle case where [Flags] enumeration has helper + // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t. + sc.WriteLine ("\tif ((x & {0}_{1}) == {0}_{1})", fn, fi.Name); + else + sc.WriteLine ("\tif (x == {0}_{1})", fn, fi.Name); + sc.WriteLine ("#ifdef {0}", fi.Name); + if (bits) + sc.WriteLine ("\t\t*r |= {1};", fn, fi.Name); + else + sc.WriteLine ("\t\t{{*r = {1}; return 0;}}", fn, fi.Name); + sc.WriteLine ("#else /* def {0} */\n\t\t{{errno = EINVAL; return -1;}}", fi.Name); + sc.WriteLine ("#endif /* ndef {0} */", fi.Name); + } + // For many values, 0 is a valid value, but doesn't have it's own symbol. + // Examples: Error (0 means "no error"), WaitOptions (0 means "no options"). + // Make 0 valid for all conversions. + sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;"); + if (bits) + sc.WriteLine ("\treturn 0;"); + else + sc.WriteLine ("\terrno = EINVAL; return -1;"); // return error if not matched + sc.WriteLine ("}\n"); + } + + private void WriteToManagedEnum (Type t, string ns, string fn, string etype, bool bits) + { + sc.WriteLine ("int {1}_To{2} ({0} x, {0} *r)", etype, ns, t.Name); + sc.WriteLine ("{"); + sc.WriteLine ("\t*r = 0;", etype); + // For many values, 0 is a valid value, but doesn't have it's own symbol. + // Examples: Error (0 means "no error"), WaitOptions (0 means "no options"). + // Make 0 valid for all conversions. + sc.WriteLine ("\tif (x == 0)\n\t\treturn 0;"); + FieldInfo[] fields = t.GetFields (); + Array.Sort<FieldInfo> (fields, MapUtils.MemberNameComparer); + foreach (FieldInfo fi in fields) { + if (!fi.IsLiteral) + continue; + sc.WriteLine ("#ifdef {0}", fi.Name); + if (bits) + // properly handle case where [Flags] enumeration has helper + // synonyms. e.g. DEFFILEMODE and ACCESSPERMS for mode_t. + sc.WriteLine ("\tif ((x & {1}) == {1})\n\t\t*r |= {0}_{1};", fn, fi.Name); + else + sc.WriteLine ("\tif (x == {1})\n\t\t{{*r = {0}_{1}; return 0;}}", fn, fi.Name); + sc.WriteLine ("#endif /* ndef {0} */", fi.Name); + } + if (bits) + sc.WriteLine ("\treturn 0;"); + else + sc.WriteLine ("\terrno = EINVAL; return -1;"); + sc.WriteLine ("}\n"); + } + + private void WriteFromManagedClass (Type t, string ns, string fn, string etype) + { + MapAttribute map = MapUtils.GetMapAttribute (t); + if (map == null || map.NativeType == null || map.NativeType.Length == 0) + return; + sc.WriteLine ("int\n{0}_From{1} (struct {0}_{1} *from, {2} *to)", + MapUtils.GetNamespace (t), t.Name, map.NativeType); + WriteManagedClassConversion (t, delegate (FieldInfo field) { + MapAttribute ft = MapUtils.GetMapAttribute (field); + if (ft != null) + return ft.NativeType; + return MapUtils.GetNativeType (field.FieldType); + }, + delegate (FieldInfo field) { + return GetNativeMemberName (field); + }, + delegate (FieldInfo field) { + return field.Name; + }, + delegate (FieldInfo field) { + return string.Format ("{0}_From{1}", + MapUtils.GetNamespace (field.FieldType), + field.FieldType.Name); + } + ); + } + + private delegate string GetFromType (FieldInfo field); + private delegate string GetToFieldName (FieldInfo field); + private delegate string GetFromFieldName (FieldInfo field); + private delegate string GetFieldCopyMethod (FieldInfo field); + + private void WriteManagedClassConversion (Type t, GetFromType gft, + GetFromFieldName gffn, GetToFieldName gtfn, GetFieldCopyMethod gfc) + { + MapAttribute map = MapUtils.GetMapAttribute (t); + sc.WriteLine ("{"); + FieldInfo[] fields = GetFieldsToCopy (t); + SortFieldsInOffsetOrder (t, fields); + int max_len = 0; + foreach (FieldInfo f in fields) { + max_len = Math.Max (max_len, f.Name.Length); + if (!MapUtils.IsIntegralType (f.FieldType)) + continue; + string d = GetAutoconfDefine (map, f); + if (d != null) + sc.WriteLine ("#ifdef " + d); + sc.WriteLine ("\t_cnm_return_val_if_overflow ({0}, from->{1}, -1);", + gft (f), gffn (f)); + if (d != null) + sc.WriteLine ("#endif /* ndef " + d + " */"); + } + sc.WriteLine ("\n\tmemset (to, 0, sizeof(*to));\n"); + foreach (FieldInfo f in fields) { + string d = GetAutoconfDefine (map, f); + if (d != null) + sc.WriteLine ("#ifdef " + d); + if (MapUtils.IsBlittableType (f.FieldType)) { + sc.WriteLine ("\tto->{0,-" + max_len + "} = from->{1};", + gtfn (f), gffn (f)); + } + else if (f.FieldType.IsEnum) { + sc.WriteLine ("\tif ({0} (from->{1}, &to->{2}) != 0) {{", gfc (f), + gffn (f), gtfn (f)); + sc.WriteLine ("\t\treturn -1;"); + sc.WriteLine ("\t}"); + } + else if (f.FieldType.IsValueType) { + sc.WriteLine ("\tif ({0} (&from->{1}, &to->{2}) != 0) {{", gfc (f), + gffn (f), gtfn (f)); + sc.WriteLine ("\t\treturn -1;"); + sc.WriteLine ("\t}"); + } + if (d != null) + sc.WriteLine ("#endif /* ndef " + d + " */"); + } + sc.WriteLine (); + sc.WriteLine ("\treturn 0;"); + sc.WriteLine ("}\n"); + sc.WriteLine (); + } + + private void WriteToManagedClass (Type t, string ns, string fn, string etype) + { + MapAttribute map = MapUtils.GetMapAttribute (t); + if (map == null || map.NativeType == null || map.NativeType.Length == 0) + return; + sc.WriteLine ("int\n{0}_To{1} ({2} *from, struct {0}_{1} *to)", + MapUtils.GetNamespace (t), t.Name, map.NativeType); + WriteManagedClassConversion (t, delegate (FieldInfo field) { + return MapUtils.GetNativeType (field.FieldType); + }, + delegate (FieldInfo field) { + return field.Name; + }, + delegate (FieldInfo field) { + return GetNativeMemberName (field); + }, + delegate (FieldInfo field) { + return string.Format ("{0}_To{1}", + MapUtils.GetNamespace (field.FieldType), + field.FieldType.Name); + } + ); + } + + private static FieldInfo[] GetFieldsToCopy (Type t) + { + FieldInfo[] fields = t.GetFields (BindingFlags.Instance | + BindingFlags.Public | BindingFlags.NonPublic); + int count = 0; + for (int i = 0; i < fields.Length; ++i) + if (MapUtils.GetCustomAttribute <NonSerializedAttribute> (fields [i]) == null) + ++count; + FieldInfo[] rf = new FieldInfo [count]; + for (int i = 0, j = 0; i < fields.Length; ++i) { + if (MapUtils.GetCustomAttribute <NonSerializedAttribute> (fields [i]) == null) + rf [j++] = fields [i]; + } + return rf; + } + + private string GetAutoconfDefine (MapAttribute typeMap, FieldInfo field) + { + if (Configuration.AutoconfMembers.BinarySearch (field.Name) < 0 && + Configuration.AutoconfMembers.BinarySearch (field.DeclaringType.Name + "." + field.Name) < 0) + return null; + return string.Format ("HAVE_{0}_{1}", + typeMap.NativeType.ToUpperInvariant().Replace (" ", "_"), + field.Name.ToUpperInvariant ()); + } + + public override void CloseFile (string file_prefix) + { + sc.Close (); + } +} + +class ConvertFileGenerator : FileGenerator { + StreamWriter scs; + + public override void CreateFile (string assembly_name, string file_prefix) + { + scs = File.CreateText (file_prefix + ".cs"); + WriteHeader (scs, assembly_name, true); + scs.WriteLine ("using System;"); + scs.WriteLine ("using System.Runtime.InteropServices;"); + scs.WriteLine ("using Mono.Unix.Native;\n"); + scs.WriteLine ("namespace Mono.Unix.Native {\n"); + scs.WriteLine ("\tpublic sealed /* static */ partial class NativeConvert"); + scs.WriteLine ("\t{"); + scs.WriteLine ("\t\tprivate NativeConvert () {}\n"); + scs.WriteLine ("\t\tprivate const string LIB = \"{0}\";\n", Configuration.NativeLibraries[0]); + scs.WriteLine ("\t\tprivate static void ThrowArgumentException (object value)"); + scs.WriteLine ("\t\t{"); + scs.WriteLine ("\t\t\tthrow new ArgumentOutOfRangeException (\"value\", value,"); + scs.WriteLine ("\t\t\t\tLocale.GetText (\"Current platform doesn't support this value.\"));"); + scs.WriteLine ("\t\t}\n"); + } + + public override void WriteType (Type t, string ns, string fn) + { + if (!CanMapType (t)) + return; + if (t.IsEnum) + WriteEnum (t, ns, fn); + else + WriteStruct (t, ns, fn); + } + + private void WriteEnum (Type t, string ns, string fn) + { + string mtype = Enum.GetUnderlyingType(t).Name; + ObsoleteAttribute oa = MapUtils.GetCustomAttribute <ObsoleteAttribute> (t); + string obsolete = ""; + if (oa != null) { + obsolete = string.Format ("[Obsolete (\"{0}\", {1})]\n\t\t", + oa.Message, oa.IsError ? "true" : "false"); + } + scs.WriteLine ( + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_From{2}\")]\n" + + "\t\tprivate static extern int From{2} ({2} value, out {3} rval);\n" + + "\n" + + "\t\t{0}public static bool TryFrom{2} ({2} value, out {3} rval)\n" + + "\t\t{{\n" + + "\t\t\treturn From{2} (value, out rval) == 0;\n" + + "\t\t}}\n" + + "\n" + + "\t\t{0}public static {3} From{2} ({2} value)\n" + + "\t\t{{\n" + + "\t\t\t{3} rval;\n" + + "\t\t\tif (From{2} (value, out rval) == -1)\n" + + "\t\t\t\tThrowArgumentException (value);\n" + + "\t\t\treturn rval;\n" + + "\t\t}}\n" + + "\n" + + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_To{2}\")]\n" + + "\t\tprivate static extern int To{2} ({3} value, out {2} rval);\n" + + "\n" + + "\t\t{0}public static bool TryTo{2} ({3} value, out {2} rval)\n" + + "\t\t{{\n" + + "\t\t\treturn To{2} (value, out rval) == 0;\n" + + "\t\t}}\n" + + "\n" + + "\t\t{0}public static {2} To{2} ({3} value)\n" + + "\t\t{{\n" + + "\t\t\t{2} rval;\n" + + "\t\t\tif (To{2} (value, out rval) == -1)\n" + + "\t\t\t\tThrowArgumentException (value);\n" + + "\t\t\treturn rval;\n" + + "\t\t}}\n", + obsolete, ns, t.Name, mtype + ); + } + + private void WriteStruct (Type t, string ns, string fn) + { + if (MapUtils.IsDelegate (t)) + return; + MapAttribute map = MapUtils.GetMapAttribute (t); + if (map == null || map.NativeType == null || map.NativeType.Length == 0) + return; + ObsoleteAttribute oa = MapUtils.GetCustomAttribute <ObsoleteAttribute> (t); + string obsolete = ""; + if (oa != null) { + obsolete = string.Format ("[Obsolete (\"{0}\", {1})]\n\t\t", + oa.Message, oa.IsError ? "true" : "false"); + } + string _ref = t.IsValueType ? "ref " : ""; + string _out = t.IsValueType ? "out " : ""; + scs.WriteLine ( + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_From{2}\")]\n" + + "\t\tprivate static extern int From{2} ({3}{2} source, IntPtr destination);\n" + + "\n" + + "\t\t{0}public static bool TryCopy ({3}{2} source, IntPtr destination)\n" + + "\t\t{{\n" + + "\t\t\treturn From{2} ({3}source, destination) == 0;\n" + + "\t\t}}\n" + + "\n" + + "\t\t{0}[DllImport (LIB, EntryPoint=\"{1}_To{2}\")]\n" + + "\t\tprivate static extern int To{2} (IntPtr source, {4}{2} destination);\n" + + "\n" + + "\t\t{0}public static bool TryCopy (IntPtr source, {4}{2} destination)\n" + + "\t\t{{\n" + + "\t\t\treturn To{2} (source, {4}destination) == 0;\n" + + "\t\t}}\n", + obsolete, ns, t.Name, _ref, _out + ); + } + + public override void CloseFile (string file_prefix) + { + scs.WriteLine ("\t}"); + scs.WriteLine ("}\n"); + scs.Close (); + } +} + +class ConvertDocFileGenerator : FileGenerator { + StreamWriter scs; + + public override void CreateFile (string assembly_name, string file_prefix) + { + scs = File.CreateText (file_prefix + ".xml"); + scs.WriteLine (" <!-- BEGIN GENERATED CONTENT"); + WriteHeader (scs, assembly_name, true); + scs.WriteLine (" -->"); + } + + public override void WriteType (Type t, string ns, string fn) + { + if (!CanMapType (t) || !t.IsEnum) + return; + + bool bits = IsFlagsEnum (t); + + string type = GetCSharpType (t); + string mtype = Enum.GetUnderlyingType(t).FullName; + string member = t.Name; + string ftype = t.FullName; + + string to_returns = ""; + string to_remarks = ""; + string to_exception = ""; + + if (bits) { + to_returns = "<returns>An approximation of the equivalent managed value.</returns>"; + to_remarks = @"<para>The current conversion functions are unable to determine + if a value in a <c>[Flags]</c>-marked enumeration <i>does not</i> + exist on the current platform. As such, if <paramref name=""value"" /> + contains a flag value which the current platform doesn't support, it + will not be present in the managed value returned.</para> + <para>This should only be a problem if <paramref name=""value"" /> + <i>was not</i> previously returned by + <see cref=""M:Mono.Unix.Native.NativeConvert.From" + member + "\" />.</para>\n"; + } + else { + to_returns = "<returns>The equivalent managed value.</returns>"; + to_exception = @" + <exception cref=""T:System.ArgumentOutOfRangeException""> + <paramref name=""value"" /> has no equivalent managed value. + </exception> +"; + } + scs.WriteLine (@" + <Member MemberName=""TryFrom{1}""> + <MemberSignature Language=""C#"" Value=""public static bool TryFrom{1} ({0} value, out {2} rval);"" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name=""value"" Type=""{0}"" /> + <Parameter Name=""rval"" Type=""{3}&"" RefType=""out"" /> + </Parameters> + <Docs> + <param name=""value"">The managed value to convert.</param> + <param name=""rval"">The OS-specific equivalent value.</param> + <summary>Converts a <see cref=""T:{0}"" /> + enumeration value to an OS-specific value.</summary> + <returns><see langword=""true"" /> if the conversion was successful; + otherwise, <see langword=""false"" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" />.</para> + <para>If successful, this method stores the OS-specific equivalent + value of <paramref name=""value"" /> into <paramref name=""rval"" />. + Otherwise, <paramref name=""rval"" /> will contain <c>0</c>.</para> + </remarks> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" /> + </Docs> + </Member> + <Member MemberName=""From{1}""> + <MemberSignature Language=""C#"" Value=""public static {2} From{1} ({0} value);"" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>{3}</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name=""value"" Type=""{0}"" /> + </Parameters> + <Docs> + <param name=""value"">The managed value to convert.</param> + <summary>Converts a <see cref=""T:{0}"" /> + to an OS-specific value.</summary> + <returns>The equivalent OS-specific value.</returns> + <exception cref=""T:System.ArgumentOutOfRangeException""> + <paramref name=""value"" /> has no equivalent OS-specific value. + </exception> + <remarks></remarks> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" /> + </Docs> + </Member> + <Member MemberName=""TryTo{1}""> + <MemberSignature Language=""C#"" Value=""public static bool TryTo{1} ({2} value, out {0} rval);"" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name=""value"" Type=""{3}"" /> + <Parameter Name=""rval"" Type=""{0}&"" RefType=""out"" /> + </Parameters> + <Docs> + <param name=""value"">The OS-specific value to convert.</param> + <param name=""rval"">The managed equivalent value</param> + <summary>Converts an OS-specific value to a + <see cref=""T:{0}"" />.</summary> + <returns><see langword=""true"" /> if the conversion was successful; + otherwise, <see langword=""false"" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" />.</para> + <para>If successful, this method stores the managed equivalent + value of <paramref name=""value"" /> into <paramref name=""rval"" />. + Otherwise, <paramref name=""rval"" /> will contain a <c>0</c> + cast to a <see cref=""T:{0}"" />.</para> + " + to_remarks + +@" </remarks> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.To{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" /> + </Docs> + </Member> + <Member MemberName=""To{1}""> + <MemberSignature Language=""C#"" Value=""public static {0} To{1} ({2} value);"" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>{0}</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name=""value"" Type=""{3}"" /> + </Parameters> + <Docs> + <param name=""value"">The OS-specific value to convert.</param> + <summary>Converts an OS-specific value to a + <see cref=""T:{0}"" />.</summary> + " + to_returns + "\n" + + to_exception + +@" <remarks> + " + to_remarks + @" + </remarks> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.From{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryFrom{1}"" /> + <altmember cref=""M:Mono.Unix.Native.NativeConvert.TryTo{1}"" /> + </Docs> + </Member> +", ftype, member, type, mtype + ); + } + + private string GetCSharpType (Type t) + { + string ut = t.Name; + if (t.IsEnum) + ut = Enum.GetUnderlyingType (t).Name; + Type et = t.GetElementType (); + if (et != null && et.IsEnum) + ut = Enum.GetUnderlyingType (et).Name; + + string type = null; + + switch (ut) { + case "Boolean": type = "bool"; break; + case "Byte": type = "byte"; break; + case "SByte": type = "sbyte"; break; + case "Int16": type = "short"; break; + case "UInt16": type = "ushort"; break; + case "Int32": type = "int"; break; + case "UInt32": type = "uint"; break; + case "Int64": type = "long"; break; + case "UInt64": type = "ulong"; break; + } + + return type; + } + + public override void CloseFile (string file_prefix) + { + scs.WriteLine (" <!-- END GENERATED CONTENT -->"); + scs.Close (); + } +} + +// vim: noexpandtab diff --git a/create-native-map/src/test.c.ref b/create-native-map/src/test.c.ref new file mode 100644 index 00000000..85f563df --- /dev/null +++ b/create-native-map/src/test.c.ref @@ -0,0 +1,285 @@ +/* + * This file was automatically generated by create-native-map from TestMap.dll. + * + * DO NOT MODIFY. + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* ndef HAVE_CONFIG_H */ + +#include <stdlib.h> +#include <string.h> + +/* + * Implementation Macros + */ +#ifndef FOO +#define FOO "foo" +#endif /* ndef FOO */ + + +/* + * Implementation Includes + */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* ndef HAVE_UNISTD_H */ +#include <stdio.h> +#include "foo.h" + +#include "test.h" + +#include <errno.h> /* errno, EOVERFLOW */ +#include <glib.h> /* g* types, g_assert_not_reached() */ + +/* returns TRUE if @type is an unsigned type */ +#define _cnm_integral_type_is_unsigned(type) \ + (sizeof(type) == sizeof(gint8) \ + ? (((type)-1) > G_MAXINT8) \ + : sizeof(type) == sizeof(gint16) \ + ? (((type)-1) > G_MAXINT16) \ + : sizeof(type) == sizeof(gint32) \ + ? (((type)-1) > G_MAXINT32) \ + : sizeof(type) == sizeof(gint64) \ + ? (((type)-1) > G_MAXINT64) \ + : (g_assert_not_reached (), 0)) + +/* returns the minimum value of @type as a gint64 */ +#define _cnm_integral_type_min(type) \ + (_cnm_integral_type_is_unsigned (type) \ + ? 0 \ + : sizeof(type) == sizeof(gint8) \ + ? G_MININT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MININT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MININT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MININT64 \ + : (g_assert_not_reached (), 0)) + +/* returns the maximum value of @type as a guint64 */ +#define _cnm_integral_type_max(type) \ + (_cnm_integral_type_is_unsigned (type) \ + ? sizeof(type) == sizeof(gint8) \ + ? G_MAXUINT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MAXUINT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MAXUINT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MAXUINT64 \ + : (g_assert_not_reached (), 0) \ + : sizeof(type) == sizeof(gint8) \ + ? G_MAXINT8 \ + : sizeof(type) == sizeof(gint16) \ + ? G_MAXINT16 \ + : sizeof(type) == sizeof(gint32) \ + ? G_MAXINT32 \ + : sizeof(type) == sizeof(gint64) \ + ? G_MAXINT64 \ + : (g_assert_not_reached (), 0)) + +#ifdef DEBUG +#define _cnm_dump_(to_t,from) \ + printf ("# %s -> %s: min=%llx; max=%llx; value=%llx; lt=%i; l0=%i; gt=%i; e=%i\n", \ + #from, #to_t, \ + (gint64) (_cnm_integral_type_min(to_t)), \ + (gint64) (_cnm_integral_type_max (to_t)), \ + (gint64) (from), \ + (_cnm_integral_type_min (to_t) <= from), \ + (from < 0), \ + /* (_cnm_integral_type_max (to_t) >= from) */ \ + (from <= _cnm_integral_type_max (to_t)), \ + ((_cnm_integral_type_min(to_t) >= from) && \ + ((from < 0) ? 1 : (from <= _cnm_integral_type_max(to_t)))) \ + ) +#else +#define _cnm_dump_(to_t, from) do {} while (0) +#endif + +#define _cnm_return_val_if_overflow(to_t,from,val) G_STMT_START { \ + if (!(_cnm_integral_type_min(to_t) <= from && \ + ((from < 0) || (from <= _cnm_integral_type_max(to_t))))) { \ + _cnm_dump_(to_t, from); \ + errno = EOVERFLOW; \ + return (val); \ + } \ + } G_STMT_END + +int +MakeMap_Test_FromFoo (struct MakeMap_Test_Foo *from, struct foo *to) +{ + _cnm_return_val_if_overflow (int, from->foo, -1); +#ifdef HAVE_STRUCT_FOO_AUTOCONF_ME + _cnm_return_val_if_overflow (gint64, from->autoconf_me, -1); +#endif /* ndef HAVE_STRUCT_FOO_AUTOCONF_ME */ + + memset (to, 0, sizeof(*to)); + + to->foo = from->foo; + to->p = from->p; +#ifdef HAVE_STRUCT_FOO_AUTOCONF_ME + to->autoconf_me = from->autoconf_me; +#endif /* ndef HAVE_STRUCT_FOO_AUTOCONF_ME */ + + return 0; +} + + +int +MakeMap_Test_ToFoo (struct foo *from, struct MakeMap_Test_Foo *to) +{ + _cnm_return_val_if_overflow (int, from->foo, -1); +#ifdef HAVE_STRUCT_FOO_AUTOCONF_ME + _cnm_return_val_if_overflow (gint64, from->autoconf_me, -1); +#endif /* ndef HAVE_STRUCT_FOO_AUTOCONF_ME */ + + memset (to, 0, sizeof(*to)); + + to->foo = from->foo; + to->p = from->p; +#ifdef HAVE_STRUCT_FOO_AUTOCONF_ME + to->autoconf_me = from->autoconf_me; +#endif /* ndef HAVE_STRUCT_FOO_AUTOCONF_ME */ + + return 0; +} + + +int +MakeMap_Test_FromFooHolder (struct MakeMap_Test_FooHolder *from, struct foo_holder *to) +{ + + memset (to, 0, sizeof(*to)); + + if (MakeMap_Test_FromFoo (&from->foo, &to->foo) != 0) { + return -1; + } + if (MakeMap_Test_FromTestEnum (from->mode, &to->mode) != 0) { + return -1; + } + + return 0; +} + + +int +MakeMap_Test_ToFooHolder (struct foo_holder *from, struct MakeMap_Test_FooHolder *to) +{ + + memset (to, 0, sizeof(*to)); + + if (MakeMap_Test_ToFoo (&from->foo, &to->foo) != 0) { + return -1; + } + if (MakeMap_Test_ToTestEnum (from->mode, &to->mode) != 0) { + return -1; + } + + return 0; +} + + +int MakeMap_Test_FromTestEnum (int x, int *r) +{ + *r = 0; + if (x == MakeMap_Test_TestEnum_Bar) +#ifdef Bar + {*r = Bar; return 0;} +#else /* def Bar */ + {errno = EINVAL; return -1;} +#endif /* ndef Bar */ + if (x == MakeMap_Test_TestEnum_Baz) +#ifdef Baz + {*r = Baz; return 0;} +#else /* def Baz */ + {errno = EINVAL; return -1;} +#endif /* ndef Baz */ + if (x == MakeMap_Test_TestEnum_Foo) +#ifdef Foo + {*r = Foo; return 0;} +#else /* def Foo */ + {errno = EINVAL; return -1;} +#endif /* ndef Foo */ + if (x == MakeMap_Test_TestEnum_Qux) +#ifdef Qux + {*r = Qux; return 0;} +#else /* def Qux */ + {errno = EINVAL; return -1;} +#endif /* ndef Qux */ + if (x == 0) + return 0; + errno = EINVAL; return -1; +} + +int MakeMap_Test_ToTestEnum (int x, int *r) +{ + *r = 0; + if (x == 0) + return 0; +#ifdef Bar + if (x == Bar) + {*r = MakeMap_Test_TestEnum_Bar; return 0;} +#endif /* ndef Bar */ +#ifdef Baz + if (x == Baz) + {*r = MakeMap_Test_TestEnum_Baz; return 0;} +#endif /* ndef Baz */ +#ifdef Foo + if (x == Foo) + {*r = MakeMap_Test_TestEnum_Foo; return 0;} +#endif /* ndef Foo */ +#ifdef Qux + if (x == Qux) + {*r = MakeMap_Test_TestEnum_Qux; return 0;} +#endif /* ndef Qux */ + errno = EINVAL; return -1; +} + +int MakeMap_Rename_FromColors (int x, int *r) +{ + *r = 0; + if (x == MakeMap_Rename_Colors_Blue) +#ifdef Blue + {*r = Blue; return 0;} +#else /* def Blue */ + {errno = EINVAL; return -1;} +#endif /* ndef Blue */ + if (x == MakeMap_Rename_Colors_Green) +#ifdef Green + {*r = Green; return 0;} +#else /* def Green */ + {errno = EINVAL; return -1;} +#endif /* ndef Green */ + if (x == MakeMap_Rename_Colors_Red) +#ifdef Red + {*r = Red; return 0;} +#else /* def Red */ + {errno = EINVAL; return -1;} +#endif /* ndef Red */ + if (x == 0) + return 0; + errno = EINVAL; return -1; +} + +int MakeMap_Rename_ToColors (int x, int *r) +{ + *r = 0; + if (x == 0) + return 0; +#ifdef Blue + if (x == Blue) + {*r = MakeMap_Rename_Colors_Blue; return 0;} +#endif /* ndef Blue */ +#ifdef Green + if (x == Green) + {*r = MakeMap_Rename_Colors_Green; return 0;} +#endif /* ndef Green */ +#ifdef Red + if (x == Red) + {*r = MakeMap_Rename_Colors_Red; return 0;} +#endif /* ndef Red */ + errno = EINVAL; return -1; +} + diff --git a/create-native-map/src/test.cs.ref b/create-native-map/src/test.cs.ref new file mode 100644 index 00000000..5e1ae6fe --- /dev/null +++ b/create-native-map/src/test.cs.ref @@ -0,0 +1,123 @@ +/* + * This file was automatically generated by create-native-map from TestMap.dll. + * + * DO NOT MODIFY. + */ + +using System; +using System.Runtime.InteropServices; +using Mono.Unix.Native; + +namespace Mono.Unix.Native { + + public sealed /* static */ partial class NativeConvert + { + private NativeConvert () {} + + private const string LIB = "NativeLib"; + + private static void ThrowArgumentException (object value) + { + throw new ArgumentOutOfRangeException ("value", value, + Locale.GetText ("Current platform doesn't support this value.")); + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_FromFoo")] + private static extern int FromFoo (ref Foo source, IntPtr destination); + + public static bool TryCopy (ref Foo source, IntPtr destination) + { + return FromFoo (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_ToFoo")] + private static extern int ToFoo (IntPtr source, out Foo destination); + + public static bool TryCopy (IntPtr source, out Foo destination) + { + return ToFoo (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_FromFooHolder")] + private static extern int FromFooHolder (ref FooHolder source, IntPtr destination); + + public static bool TryCopy (ref FooHolder source, IntPtr destination) + { + return FromFooHolder (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_ToFooHolder")] + private static extern int ToFooHolder (IntPtr source, out FooHolder destination); + + public static bool TryCopy (IntPtr source, out FooHolder destination) + { + return ToFooHolder (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_FromTestEnum")] + private static extern int FromTestEnum (TestEnum value, out Int32 rval); + + public static bool TryFromTestEnum (TestEnum value, out Int32 rval) + { + return FromTestEnum (value, out rval) == 0; + } + + public static Int32 FromTestEnum (TestEnum value) + { + Int32 rval; + if (FromTestEnum (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="MakeMap_Test_ToTestEnum")] + private static extern int ToTestEnum (Int32 value, out TestEnum rval); + + public static bool TryToTestEnum (Int32 value, out TestEnum rval) + { + return ToTestEnum (value, out rval) == 0; + } + + public static TestEnum ToTestEnum (Int32 value) + { + TestEnum rval; + if (ToTestEnum (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="MakeMap_Rename_FromColors")] + private static extern int FromColors (Colors value, out Int32 rval); + + public static bool TryFromColors (Colors value, out Int32 rval) + { + return FromColors (value, out rval) == 0; + } + + public static Int32 FromColors (Colors value) + { + Int32 rval; + if (FromColors (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="MakeMap_Rename_ToColors")] + private static extern int ToColors (Int32 value, out Colors rval); + + public static bool TryToColors (Int32 value, out Colors rval) + { + return ToColors (value, out rval) == 0; + } + + public static Colors ToColors (Int32 value) + { + Colors rval; + if (ToColors (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + } +} + diff --git a/create-native-map/src/test.h.ref b/create-native-map/src/test.h.ref new file mode 100644 index 00000000..fc34797f --- /dev/null +++ b/create-native-map/src/test.h.ref @@ -0,0 +1,147 @@ +/* + * This file was automatically generated by create-native-map from TestMap.dll. + * + * DO NOT MODIFY. + */ + +#ifndef INC_TestMap_test_H +#define INC_TestMap_test_H + +#include <glib.h> + +G_BEGIN_DECLS + +/* + * Public Macros + */ +#ifndef DefineMe +#define DefineMe 42 +#endif /* ndef DefineMe */ + + +/* + * Public Includes + */ +#include <stdlib.h> + +/* + * Enumerations + */ +enum MakeMap_Test_TestEnum { + MakeMap_Test_TestEnum_Bar = 0x00000001, + #define MakeMap_Test_TestEnum_Bar MakeMap_Test_TestEnum_Bar + MakeMap_Test_TestEnum_Baz = 0x00000002, + #define MakeMap_Test_TestEnum_Baz MakeMap_Test_TestEnum_Baz + MakeMap_Test_TestEnum_Foo = 0x00000000, + #define MakeMap_Test_TestEnum_Foo MakeMap_Test_TestEnum_Foo + MakeMap_Test_TestEnum_Qux = 0x00000003, + #define MakeMap_Test_TestEnum_Qux MakeMap_Test_TestEnum_Qux +}; +int MakeMap_Test_FromTestEnum (int x, int *r); +int MakeMap_Test_ToTestEnum (int x, int *r); + +enum MakeMap_Rename_Colors { + MakeMap_Rename_Colors_Blue = 0x00000001, + #define MakeMap_Rename_Colors_Blue MakeMap_Rename_Colors_Blue + MakeMap_Rename_Colors_Green = 0x00000002, + #define MakeMap_Rename_Colors_Green MakeMap_Rename_Colors_Green + MakeMap_Rename_Colors_Red = 0x00000000, + #define MakeMap_Rename_Colors_Red MakeMap_Rename_Colors_Red +}; +int MakeMap_Rename_FromColors (int x, int *r); +int MakeMap_Rename_ToColors (int x, int *r); + + +/* + * Managed Structure Declarations + */ + +struct MakeMap_Test_Baz; +struct MakeMap_Test_Foo; +struct MakeMap_Test_FooHolder; +struct MakeMap_Test_ForDelegate; +struct MakeMap_Test_Qux; +struct MakeMap_Rename_Stat; + +/* + * Inferred Structure Declarations + */ + +struct foo; +struct foo_holder; + +/* + * Delegate Declarations + */ + +typedef void (*DelArrayBaz) (int i, struct MakeMap_Test_Baz** b); +typedef void (*DelArrayFoo) (int i, struct MakeMap_Test_Foo* f); +typedef void (*DelBaz) (int i, struct MakeMap_Test_Baz* b); +typedef void (*DelFoo) (int i, struct MakeMap_Test_Foo f); +typedef void (*DelRefArrayBaz) (int i, struct MakeMap_Test_Baz*** b); +typedef void (*DelRefArrayFoo) (int i, struct MakeMap_Test_Foo** f); +typedef void (*DelRefBaz) (int i, struct MakeMap_Test_Baz** b); +typedef void (*DelRefFoo) (int i, struct MakeMap_Test_Foo* f); +typedef char* (*MyDelegate) (int b1, unsigned char b2, signed char b3, short s1, unsigned short us1, int i1, unsigned int ui1, gint64 l1, guint64 ul1, void* p1, void* p2, const char* s2, char* sb1, void* h, struct MakeMap_Test_ForDelegate fd); + +/* + * Structures + */ + +struct MakeMap_Test_Baz { + DelFoo b1; + DelRefFoo b2; + DelArrayFoo b3; + DelRefArrayFoo b4; + DelBaz b5; + DelRefBaz b6; + DelArrayBaz b7; + DelRefArrayBaz b8; +}; + +struct MakeMap_Test_Foo { + int foo; + void* p; + gint64 autoconf_me; +}; + +int +MakeMap_Test_FromFoo (struct MakeMap_Test_Foo* from, struct foo *to); +int +MakeMap_Test_ToFoo (struct foo *from, struct MakeMap_Test_Foo* to); + + +struct MakeMap_Test_FooHolder { + struct MakeMap_Test_Foo foo; /* struct foo */ + int mode; +}; + +int +MakeMap_Test_FromFooHolder (struct MakeMap_Test_FooHolder* from, struct foo_holder *to); +int +MakeMap_Test_ToFooHolder (struct foo_holder *from, struct MakeMap_Test_FooHolder* to); + + +struct MakeMap_Test_ForDelegate { + int i; +}; + +struct MakeMap_Test_Qux { + int i; + struct MakeMap_Test_Baz* b; +}; + +struct MakeMap_Rename_Stat { + gint64 st_atime_; /* time_t */ +}; + + +/* + * Functions + */ +void UseQux (DelFoo b, struct MakeMap_Test_Qux** q); + +G_END_DECLS + +#endif /* ndef INC_Mono_Posix_test_H */ + diff --git a/create-native-map/src/test.xml.ref b/create-native-map/src/test.xml.ref new file mode 100644 index 00000000..01330657 --- /dev/null +++ b/create-native-map/src/test.xml.ref @@ -0,0 +1,225 @@ + <!-- BEGIN GENERATED CONTENT +/* + * This file was automatically generated by create-native-map from TestMap.dll. + * + * DO NOT MODIFY. + */ + + --> + + <Member MemberName="TryFromTestEnum"> + <MemberSignature Language="C#" Value="public static bool TryFromTestEnum (MakeMap.Test.TestEnum value, out int rval);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="MakeMap.Test.TestEnum" /> + <Parameter Name="rval" Type="System.Int32&" RefType="out" /> + </Parameters> + <Docs> + <param name="value">The managed value to convert.</param> + <param name="rval">The OS-specific equivalent value.</param> + <summary>Converts a <see cref="T:MakeMap.Test.TestEnum" /> + enumeration value to an OS-specific value.</summary> + <returns><see langword="true" /> if the conversion was successful; + otherwise, <see langword="false" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref="M:Mono.Unix.Native.NativeConvert.FromTestEnum" />.</para> + <para>If successful, this method stores the OS-specific equivalent + value of <paramref name="value" /> into <paramref name="rval" />. + Otherwise, <paramref name="rval" /> will contain <c>0</c>.</para> + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToTestEnum" /> + </Docs> + </Member> + <Member MemberName="FromTestEnum"> + <MemberSignature Language="C#" Value="public static int FromTestEnum (MakeMap.Test.TestEnum value);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Int32</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="MakeMap.Test.TestEnum" /> + </Parameters> + <Docs> + <param name="value">The managed value to convert.</param> + <summary>Converts a <see cref="T:MakeMap.Test.TestEnum" /> + to an OS-specific value.</summary> + <returns>The equivalent OS-specific value.</returns> + <exception cref="T:System.ArgumentOutOfRangeException"> + <paramref name="value" /> has no equivalent OS-specific value. + </exception> + <remarks></remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToTestEnum" /> + </Docs> + </Member> + <Member MemberName="TryToTestEnum"> + <MemberSignature Language="C#" Value="public static bool TryToTestEnum (int value, out MakeMap.Test.TestEnum rval);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="System.Int32" /> + <Parameter Name="rval" Type="MakeMap.Test.TestEnum&" RefType="out" /> + </Parameters> + <Docs> + <param name="value">The OS-specific value to convert.</param> + <param name="rval">The managed equivalent value</param> + <summary>Converts an OS-specific value to a + <see cref="T:MakeMap.Test.TestEnum" />.</summary> + <returns><see langword="true" /> if the conversion was successful; + otherwise, <see langword="false" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref="M:Mono.Unix.Native.NativeConvert.ToTestEnum" />.</para> + <para>If successful, this method stores the managed equivalent + value of <paramref name="value" /> into <paramref name="rval" />. + Otherwise, <paramref name="rval" /> will contain a <c>0</c> + cast to a <see cref="T:MakeMap.Test.TestEnum" />.</para> + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromTestEnum" /> + </Docs> + </Member> + <Member MemberName="ToTestEnum"> + <MemberSignature Language="C#" Value="public static MakeMap.Test.TestEnum ToTestEnum (int value);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>MakeMap.Test.TestEnum</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="System.Int32" /> + </Parameters> + <Docs> + <param name="value">The OS-specific value to convert.</param> + <summary>Converts an OS-specific value to a + <see cref="T:MakeMap.Test.TestEnum" />.</summary> + <returns>The equivalent managed value.</returns> + + <exception cref="T:System.ArgumentOutOfRangeException"> + <paramref name="value" /> has no equivalent managed value. + </exception> + <remarks> + + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromTestEnum" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToTestEnum" /> + </Docs> + </Member> + + + <Member MemberName="TryFromColors"> + <MemberSignature Language="C#" Value="public static bool TryFromColors (MakeMap.ToBeRenamed.Colors value, out int rval);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="MakeMap.ToBeRenamed.Colors" /> + <Parameter Name="rval" Type="System.Int32&" RefType="out" /> + </Parameters> + <Docs> + <param name="value">The managed value to convert.</param> + <param name="rval">The OS-specific equivalent value.</param> + <summary>Converts a <see cref="T:MakeMap.ToBeRenamed.Colors" /> + enumeration value to an OS-specific value.</summary> + <returns><see langword="true" /> if the conversion was successful; + otherwise, <see langword="false" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref="M:Mono.Unix.Native.NativeConvert.FromColors" />.</para> + <para>If successful, this method stores the OS-specific equivalent + value of <paramref name="value" /> into <paramref name="rval" />. + Otherwise, <paramref name="rval" /> will contain <c>0</c>.</para> + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToColors" /> + </Docs> + </Member> + <Member MemberName="FromColors"> + <MemberSignature Language="C#" Value="public static int FromColors (MakeMap.ToBeRenamed.Colors value);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Int32</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="MakeMap.ToBeRenamed.Colors" /> + </Parameters> + <Docs> + <param name="value">The managed value to convert.</param> + <summary>Converts a <see cref="T:MakeMap.ToBeRenamed.Colors" /> + to an OS-specific value.</summary> + <returns>The equivalent OS-specific value.</returns> + <exception cref="T:System.ArgumentOutOfRangeException"> + <paramref name="value" /> has no equivalent OS-specific value. + </exception> + <remarks></remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToColors" /> + </Docs> + </Member> + <Member MemberName="TryToColors"> + <MemberSignature Language="C#" Value="public static bool TryToColors (int value, out MakeMap.ToBeRenamed.Colors rval);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>System.Boolean</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="System.Int32" /> + <Parameter Name="rval" Type="MakeMap.ToBeRenamed.Colors&" RefType="out" /> + </Parameters> + <Docs> + <param name="value">The OS-specific value to convert.</param> + <param name="rval">The managed equivalent value</param> + <summary>Converts an OS-specific value to a + <see cref="T:MakeMap.ToBeRenamed.Colors" />.</summary> + <returns><see langword="true" /> if the conversion was successful; + otherwise, <see langword="false" />.</returns> + <remarks><para>This is an exception-safe alternative to + <see cref="M:Mono.Unix.Native.NativeConvert.ToColors" />.</para> + <para>If successful, this method stores the managed equivalent + value of <paramref name="value" /> into <paramref name="rval" />. + Otherwise, <paramref name="rval" /> will contain a <c>0</c> + cast to a <see cref="T:MakeMap.ToBeRenamed.Colors" />.</para> + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.ToColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromColors" /> + </Docs> + </Member> + <Member MemberName="ToColors"> + <MemberSignature Language="C#" Value="public static MakeMap.ToBeRenamed.Colors ToColors (int value);" /> + <MemberType>Method</MemberType> + <ReturnValue> + <ReturnType>MakeMap.ToBeRenamed.Colors</ReturnType> + </ReturnValue> + <Parameters> + <Parameter Name="value" Type="System.Int32" /> + </Parameters> + <Docs> + <param name="value">The OS-specific value to convert.</param> + <summary>Converts an OS-specific value to a + <see cref="T:MakeMap.ToBeRenamed.Colors" />.</summary> + <returns>The equivalent managed value.</returns> + + <exception cref="T:System.ArgumentOutOfRangeException"> + <paramref name="value" /> has no equivalent managed value. + </exception> + <remarks> + + </remarks> + <altmember cref="M:Mono.Unix.Native.NativeConvert.FromColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryFromColors" /> + <altmember cref="M:Mono.Unix.Native.NativeConvert.TryToColors" /> + </Docs> + </Member> + + <!-- END GENERATED CONTENT --> |