View Javadoc

1   /*
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	
4   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
5   	
6   	JNAerator is free software: you can redistribute it and/or modify
7   	it under the terms of the GNU Lesser General Public License as published by
8   	the Free Software Foundation, either version 3 of the License, or
9   	(at your option) any later version.
10  	
11  	JNAerator is distributed in the hope that it will be useful,
12  	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  	GNU Lesser General Public License for more details.
15  	
16  	You should have received a copy of the GNU Lesser General Public License
17  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19  package com.ochafik.lang.jnaerator;
20  
21  import java.io.File;
22  
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.PrintWriter;
26  import java.net.URL;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Locale;
35  import java.util.Map;
36  import java.util.Set;
37  import java.util.logging.Level;
38  import java.util.regex.Matcher;
39  import java.util.regex.Pattern;
40  
41  import javax.tools.Diagnostic;
42  import javax.tools.DiagnosticCollector;
43  import javax.tools.JavaCompiler;
44  import javax.tools.JavaFileObject;
45  import javax.tools.Diagnostic.Kind;
46  
47  import org.anarres.cpp.LexerException;
48  import org.antlr.runtime.RecognitionException;
49  //import org.junit.runner.JUnitCore;
50  import org.rococoa.cocoa.foundation.NSClass;
51  
52  import com.ochafik.io.FileListUtils;
53  import com.ochafik.io.ReadText;
54  import com.ochafik.lang.compiler.CompilerUtils;
55  import com.ochafik.lang.compiler.MemoryFileManager;
56  import com.ochafik.lang.compiler.MemoryJavaFile;
57  import com.ochafik.lang.compiler.URLFileObject;
58  import com.ochafik.lang.jnaerator.JNAeratorCommandLineArgs.OptionDef;
59  import com.ochafik.lang.jnaerator.nativesupport.DllExport;
60  import com.ochafik.lang.jnaerator.parser.Arg;
61  import com.ochafik.lang.jnaerator.parser.Declaration;
62  import com.ochafik.lang.jnaerator.parser.Declarator;
63  import com.ochafik.lang.jnaerator.parser.Define;
64  import com.ochafik.lang.jnaerator.parser.Element;
65  import com.ochafik.lang.jnaerator.parser.Expression;
66  import com.ochafik.lang.jnaerator.parser.Function;
67  import com.ochafik.lang.jnaerator.parser.Identifier;
68  import com.ochafik.lang.jnaerator.parser.ModifiableElement;
69  import com.ochafik.lang.jnaerator.parser.Modifier;
70  import com.ochafik.lang.jnaerator.parser.ObjCppParser;
71  import com.ochafik.lang.jnaerator.parser.Scanner;
72  import com.ochafik.lang.jnaerator.parser.SourceFile;
73  import com.ochafik.lang.jnaerator.parser.Struct;
74  import com.ochafik.lang.jnaerator.parser.TypeRef;
75  import com.ochafik.lang.jnaerator.parser.VariablesDeclaration;
76  import com.ochafik.lang.jnaerator.parser.Expression.MemberRefStyle;
77  import com.ochafik.lang.jnaerator.parser.Identifier.QualificationSeparator;
78  import com.ochafik.lang.jnaerator.parser.Identifier.QualifiedIdentifier;
79  import com.ochafik.lang.jnaerator.parser.Identifier.SimpleIdentifier;
80  import com.ochafik.lang.jnaerator.parser.ModifierKind;
81  import com.ochafik.lang.jnaerator.parser.ObjCppLexer;
82  import com.ochafik.lang.jnaerator.parser.Struct.Type;
83  import com.ochafik.lang.jnaerator.runtime.LibraryExtractor;
84  import com.ochafik.lang.jnaerator.runtime.MangledFunctionMapper;
85  import com.ochafik.lang.jnaerator.runtime.Mangling;
86  import com.ochafik.lang.jnaerator.studio.JNAeratorStudio;
87  import com.ochafik.lang.jnaerator.studio.JNAeratorStudio.SyntaxException;
88  import com.ochafik.util.listenable.Adapter;
89  import com.ochafik.util.listenable.Pair;
90  import com.ochafik.util.string.RegexUtils;
91  import com.ochafik.util.string.StringUtils;
92  import com.sun.jna.Library;
93  import com.sun.jna.Native;
94  import com.sun.jna.NativeLibrary;
95  import com.sun.jna.Pointer;
96  import com.sun.jna.PointerType;
97  import java.io.BufferedReader;
98  import java.io.BufferedWriter;
99  import java.io.FileOutputStream;
100 import java.io.FileReader;
101 import java.io.StringReader;
102 import org.antlr.runtime.ANTLRReaderStream;
103 import org.antlr.runtime.CommonTokenStream;
104 import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*;
105 import static com.ochafik.lang.jnaerator.nativesupport.NativeExportUtils.*;
106 /*
107 //include com/ochafik/lang/jnaerator/parser/*.mm
108 //include com/ochafik/lang/jnaerator/parser/ObjCpp.g
109  */
110 
111 
112 /**
113  * java -Xmx2000m -jar ../bin/jnaerator.jar `for F in /System/Library/Frameworks/*.framework ; do echo $F| sed -E 's/^.*\/([^/]+)\.framework$/-framework \1/' ; done` -out apple-frameworks.jar
114  */
115 
116 public class JNAerator {
117 
118 	public static interface Feedback {
119 		void setStatus(final String string);
120 		void setFinished(File toOpen);
121 		void setFinished(Throwable e);
122 		void sourcesParsed(SourceFiles sourceFiles);
123 		void wrappersGenerated(Result result);
124 	}
125 	private static Pattern argTokenPattern = Pattern.compile("(?m)\"[^\"]*\"|[^\\s]+");
126 	private static Pattern argVariablePattern = Pattern.compile("\\$\\(([^)]+)\\)");
127 	final JNAeratorConfig config;
128 	
129 	public JNAerator(JNAeratorConfig config) {
130 		this.config = config;
131 	}
132 
133 	static final Pattern definePattern = Pattern.compile("#\\s*define\\s+(\\w+)\\s+(.*)");
134 	static final boolean fullFilePathInComments = true;
135 	
136 	private static final String DEFAULT_CONFIG_FILE = "config.jnaerator";
137 	protected static final Pattern fileRadixPattern = Pattern.compile("(?:[/\\\\]|^)(.*?)(?:Full\\.bridgesupport|\\.[^.]+)$");
138 	private static final Pattern classAndMethodNamePattern = Pattern.compile("(.+?)::([^:]+)");
139 
140 	//"@C:\Prog\jnaerator\sources\com\ochafik\lang\jnaerator\nativesupport\dllexport.jnaerator"
141 	//"C:\Prog\CPP\CppLibTest\jnaerator\CppLibTest.jnaerator"
142 	
143 	public static String[] getJNAeratorArgsFromPref() {
144 		String argsPref = System.getProperty("jnaerator.args");
145 		if (argsPref == null)
146 			return null;
147 		return argsPref.split(",");
148 	}
149 	public static void main(String[] argsArray) {
150 		String[] jnAeratorArgsFromPref = getJNAeratorArgsFromPref();
151 		if (jnAeratorArgsFromPref != null) {
152 			ArrayList<String> list = new ArrayList<String>();
153 			list.addAll(Arrays.asList(jnAeratorArgsFromPref));
154 			list.addAll(Arrays.asList(argsArray));
155 			argsArray = list.toArray(new String[list.size()]);
156 		}
157 		if (argsArray.length == 0) {
158 			if (new File("/Users/ochafik").exists()) {
159 				argsArray = new String[] {
160 //						"-wikiHelp",
161 						//"/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.0.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSURL.h",
162 						//"/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator2.0.sdk/System/Library/Frameworks/Foundation.framework/Versions/C/Headers",
163 //						"@/Users/ochafik/src/opencv-1.1.0/config.jnaerator",
164 //						"-library", "gc", 
165 //						"/Users/ochafik/src/gc6.8/include/",
166 //						"-I/Developer/SDKs/MacOSX10.5.sdk/usr/include",
167 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/sys/event.h",
168 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/machine/types.h",
169 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/sys/cdefs.h",
170 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/sys/_types.h",
171 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/stdint.h",
172 						
173 //						"-autoConf",
174 						//"-library", "c",
175 //						"-root", "org.rococoa",
176 						
177 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/sys/types.h", 
178 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/architecture/i386/math.h",
179 //						"/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h",
180 //						"/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks/CoreGraphics.framework/Headers/CGBase.h",
181 //						"/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/Frameworks/CoreGraphics.framework/Headers/CGShading.h",
182 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/AvailabilityMacros.h",
183 //						"/Users/ochafik/Prog/Java/testxp/test.h",
184 //						"/Users/ochafik/Prog/Java/test/Test2.h",
185 //						"-library", "objc",
186 //						"/Developer/SDKs/MacOSX10.4u.sdk/usr/include/objc/objc.h",
187 //						"-framework", "Foundation",
188 //						"-framework", "AppKit",
189 //						"-framework", "CoreFoundation",
190 //						"-framework", "IOKit",
191 //						"/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h",
192 //						"/System/Library/Frameworks/Foundation.framework/Headers/NSString.h",
193 //						"/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h",
194 //						"-framework", "CoreGraphics", 
195 //						"-framework", "CarbonCore", 
196 						//"-f", "QTKit", 
197 //						"-o", "/Users/ochafik/Prog/Java/test/objc",
198 //						"-o", "/Users/ochafik/Prog/Java/testxp",
199 //						"/Users/ochafik/Prog/Java/test/Test.h",
200 //						"/Users/ochafik/Prog/Java/test/JNATest.h",
201 						//"-o", "/Users/ochafik/Prog/Java",
202 //						"@/Users/ochafik/src/opencv-1.1.0/config.jnaerator",
203 //						"-library", "CocoaTest", "-o", "/Users/ochafik/Prog/Java/test/cppxcode",
204 //						"/Users/ochafik/Prog/Java/versionedSources/jnaerator/trunk/examples/XCode/CocoaTest/TestClass.h",
205 						
206 //						"/Users/ochafik/src/qhull-2003.1/qhull.jnaerator",
207 //						"@",
208 //						"/Users/ochafik/Prog/Java/versionedSources/jnaerator/trunk/examples/Rococoa/cocoa.jnaerator",
209 //						"-limitComments",
210 //						"@/Users/ochafik/src/opencv-1.1.0/config.jnaerator",
211 //						"-o", "/Users/ochafik/src/opencv-1.1.0",
212 //						"/Users/ochafik/Prog/Java/test/cocoa/cocoa.h",
213 //						"/tmp/BridgeSupportTiger/Release/Library/BridgeSupport/CoreGraphics.bridgesupport"
214 //						"/tmp/BridgeSupportTiger/Release/Library/BridgeSupport/CoreFoundation.bridgesupport"
215 //						"-framework", "CoreGraphics",
216 //						"-o", "/Users/ochafik/Prog/Java/test/foundation2",
217 //						"-noRuntime",
218 //						"/Users/ochafik/Prog/Java/versionedSources/jnaerator/trunk/tests/callbacks/test.h",
219 						//"-noComp",
220 						//"-framework", "Foundation",
221 						//"-o", "/Users/ochafik/jnaerator/jnaerator/cocoa",
222 						"-library", "Test",
223 						"/Users/ochafik/Prog/Java/versionedSources/jnaerator/trunk/test/classes.h",
224 						"-o", "/Users/ochafik/Prog/Java/versionedSources/jnaerator/trunk/test",
225 						"-noComp", "-noJar",
226 //						"-no"
227 						//"-studio",
228 //						"/Users/ochafik/src/opencv-1.1.0/config.jnaerator",
229 //						"-root", "outpackage",
230 //						"-root", "org.rococoa.cocoa",
231 //						"/System/Library/Frameworks/Foundation.framework/Resources/BridgeSupport/FoundationFull.bridgesupport",
232 //						"-o", "/Users/ochafik/Prog/Java/test/opencv",
233 //						"-scalaOut", "/Users/ochafik/Prog/Java/test/opencv/scala",
234 //						"-noComp",	
235 //						"-gui",
236 //						"-jar", "/Users/ochafik/Prog/Java/test/foundation2/test.jar",
237 //						"@/Users/ochafik/Prog/Java/versionedSources/nativelibs4java/trunk/libraries/MacOSXFrameworks/config.jnaerator"
238 //						"-library", "opencl",
239 //						"/Users/ochafik/src/opencl/cl.h",
240 //						"-o", "/Users/ochafik/src/opencl",
241 						"-v"
242 				};
243 			} else if (new File(DEFAULT_CONFIG_FILE).exists()){
244 				argsArray = new String[] { "@", DEFAULT_CONFIG_FILE };
245 			} else {
246 				JNAeratorCommandLineArgs.displayHelp(false);
247 				return;
248 			}
249 		}
250 		
251 		try {
252 			List<String> args = new ArrayList<String>(Arrays.asList(argsArray));
253 			
254 			final JNAeratorConfig config = new JNAeratorConfig();
255 			config.preprocessorConfig.frameworksPath.addAll(JNAeratorConfigUtils.DEFAULT_FRAMEWORKS_PATH);
256 			new JNAeratorCommandLineArgs.ArgsParser() {
257 
258 				Feedback feedback = null;
259 				
260 				List<String> frameworks = new ArrayList<String>();
261 				boolean simpleGUI = false;
262 				String arch = LibraryExtractor.getCurrentOSAndArchString();
263 				String currentLibrary = null;
264 				
265 				@Override
266 				List<String> parsed(ParsedArg a) throws Exception {
267 					switch (a.def) {					
268 					
269 					case AddIncludePath:
270 						config.preprocessorConfig.includes.add(a.getFileParam(0).toString());
271 						break;
272 					case AddFrameworksPath:
273 						config.preprocessorConfig.frameworksPath.add(a.getFileParam(0).toString());
274 						break;
275 					case NoPreprocessing:
276 						config.preprocessorConfig.preprocess = false;
277 						break;
278 					case MaxConstructedFields:
279 						config.maxConstructedFields = a.getIntParam(0);
280 						break;
281 					case NoPrimitiveArrays:
282 						config.noPrimitiveArrays = true;
283 						break;
284 					case IfRegexMatch:
285 						String javaProperty = a.getStringParam(0),
286 								regex = a.getStringParam(1),
287 								thenCmd = a.getStringParam(2),
288 								elseCmd = a.getStringParam(3);
289 						String propValue = System.getProperty(javaProperty);
290 						if (propValue == null)
291 							propValue = "";
292 						return Arrays.asList(propValue.matches(regex) ? thenCmd : elseCmd);
293 					case NoCompile:
294 						config.compile = false;
295 						break;
296 					case NoStringReturns:
297 						config.stringifyConstCStringReturnValues = false;
298 						break;
299 					case CPlusPlusGen:
300 						config.genCPlusPlus = true;
301 						break;
302 					case CurrentLibrary:
303 						currentLibrary = a.getStringParam(0);
304 						break;
305 					case CurrentPackage:
306 						config.packageName = a.getStringParam(0);
307 						break;
308 					case NoLibBundle:
309 						config.bundleLibraries = false;
310 						break;
311 					case DefaultLibrary:
312 						config.defaultLibrary = a.getStringParam(0);
313 						break;
314 					case RecursedExtensions:
315 						config.fileFilter = "*".equals(a.getStringParam(0)) ? null : new JNAeratorConfigUtils.FileExtensionFilter(a.getStringParam(0).split("[:;"));
316 						break;
317 					case DefineMacro:
318 						config.preprocessorConfig.macros.put(a.getStringParam(0), a.getStringParam(1));
319 						break;
320 					case Direct:
321 						config.useJNADirectCalls = true;
322 						break;
323 					case EntryName:
324 						config.entryName = a.getStringParam(0);
325 						break;
326 					case ExtractSymbols:
327 						config.extractLibSymbols = true;
328 						break;
329 					case File:
330 						return parsedFile(a);
331 					case FrameworksPath:
332 						config.preprocessorConfig.frameworksPath.clear();
333 						config.preprocessorConfig.frameworksPath.addAll(Arrays.asList(a.getStringParam(0).split(":")));
334 						break;
335 					case GUI:
336 						simpleGUI = true;
337 						break;
338 					case Help:
339 					case WikiDoc:
340 						JNAeratorCommandLineArgs.displayHelp(a.def == OptionDef.WikiDoc);
341 						System.exit(0);
342 						break;
343 					case WCharAsShort:
344 						config.wcharAsShort = true;
345 						break;
346 					case JarOut:
347 						config.outputJar = a.getFileParam(0);
348 						break;
349 					case NoMangling:
350 						config.noMangling = true;
351 						break;
352 					case NoComments:
353 						config.noComments = true;
354 						break;
355 					case LimitComments:
356 						config.limitComments = true;
357 						break;
358 					case MacrosOut:
359 						config.macrosOutFile = a.getFileParam(0);
360 						break;
361 					case GCCLong:
362 						config.gccLong = true;
363 						break;
364 					case SizeAsLong:
365 						config.sizeAsLong = true;
366 						break;
367 					case NoAuto:
368 						config.autoConf = false;
369 						break;
370 					case NoCPP:
371 						config.noCPlusPlus = true;
372 						break;
373 					case ScalaOut:
374 						config.scalaOut = a.getFileParam(0);
375 						break;
376 					case NoRuntime:
377 						config.bundleRuntime = false;
378 						break;
379 					case OutputDir:
380 						config.outputDir = a.getFileParam(0);
381 						break;
382 					case PreferJavac:
383 						config.preferJavac = true;
384 						break;
385 					case BridgeSupportOutFile:
386 						config.bridgesupportOutFile = a.getFileParam(0);
387 						break;
388 					case ChoicesOut:
389 						config.choicesOutFile = a.getFileParam(0);
390 						break;
391 					case ChoicesIn:
392 						config.choicesInputFile = a.getFileParam(0);
393 						break;
394 					case PreprocessingOut:
395 						config.preprocessingOutFile = a.getFileParam(0);
396 						break;
397 					case ExtractionOut:
398 						config.extractedSymbolsOut = a.getFileParam(0);
399 						break;
400 						
401 					case Project:
402 						JNAeratorConfigUtils.readProjectConfig(a.getFileParam(0), a.getStringParam(1), config);
403 						break;
404 					case RootPackage:
405 						config.rootPackageName = a.getStringParam(0);
406 						break;
407 					case StructsInLibrary:
408 						config.putTopStructsInSeparateFiles = false;
409 						break;
410 					case Studio:
411 						try {
412 							JNAeratorStudio.main(new String[0]);
413 							return null;
414 						} catch (Exception ex) {
415 							ex.printStackTrace();
416 							System.exit(1);
417 						}
418 						break;
419 //					case Test:
420 //						try {
421 //							JUnitCore.main(JNAeratorTests.class.getName());
422 //							System.exit(0);
423 //						} catch (Exception ex) {
424 //							ex.printStackTrace();
425 //							System.exit(1);
426 //						}
427 //						break;
428 					case Verbose:
429 						config.verbose = true;
430 						break;
431 					case Framework:
432 						frameworks.add(a.getStringParam(0));
433 						break;
434 					case IncludeArgs:
435 						return parsedArgsInclude(a);
436 					case Arch:
437 						arch = a.getStringParam(0);
438 						break;
439 					
440 					}
441 					return Collections.emptyList();
442 				}
443 
444 				private List<String> parsedFile(ParsedArg a) throws Exception {
445 					File file = a.getFileParam(0);
446 					if (file != null) {
447 						String fn = file.getName();
448 						if (file.isDirectory() && fn.matches(".*\\.framework"))
449 							frameworks.add(file.toString());
450 						else if (file.isFile() && fn.matches(".*\\.jnaerator"))
451 							return parsedArgsInclude(a);
452 						else if (fn.matches(".*\\.bridgesupport"))
453 							config.bridgeSupportFiles.add(file);
454 						else if (file.isFile() && isLibraryFile(file)) {
455 							if (config.verbose)
456 								System.out.println("Adding file '" + file + "' for arch '" + arch +"'.");
457 							config.addLibraryFile(file, arch);
458 						} else {
459 							String lib = currentLibrary;
460 							if (file.isDirectory() && fn.endsWith(".xcode") ||
461 								file.isFile() && fn.toLowerCase().endsWith(".sln")) 
462 							{
463 								JNAeratorConfigUtils.readProjectConfig(file, null, config);
464 							} else {
465 								if (lib == null) {
466 									String name = fn;
467 									int i = name.indexOf('.');
468 									if (i >= 0)
469 										name = name.substring(0, i).trim();
470 									if (name.length() > 0)
471 										lib = name;
472 									System.out.println("Warning: no -library option for file '" + fn + "', using \"" + lib + "\".");
473 								}
474 								config.addSourceFile(file, lib, !file.isFile());//config.defaultLibrary);
475 							}
476 						}
477 					}
478 					return Collections.emptyList();
479 				}
480 
481 				private List<String> parsedArgsInclude(ParsedArg a) throws IOException {
482 					final File argsFile = a.getFileParam(0);
483 					
484 					String argsFileContent = ReadText.readText(argsFile);
485 					Adapter<String[], String> argVariableReplacer = new Adapter<String[], String>() {
486 						@Override
487 						public String adapt(String[] value) {
488 							String n = value[1];
489 							String v = System.getProperty(n);
490 							if (v == null)
491 								v = System.getenv(n);
492 							if (v == null && n.equals("DIR"))
493 								v = argsFile.getAbsoluteFile().getParent();
494 							return v;
495 						}
496 					};
497 					
498 					// Strip comments out
499 					argsFileContent = argsFileContent.replaceAll("(?m)//[^\n]*(\n|$)", "\n");
500 					argsFileContent = argsFileContent.replaceAll("(?m)/\\*([^*]|\\*[^/])*\\*/", "");
501 					
502 					// Replace variables
503 					argsFileContent = RegexUtils.regexReplace(argVariablePattern, argsFileContent, argVariableReplacer);
504 					
505 					List<String> ret = new ArrayList<String>();
506 					List<String[]> tokens = RegexUtils.find(argsFileContent, argTokenPattern);
507 					for (String[] tokenMatch : tokens) {
508 						String token = tokenMatch[0];
509 						token = token.trim();
510 						if (token.startsWith("\"") && token.endsWith("\""))
511 							token = token.substring(1, token.length() - 1);
512 						
513 						if (token.length() == 0 || token.matches("^(//|#).*"))
514 							continue;
515 						
516 						boolean allowMissing = token.endsWith("?");
517 						if (token.contains("*")) {
518 							Collection<String> rs = FileListUtils.resolveShellLikeFileList(allowMissing ? token.substring(0, token.length() - 1) : token);
519 							for (String r : rs)
520 								ret.add(allowMissing ? r + "?" : r);
521 							if (!rs.isEmpty())
522 								continue;
523 						}
524 						ret.add(token);
525 					}
526 					return ret;
527 				}
528 
529 				@Override
530 				void finished() throws IOException {
531 					for (String framework : frameworks)
532 						JNAeratorConfigUtils.addFramework(config, framework);
533 					
534 					config.addRootDir(new File("."));
535 					for (String i : config.preprocessorConfig.includes) {
536 						try {
537 							config.addRootDir(new File(i));
538 						} catch (Exception ex) {}
539 					}	
540 					
541 					if (config.sourceFiles.isEmpty() && config.bridgeSupportFiles.isEmpty() && !config.libraryFiles.isEmpty())
542 						config.extractLibSymbols = true;
543 					
544 					Collection<File> inputFiles = config.getInputFiles();
545 					File firstFile = inputFiles.isEmpty() ? null : inputFiles.iterator().next().getAbsoluteFile();
546 					String firstFileName = firstFile == null ? null : firstFile.getName();
547 					String entry = config.entryName == null ? RegexUtils.findFirst(firstFileName, fileRadixPattern, 1) : config.entryName; 
548 					if (entry != null)
549 						entry = TypeConversion.getValidJavaIdentifier(ident(entry)).toString();
550 
551 					if (config.outputDir == null)
552 						config.outputDir = firstFile == null ? new File(".") : firstFile.getAbsoluteFile().getParentFile();
553 					
554 					if (config.outputJar == null && config.compile)
555 						config.outputJar = new File(config.outputDir, (entry == null ? "out" : entry) + ".jar");
556 					
557 					if (config.verbose) {
558 						if (config.macrosOutFile == null)
559 							config.macrosOutFile = new File("_jnaerator.macros.cpp");
560 						if (config.choicesOutFile == null)
561 							config.choicesOutFile = new File("_jnaerator.choices");
562 						if (config.preprocessingOutFile == null)
563 							config.preprocessingOutFile = new File("_jnaerator.preprocessed.c");
564 						if (config.extractedSymbolsOut == null)
565 							config.extractedSymbolsOut = new File("_jnaerator.extractedSymbols.h");
566 						if (config.bridgesupportOutFile == null)
567 							config.bridgesupportOutFile = new File("_jnaerator.bridgesupport.h");
568 					}
569 					
570 					config.cacheDir = getDir("cache");
571 					
572 					if (simpleGUI) {
573 						SimpleGUI gui = new SimpleGUI(config);
574 						feedback = gui;
575 						gui.show();
576 					} else {
577 						feedback = new Feedback() {
578 							
579 							@Override
580 							public void setStatus(String string) {
581 								if (config.verbose)
582 									System.out.println(string);
583 							}
584 							
585 							@Override
586 							public void setFinished(Throwable e) {
587 								System.out.println("JNAeration failed !");
588 								e.printStackTrace();
589 								System.exit(1);
590 							}
591 							
592 							@Override
593 							public void setFinished(File toOpen) {
594 								System.out.println("JNAeration completed !");
595 								System.out.println(toOpen.getAbsolutePath());
596 								System.exit(0);
597 							}
598 
599 							@Override
600 							public void sourcesParsed(SourceFiles sourceFiles) {
601 								
602 							}
603 
604 							@Override
605 							public void wrappersGenerated(
606 									com.ochafik.lang.jnaerator.Result result) {
607 								// TODO Auto-generated method stub
608 								
609 							}
610 						}; 
611 					}
612 					
613 					new JNAerator(config).jnaerate(feedback);
614 					if (!simpleGUI)
615 						System.exit(0);
616 				}
617 				
618 			}.parse(args);
619 			
620 		} catch (Exception e) {
621 			e.printStackTrace();
622 			System.exit(1);
623 		}
624 	}
625 	public PrintWriter getClassSourceWriter(ClassOutputter outputter, String className) throws IOException {
626 		return outputter.getClassSourceWriter(className);
627 	}
628 	private static boolean isLibraryFile(File file) {
629 		String arg = file.getName().toLowerCase();
630 		return 
631 			arg.endsWith(".dll") || 
632 			arg.endsWith(".pdb") || 
633 			arg.endsWith(".dylib") || 
634 			arg.endsWith(".so") || 
635 			arg.endsWith(".jnilib");
636 	}
637 	public void jnaerate(final Feedback feedback) {
638 		try {
639 			if (config.autoConf) {
640 				feedback.setStatus("Auto-configuring parser...");
641 				JNAeratorConfigUtils.autoConfigure(config);
642 			}
643 			
644 			if (config.verbose)
645 				JNAeratorConfigUtils.logger.log(Level.INFO, "Include path : \n\t" + StringUtils.implode(config.preprocessorConfig.includes, "\n\t"));
646 			
647 			DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
648 			JavaCompiler c = CompilerUtils.getJavaCompiler(config.preferJavac);
649 			final MemoryFileManager mfm = new MemoryFileManager(c.getStandardFileManager(diagnostics, null, null));
650 			
651 			final ClassOutputter[] classOutputter = new ClassOutputter[1];
652 			if (config.compile) {
653 				classOutputter[0] = new ClassOutputter() {
654 					@Override
655 					public PrintWriter getClassSourceWriter(String className) throws FileNotFoundException {
656 						String path = "file:///" + className.replace('.', '/') + ".java";
657 						MemoryJavaFile c = new MemoryJavaFile(path, (String)null, JavaFileObject.Kind.SOURCE);
658 						mfm.inputs.put(c.getPath().toString(), c);
659 						return new PrintWriter(c.openWriter());
660 					}
661 				};
662 			} else {
663 				classOutputter[0] = new ClassOutputter() {
664 					public PrintWriter getClassSourceWriter(String className) throws FileNotFoundException {
665 						File file = new File(JNAerator.this.config.outputDir, className.replace('.', File.separatorChar) + ".java");
666 						File parent = file.getParentFile();
667 						if (!parent.exists())
668 							parent.mkdirs();
669 	
670 						feedback.setStatus("Generating " + file.getName());
671 	
672 						return new PrintWriter(file) {
673 							@Override
674 							public void print(String s) {
675 								super.print(s.replace("\r", "").replace("\n", StringUtils.LINE_SEPARATOR));
676 							}
677 						};
678 					}
679 				};
680 			}
681 			
682 			Result result = createResult(new ClassOutputter() {
683 				
684 				@Override
685 				public PrintWriter getClassSourceWriter(String className) throws IOException {
686 					return JNAerator.this.getClassSourceWriter(classOutputter[0], className);
687 				}
688 			}, feedback);
689 			
690 			SourceFiles sourceFiles = parseSources(feedback, result.typeConverter);
691 			if (config.extractLibSymbols)
692 				parseLibSymbols(sourceFiles, result);
693 			
694 			feedback.sourcesParsed(sourceFiles);
695 			
696 			ScalaGenerator sgen = null;
697 			if (config.scalaOut != null)
698 				sgen = new ScalaGenerator(result);
699 			
700 			jnaerationCore(sourceFiles, result);
701 			if (sgen != null)
702 				sgen.jnaerationCompleted();
703 			feedback.wrappersGenerated(result);
704 			
705 			if (config.compile) {
706 				for (Map.Entry<String, String> cnAndSrc : config.extraJavaSourceFilesContents.entrySet()) {
707 					mfm.addSourceInput(cnAndSrc.getKey(), cnAndSrc.getValue());
708 				}
709 				feedback.setStatus("Compiling JNAerated files...");
710 				CompilerUtils.compile(c, mfm, diagnostics, "1.5", config.cacheDir, NativeLibrary.class, JNAerator.class, NSClass.class, Mangling.class);
711 				CompilerUtils.CompilationError.throwErrors(diagnostics.getDiagnostics(), mfm.inputs, c.getClass().getName());
712 				
713 				if (config.outputJar != null && result.config.bundleRuntime) {
714 					feedback.setStatus("Copying runtime classes...");
715 					addRuntimeClasses(result, mfm);
716 				}
717 			}
718 			if (config.outputJar != null) {
719 				
720 				feedback.setStatus("Generating " + config.outputJar.getName());
721 				mfm.writeJar(config.outputJar, config.bundleSources, getAdditionalFiles());
722 			}
723 //			if (true)
724 //				throw new RuntimeException("no luck !");
725 			feedback.setFinished(config.outputJar != null ? config.outputJar : config.outputDir);
726 		} catch (Throwable th) {
727 			feedback.setFinished(th);
728 		}
729 	}
730 	
731 	public void parseLibSymbols(SourceFiles sourceFiles, Result result) throws FileNotFoundException {
732 		PrintWriter fileOut = null;
733 		if (config.extractedSymbolsOut != null) {
734 			if (config.verbose)
735 				System.out.println("Writing symbols extracted from libraries to '" + config.extractedSymbolsOut + "'");
736 			fileOut = new PrintWriter(config.extractedSymbolsOut);
737 		}
738 		
739 		for (File libFile : config.libraryFiles) {
740 			if (libFile.getName().toLowerCase().endsWith(".dll")) {
741 				try {
742 					result.feedback.setStatus("Extracting symbols from " + libFile.getName() + "...");
743 					
744 					SourceFile sf = new SourceFile();
745 					sf.setElementFile(libFile.toString());
746 					List<ParsedExport> dllExports = DllExport.parseDllExports(libFile);
747 					Map<String, Struct> cppClasses = new HashMap<String, Struct>();
748 					Pattern pubPat = Pattern.compile("(public|private|protected):(.*)");
749 					for (ParsedExport dllExport : dllExports) {
750 						//dllExport.mangling
751 						String dem = dllExport.demangled;
752 						Matcher m = pubPat.matcher(dem);
753 						String pub = null;
754 						if (m.matches()) {
755 							dem = m.group(2);
756 							pub = m.group(1);
757 						}
758 						String text = "// @mangling " + dllExport.mangling + "\n" + 
759 							dem + ";";
760 						ObjCppParser parser = JNAeratorParser.newObjCppParser(result.typeConverter, text, false);//config.verbose);
761 						parser.setupSymbolsStack();
762 						List<Declaration> decls = parser.declarationEOF();
763 						if (decls == null)
764 							continue;
765 						
766 						for (Declaration decl : decls) {
767 							if (decl instanceof VariablesDeclaration && decl.getValueType() != null)
768 								decl.getValueType().addModifiers(Modifier.Extern);
769 							decl.addModifiers(Modifier.parseModifier(pub));
770 							if (decl instanceof Function) {
771 								Function f = (Function)decl;
772 								List<SimpleIdentifier> si = new ArrayList<SimpleIdentifier>(f.getName().resolveSimpleIdentifiers());
773 								Identifier ci;
774 								if (si.size() == 1) {
775 									String name = si.get(0) == null ? null : si.get(0).toString();
776 									String[] cm = name == null ? null : RegexUtils.match(name, classAndMethodNamePattern);
777 									if (cm == null) {
778 										sf.addDeclaration(decl);
779 										continue;
780 									}
781 									ci = ident(cm[0]);
782 									f.setName(ident(cm[1]));
783 								} else {
784 									si.remove(si.size() - 1);
785 									ci = new QualifiedIdentifier(QualificationSeparator.Colons, si);
786 								}
787 								if (dem.contains("__thiscall"))
788 									f.addModifiers(Modifier.__thiscall);
789 								if (dem.contains("__fastcall"))
790 									f.addModifiers(Modifier.__fastcall);
791 								
792 								Struct s = cppClasses.get(ci.toString());
793 								if (s == null) {
794 									s = new Struct();
795 									cppClasses.put(ci.toString(), s);
796 									s.setType(Struct.Type.CPPClass);
797 									s.setTag(ci.clone());
798 									sf.addDeclaration(decl(s));
799 								}
800 								Identifier n = f.getName().resolveLastSimpleIdentifier();
801 //										String ns = n.toString();
802 //										if (ns.startsWith("_"))
803 //											n = ident(ns.substring(1));
804 								f.setName(n);
805 								s.addDeclaration(f);
806 							} else
807 								sf.addDeclaration(decl);
808 						}
809 					}
810 					if (!sf.getDeclarations().isEmpty()) {
811 						sourceFiles.add(sf);
812 						if (fileOut != null)
813 							fileOut.println(sf);
814 					}
815 					
816 				} catch (Throwable ex) {
817 					ex.printStackTrace();
818 				}
819 			}
820 		}
821 		if (fileOut != null)
822 			fileOut.close();
823 	}
824 	private Map<String, File> getAdditionalFiles() {
825 
826 		Map<String, File> additionalFiles = new HashMap<String,File>();
827 
828 		if (config.bundleLibraries) {
829 			for (Map.Entry<String, List<File>> e : config.libraryFilesByArch.entrySet()) {
830 				String arch = e.getKey();
831 				for (File libraryFile : e.getValue())
832 					additionalFiles.put(
833 						"libraries/" + (arch == null || arch.length() == 0 ? "" : arch + "/") + libraryFile.getName(), 
834 						libraryFile
835 					);
836 			}
837 			for (String library : new HashSet<String>(config.libraryByFile.values())) {
838 				String libraryFileName = System.mapLibraryName(library);
839 				File libraryFile = new File(libraryFileName); 
840 				//TODO lookup in library path
841 				if (!libraryFile.exists() && libraryFileName.endsWith(".jnilib"))
842 					libraryFile = new File(libraryFileName = libraryFileName.substring(0, libraryFileName.length() - ".jnilib".length()) + ".dylib");
843 					
844 				String key = "libraries/" + LibraryExtractor.getCurrentOSAndArchString() + "/" + libraryFile.getName();
845 				if (additionalFiles.containsKey(key))
846 					continue;
847 				
848 				if (libraryFile.exists()) {
849 					System.out.println("Bundling " + libraryFile);
850 					additionalFiles.put(key, libraryFile);
851 				}// else {
852 					//System.out.println("File " + libraryFileName + " not found");
853 				//}
854 			}
855 		}
856 		return additionalFiles;
857 	}
858 	protected void addRuntimeClasses(Result result, MemoryFileManager mfm) throws IOException {
859 		
860 		ClassLoader classLoader = JNAerator.class.getClassLoader();
861 		String listingFile = "jnaerator-runtime.jar.files";
862 		List<String> files = ReadText.readLines(classLoader.getResourceAsStream(listingFile ));
863 		
864 		try {
865 			if (files == null)
866 				files = ReadText.readLines("/Users/ochafik/Prog/Java/bin/jnaerator-runtime.jar.files");
867 		} catch (Exception ex) {}
868 //		if (files == null)
869 //			throw new FileNotFoundException(listingFile);
870 		
871 		if (files == null) {
872 			throw new FileNotFoundException("Warning: Could not find JNAerator listing file '" + listingFile + "' : JNAerated files will need JNAerator in the path to execute.");
873 //			ex.printStackTrace();
874 //			ex.printStackTrace(new PrintStream(new FileOutputStream(FileDescriptor.err)));
875 //			return;
876 		}
877 		
878 		boolean needsObjCRuntime = result.hasObjectiveC();
879 		for (String file : files) {
880 			if (!needsObjCRuntime) {
881 				if (!file.startsWith("com/ochafik") &&
882 						!file.startsWith("com/sun/jna"))
883 					continue;
884 			}
885 			
886 			URL url = classLoader.getResource(file);
887 			if (url == null) {
888 				if (file.matches("com/sun/jna/[^/]+/(lib\\w+\\.(jnilib|so)|\\w+\\.dll)")) {
889 					System.out.println("JNA library missing : " + file);
890 					continue;
891 				}
892 				if (file.matches("com/ochafik/lang/jnaerator/runtime/scala/.*\\.part")) {
893 					System.out.println("Scala code missing : " + file);
894 					continue;
895 				}
896 				throw new FileNotFoundException(file);
897 			}
898 			
899 			file = "file:///" + file;
900 			if (!mfm.outputs.containsKey(file)) {
901 				mfm.outputs.put(file, new URLFileObject(url));
902 			}
903 		}
904 		/*
905 		for (URL sourceJar : new URL[] {
906 				ClassUtils.getClassPath(NativeLibrary.class),
907 				ClassUtils.getClassPath(Rococoa.class)
908 		})
909 			for (URL resURL : URLUtils.listFiles(sourceJar, null)) {
910 				String s = resURL.getFile();
911 				if (s.startsWith("META-INF"))
912 					continue;
913 				
914 				if (!mfm.outputs.containsKey(s)) {
915 					mfm.outputs.put(s, new URLFileObject(resURL));
916 				}
917 			}
918 		*/
919 	}
920 	public static File getDir(String name) {
921 		File dir = new File(getDir(), name);
922 		dir.mkdirs();
923 		return dir;
924 	}
925 	public static File getDir() {
926 		File dir = new File(System.getProperty("user.home"));
927 		dir = new File(dir, ".jnaerator");
928 		dir = new File(dir, "temp");
929 		dir.mkdirs();
930 		return dir;
931 	}
932 	static boolean isHexDigit(char c) {
933 		return 
934 			c >= 'A' && c <= 'F' ||
935 			c >= 'a' && c <= 'f' ||
936 			Character.isDigit(c);
937 	}
938 	static void escapeUnicode(String s, StringBuilder bout) {
939 		bout.setLength(0);
940 		char[] chars = s.toCharArray();
941 		for (int iChar = 0, nChars = chars.length; iChar < nChars; iChar++) {
942 			char c = chars[iChar];
943 			int v = (int)c;
944 			if (v > 127) {
945 				bout.append("\\u");
946 				String h = Integer.toHexString(v);
947 				for (int i = 4 - h.length(); i-- != 0;)
948 					bout.append('0');
949 				bout.append(h);
950 			} else {
951 				// handle \\uXXXX -> \\uuXXXX transformation :
952 //				if (c == '\\' && 
953 //						iChar < nChars - 5 && 
954 //						chars[iChar + 1] == 'u' &&
955 //						isHexDigit(chars[iChar + 2]) &&
956 //						isHexDigit(chars[iChar + 3]) &&
957 //						isHexDigit(chars[iChar + 4]) &&
958 //						isHexDigit(chars[iChar + 5])
959 //				) {
960 //					bout.append("\\u");
961 //				}
962 				bout.append(c);
963 			}
964 		}
965 	}
966 			
967 	public SourceFiles parseSources(Feedback feedback, TypeConversion typeConverter) throws IOException, LexerException {
968 		feedback.setStatus("Parsing native headers...");
969 		return JNAeratorParser.parse(config, typeConverter);
970 	}
971 	public void addFile(File file, List<File> out) throws IOException {
972 		if (file.isFile()) {
973 			out.add(file);
974 		} else {
975 			File[] fs = file.listFiles();
976 			if (fs != null) {
977 				for (File f : fs) {
978 					addFile(f, out);
979 				}
980 			}
981 		}
982 	}
983 	
984 	private static void generateLibraryFiles(SourceFiles sourceFiles, Result result) throws IOException {
985 		
986 		Struct librariesHub = null;
987 		PrintWriter hubOut = null;
988 		if (result.config.entryName != null) {
989 			librariesHub = new Struct();
990 			librariesHub.addToCommentBefore("JNA Wrappers instances");
991 			librariesHub.setType(Type.JavaClass);
992 			librariesHub.addModifiers(Modifier.Public, Modifier.Abstract);
993 			Identifier hubName = result.getHubFullClassName();
994 			librariesHub.setTag(hubName.resolveLastSimpleIdentifier());
995 			hubOut = result.classOutputter.getClassSourceWriter(hubName.toString());
996 			hubOut.println("package " + hubName.resolveAllButLastIdentifier() + ";");
997 			for (Identifier pn : result.javaPackages)
998 				if (!pn.equals(""))
999 					hubOut.println("import " + pn + ".*;");
1000 		}
1001 		for (String library : result.libraries) {
1002 			if (library == null)
1003 				continue; // to handle code defined in macro-expanded expressions
1004 //				library = "";
1005 			
1006 			Identifier javaPackage = result.javaPackageByLibrary.get(library);
1007 			Identifier simpleLibraryClassName = result.getLibraryClassSimpleName(library);
1008 			
1009 			Identifier fullLibraryClassName = result.getLibraryClassFullName(library);//ident(javaPackage, libraryClassName);
1010 			//if (!result.objCClasses.isEmpty())
1011 			//	out.println("import org.rococoa.ID;");
1012 			
1013 			
1014 			Struct interf = new Struct();
1015 			interf.addToCommentBefore("JNA Wrapper for library <b>" + library + "</b>",
1016 					result.declarationsConverter.getFileCommentContent(result.config.libraryProjectSources.get(library), null)
1017 			);
1018 			if (hubOut != null)
1019 				interf.addToCommentBefore("@see " + result.config.entryName + "." + library);
1020 			
1021 			interf.addModifiers(Modifier.Public);
1022 			interf.setTag(simpleLibraryClassName);
1023 			Identifier libSuperInter = ident(Library.class);
1024 			if (result.config.useJNADirectCalls) {
1025 				interf.addProtocols(libSuperInter);
1026 				interf.setType(Type.JavaClass);
1027 			} else {
1028 				interf.setParents(libSuperInter);
1029 				interf.setType(Type.JavaInterface);
1030 			}
1031 			
1032 			Expression libNameExpr = opaqueExpr(result.getLibraryFileExpression(library));
1033 			TypeRef libTypeRef = typeRef(fullLibraryClassName);
1034 			Expression libClassLiteral = classLiteral(libTypeRef);
1035 			
1036 			Expression libraryPathGetterExpr = methodCall(
1037 				expr(typeRef(LibraryExtractor.class)),
1038 				MemberRefStyle.Dot,
1039 				"getLibraryPath",
1040 				libNameExpr,
1041 				expr(true),
1042 				libClassLiteral
1043 			);
1044 			
1045 			String libNameStringFieldName = "JNA_LIBRARY_NAME", nativeLibFieldName = "JNA_NATIVE_LIB";
1046 			interf.addDeclaration(new VariablesDeclaration(typeRef(String.class), new Declarator.DirectDeclarator(
1047 				libNameStringFieldName,
1048 				libraryPathGetterExpr
1049 			)).addModifiers(Modifier.Public, Modifier.Static, Modifier.Final));
1050 			
1051 			Expression libraryNameFieldExpr = memberRef(expr(libTypeRef.clone()), MemberRefStyle.Dot, ident(libNameStringFieldName));
1052 			Expression optionsMapExpr = memberRef(expr(typeRef(MangledFunctionMapper.class)), MemberRefStyle.Dot, "DEFAULT_OPTIONS");
1053 			interf.addDeclaration(new VariablesDeclaration(typeRef(NativeLibrary.class), new Declarator.DirectDeclarator(
1054 				nativeLibFieldName,
1055 				methodCall(
1056 					expr(typeRef(NativeLibrary.class)),
1057 					MemberRefStyle.Dot,
1058 					"getInstance",
1059 					libraryNameFieldExpr.clone(),
1060 					optionsMapExpr.clone()
1061 				)
1062 			)).addModifiers(Modifier.Public, Modifier.Static, Modifier.Final));
1063 			Expression nativeLibFieldExpr = memberRef(expr(libTypeRef.clone()), MemberRefStyle.Dot, ident(nativeLibFieldName));
1064 				
1065 			if (result.config.useJNADirectCalls) {
1066 				interf.addDeclaration(new Function(Function.Type.StaticInit, null, null).setBody(block(
1067 					stat(methodCall(
1068 						expr(typeRef(Native.class)),
1069 						MemberRefStyle.Dot,
1070 						"register",
1071 						libraryNameFieldExpr.clone()
1072 					))
1073 				)).addModifiers(Modifier.Static));
1074 			} else {
1075 				VariablesDeclaration instanceDecl = new VariablesDeclaration(libTypeRef, new Declarator.DirectDeclarator(
1076 					librariesHub == null ? "INSTANCE" : library,
1077 					cast(
1078 						libTypeRef, 
1079 						methodCall(
1080 							expr(typeRef(Native.class)),
1081 							MemberRefStyle.Dot,
1082 							"loadLibrary",
1083 							libraryNameFieldExpr.clone(),
1084 							libClassLiteral,
1085 							optionsMapExpr.clone()
1086 						)
1087 					)
1088 				)).addModifiers(Modifier.Public, Modifier.Static, Modifier.Final);
1089 				if (librariesHub != null) {
1090 					librariesHub.addDeclaration(instanceDecl);
1091 					librariesHub.addProtocol(fullLibraryClassName.clone());
1092 				} else
1093 					interf.addDeclaration(instanceDecl);
1094 			}
1095 			
1096 			//out.println("\tpublic " + libraryClassName + " INSTANCE = (" + libraryClassName + ")" + Native.class.getName() + ".loadLibrary(" + libraryNameExpression  + ", " + libraryClassName + ".class);");
1097 			
1098 			Signatures signatures = result.getSignaturesForOutputClass(fullLibraryClassName);
1099 			result.typeConverter.allowFakePointers = true;
1100 			result.declarationsConverter.convertEnums(result.enumsByLibrary.get(library), signatures, interf, fullLibraryClassName);
1101 			result.declarationsConverter.convertConstants(library, result.definesByLibrary.get(library), sourceFiles, signatures, interf, fullLibraryClassName);
1102 			result.declarationsConverter.convertStructs(result.structsByLibrary.get(library), signatures, interf, fullLibraryClassName);
1103 			result.declarationsConverter.convertCallbacks(result.callbacksByLibrary.get(library), signatures, interf, fullLibraryClassName);
1104 			result.declarationsConverter.convertFunctions(result.functionsByLibrary.get(library), signatures, interf, fullLibraryClassName);
1105 			result.globalsGenerator.convertGlobals(result.globalsByLibrary.get(library), signatures, interf, nativeLibFieldExpr, fullLibraryClassName, library);
1106 
1107 			result.typeConverter.allowFakePointers = false;
1108 			
1109 			Set<String> fakePointers = result.fakePointersByLibrary.get(fullLibraryClassName);
1110 			if (fakePointers != null)
1111 			for (String fakePointerName : fakePointers) {
1112 				if (fakePointerName.contains("::"))
1113 					continue;
1114 				
1115 				Identifier fakePointer = ident(fakePointerName);
1116 				if (!signatures.classSignatures.add(fakePointer))
1117 					continue;
1118 				
1119 				Struct ptClass = result.declarationsConverter.publicStaticClass(fakePointer, ident(PointerType.class), Struct.Type.JavaClass, null);
1120 				ptClass.addToCommentBefore("Pointer to unknown (opaque) type");
1121 				ptClass.addDeclaration(new Function(Function.Type.JavaMethod, fakePointer, null,
1122 					new Arg("pointer", typeRef(Pointer.class))
1123 				).addModifiers(Modifier.Public).setBody(
1124 					block(stat(methodCall("super", varRef("pointer")))))
1125 				);
1126 				ptClass.addDeclaration(new Function(Function.Type.JavaMethod, fakePointer, null)
1127 				.addModifiers(Modifier.Public)
1128 				.setBody(
1129 					block(stat(methodCall("super")))
1130 				));
1131 				interf.addDeclaration(decl(ptClass));
1132 			}
1133 			
1134 			interf = result.notifyBeforeWritingClass(fullLibraryClassName, interf, signatures, library);
1135 			if (interf != null) {
1136 				final PrintWriter out = result.classOutputter.getClassSourceWriter(fullLibraryClassName.toString());
1137 				
1138 				//out.println("///\n/// This file was autogenerated by JNAerator (http://jnaerator.googlecode.com/), \n/// a tool written by Olivier Chafik (http://ochafik.free.fr/).\n///");
1139 				result.printJavaHeader(javaPackage, out);
1140 				out.println(interf);
1141 				out.close();
1142 			}
1143 		}
1144 		if (hubOut != null) {
1145 			hubOut.println(librariesHub.toString());
1146 			hubOut.close();
1147 		}
1148 	}
1149 	/// To be overridden
1150 	public Result createResult(final ClassOutputter outputter, Feedback feedback) {
1151 		Result r = new Result(config, new ClassOutputter() {
1152 			@Override
1153 			public PrintWriter getClassSourceWriter(String className)
1154 					throws IOException {
1155 				PrintWriter w = outputter.getClassSourceWriter(className);
1156 				return new PrintWriter(w) {
1157 					StringBuilder bout = new StringBuilder();
1158 					@Override
1159 					public void print(String s) {
1160 						escapeUnicode(s, bout);
1161 						super.print(bout.toString());
1162 					}
1163 				};
1164 			}
1165 		});
1166 		r.feedback = feedback;
1167 		return r;
1168 	}
1169 
1170 	public static ObjCppParser newParser(String s) throws IOException {
1171 		Result result = new Result(new JNAeratorConfig(), null);
1172 		ObjCppParser parser = new ObjCppParser(new CommonTokenStream(new ObjCppLexer(
1173 				new ANTLRReaderStream(new StringReader(s))))
1174 		// , new DummyDebugEventListener()
1175 		);
1176 		parser.typeConverter = result.typeConverter;
1177 		return parser;
1178 	}
1179 	protected void readChoices(Result result) throws IOException, RecognitionException {
1180 		BufferedReader in = new BufferedReader(new FileReader(result.config.choicesInputFile));
1181 		String line;
1182 
1183 		List<Function> functions = null;
1184 
1185 		int iLine = 0;
1186 		while ((line = in.readLine()) != null) {
1187 			iLine++;
1188 			line = line.trim();
1189 			if (line.startsWith("//"))
1190 				continue;
1191 			if (line.length() == 0)
1192 				functions = null;
1193 
1194 
1195 
1196 			Function function = null;
1197 			if (functions == null) {
1198 				function = newParser(line).javaMethodDeclaration();
1199 			} else {
1200 				function = newParser(line).functionDeclaration().function;
1201 			}
1202 			if (function == null) {
1203 				System.err.println("Error: failed to parse function at line " + iLine + ": '" + line + "'");
1204 				continue;
1205 			}
1206 			if (functions == null)
1207 				result.declarationsConverter.functionAlternativesByNativeSignature.put(
1208 					function.computeSignature(false),
1209 					new Pair<Function, List<Function>>(
1210 						function,
1211 						functions = new ArrayList<Function>()
1212 					)
1213 				);
1214 			else
1215 				functions.add(function);
1216 		}
1217 
1218 		System.err.println("Read " + result.declarationsConverter.functionAlternativesByNativeSignature.size() + " custom declarations from " + result.config.choicesInputFile);
1219 	}
1220 		
1221 	public void jnaerationCore(SourceFiles sourceFiles, Result result) throws IOException, LexerException, RecognitionException {
1222 		result.feedback.setStatus("Normalizing parsed code...");
1223 
1224 		if (result.config.choicesInputFile != null)
1225 			readChoices(result);
1226 		
1227 		/// Perform Objective-C-specific pre-transformation (javadoc conversion for enums + find name of enums based on next sibling integer typedefs)
1228 		sourceFiles.accept(new ObjectiveCToJavaPreScanner());
1229 
1230 		/// Explode declarations to have only one direct declarator each
1231 		sourceFiles.accept(new CToJavaPreScanner());
1232 		
1233 		/// Give sensible names to anonymous function signatures, structs, enums, unions, and move them up one level as typedefs
1234 		sourceFiles.accept(new MissingNamesChooser(result));
1235 		
1236 		/// Move storage modifiers up to the storage
1237 		sourceFiles.accept(new Scanner() {
1238 			@Override
1239 			protected void visitTypeRef(TypeRef tr) {
1240 				super.visitTypeRef(tr);
1241 				Element parent = tr.getParentElement();
1242 				if (parent instanceof TypeRef) {// || parent instanceof VariablesDeclaration) {
1243 					List<Modifier> stoMods = getStoMods(tr.getModifiers());
1244 					if (stoMods != null) {
1245 						List<Modifier> newMods = new ArrayList<Modifier>(tr.getModifiers());
1246 						newMods.removeAll(stoMods);
1247 						tr.setModifiers(newMods);
1248 						((ModifiableElement)parent).addModifiers(stoMods);
1249 					}
1250 				}
1251 			}
1252 			public List<Modifier> getStoMods(List<Modifier> mods) {
1253 				List<Modifier> ret = null;
1254 				for (Modifier mod : mods) {
1255 					if (mod.isA(ModifierKind.StorageClassSpecifier)) {
1256 						if (ret == null)
1257 							ret = new ArrayList<Modifier>();
1258 						ret.add(mod);
1259 					}
1260 				}
1261 				return ret;
1262 			}
1263 		});
1264 		
1265 		/// Build JavaDoc comments where applicable
1266 		sourceFiles.accept(new JavaDocCreator(result));
1267 		
1268 		assert checkNoCycles(sourceFiles);
1269 		
1270 		//##################################################################
1271 		//##### BEGINNING HERE, sourceFiles NO LONGER GETS MODIFIED ! ######
1272 		//##################################################################
1273 		
1274 		if (result.feedback != null && !result.config.bridgeSupportFiles.isEmpty())
1275 			result.feedback.setStatus("Parsing BridgeSupport files...");
1276 		
1277 		//new BridgeSupportParser(result, sourceFiles).parseBridgeSupportFiles();
1278 		
1279 		/// Gather Objective-C classes
1280 		sourceFiles.accept(result);
1281 		result.rehabilitateWeakTypeDefs();
1282 		
1283 		result.chooseLibraryClasses(config.packageName, config.rootPackageName);
1284 		
1285 		//TODO resolve variables in visual studio projects
1286 		//TODO Propagate unconvertible expressions, mark corresponding elements / trees as "to be commented out"
1287 		
1288 		/// Resolution's first pass : define relevant chained environment for each element
1289 //		final DefinitionsVisitor definitions = new DefinitionsVisitor();
1290 //		sourceFiles.accept(definitions);
1291 		
1292 		/// Resolve references of variables and types (map id -> type)
1293 //		ResolutionScanner resolutions = new ResolutionScanner(definitions, originalOut);
1294 //		sourceFiles.accept(resolutions);
1295 		
1296 
1297 		/// Filter unused symbols from implicitely included files
1298 //		if (config.symbolsAccepter != null) {
1299 //			originalOut.println("Filtering unused symbols");
1300 //			UnusedScanner unused = new UnusedScanner(resolutions, config.symbolsAccepter, null);//originalOut);
1301 //			sourceFiles.accept(unused);
1302 //			unused.removeUnused(null);	
1303 //		}
1304 		
1305 		
1306 		/// Spit Objective-C classes out
1307 		if (!result.classes.isEmpty()) {
1308 			result.feedback.setStatus("Generating Objective-C classes...");
1309 			result.objectiveCGenerator.generateObjectiveCClasses();
1310 		}
1311 		
1312 		result.feedback.setStatus("Generating libraries...");
1313 		
1314 		if (result.libraries.size() == 1) {
1315 			List<Define> list = result.definesByLibrary.get(null);
1316 			if (list != null) {
1317 				String lib = result.libraries.iterator().next();
1318 				Result.getList(result.definesByLibrary, lib).addAll(list);
1319 			}
1320 		}
1321 		
1322 		generateLibraryFiles(sourceFiles, result);
1323 
1324 		//if (config.verbose)
1325 		for (String unknownType : result.typeConverter.unknownTypes) 
1326 			System.out.println("Unknown Type: " + unknownType);
1327 
1328 		if (result.config.choicesOutFile != null) {
1329 			PrintWriter out = new PrintWriter(result.config.choicesOutFile);
1330 			for (Map.Entry<String, Pair<Function, List<Function>>> e : result.declarationsConverter.functionAlternativesByNativeSignature.entrySet()) {
1331 				Function f = e.getValue().getKey();
1332 				String ff = f.getElementFile();
1333 				if (ff != null)
1334 					out.println("// " + ff + (f.getElementLine() > 0 ? ":" + f.getElementLine() : ""));
1335 
1336 				out.println(f);
1337 				for (Function alt : e.getValue().getValue()) {
1338 					out.println(alt);
1339 				}
1340 				out.println();
1341 			}
1342 			out.close();
1343 		}
1344 	}
1345 	private boolean checkNoCycles(SourceFiles sourceFiles) {
1346 		final HashSet<Integer> ids = new HashSet<Integer>(new Arg().getId());
1347 		sourceFiles.accept(new Scanner() {
1348 			@Override
1349 			protected void visitElement(Element d) {
1350 				if (d != null && !ids.add(d.getId()))
1351 					throw new RuntimeException("Cycle : " + d);
1352 				super.visitElement(d);
1353 			}
1354 		});
1355 		return true;
1356 	}
1357 
1358 }