1 /*
2  * This file is part of gir-to-d.
3  *
4  * gir-to-d is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation, either version 3
7  * of the License, or (at your option) any later version.
8  *
9  * gir-to-d is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with gir-to-d.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 module girtod;
19 
20 import std.algorithm: canFind, find, findSkip, startsWith;
21 import std.array;
22 import std.file : exists, getcwd, isFile;
23 import std.getopt;
24 import std.path;
25 import std.stdio;
26 import core.stdc.stdlib;
27 
28 import gtd.GirWrapper;
29 import gtd.Log;
30 import gtd.WrapException;
31 
32 void main(string[] args)
33 {
34 	bool printFree;
35 	string lookupFile = "APILookup.txt";
36 
37 	GirWrapper wrapper = new GirWrapper("./", "./out");
38 	Option printFilesOption;
39 
40 	wrapper.cwdOrBaseDirectory = getcwd();
41 
42 	printFilesOption.optLong = "--print-files";
43 	printFilesOption.help    = "Write a newline separated list of generated files to stdout. Optionally you can pass 'relative[,/base/path] or 'full' to force printing the relative or full paths of the files.";
44 
45 	auto helpInformation = getopt(
46 		args,
47 		std.getopt.config.passThrough,
48 		"input|i",            "Directory containing the API description. Or a lookup file (Default: ./)", &wrapper.inputDir,
49 		"output|o",           "Output directory for the generated binding. (Default: ./out)", &wrapper.outputDir,
50 		"use-runtime-linker", "Link the gtk functions with the runtime linker.", &wrapper.useRuntimeLinker,
51 		"gir-directory|g",    "Directory to search for gir files before the system directory.", &wrapper.commandlineGirPath,
52 		"print-free",         "Print functions that don't have a parent module.", &printFree,
53 		"use-bind-dir",       "Include public imports for the old gtkc package.", &wrapper.useBindDir,
54 		"version",            "Print the version and exit", (){ writeln("GIR to D ", import("VERSION")); exit(0); }
55 	);
56 
57 	if (helpInformation.helpWanted)
58 	{
59 		defaultGetoptPrinter("girtod is an utility that generates D bindings using the GObject introspection files.\n\nOptions:",
60 			helpInformation.options ~ printFilesOption);
61 		exit(0);
62 	}
63 
64 	if ( args.length > 1 )
65 		handlePrintFiles(args, wrapper);
66 
67 	if ( wrapper.inputDir.exists && wrapper.inputDir.isFile() )
68 	{
69 		lookupFile = wrapper.inputDir.baseName();
70 		wrapper.inputDir = wrapper.inputDir.dirName();
71 	}
72 
73 	try
74 	{
75 		//Read in the GIR and API files.
76 		if ( lookupFile.extension == ".gir" )
77 			wrapper.proccessGIR(lookupFile);
78 		else
79 			wrapper.proccess(lookupFile);
80 
81 		if ( printFree )
82 			wrapper.printFreeFunctions();
83 
84 		//Generate the D binding
85 		foreach(pack; wrapper.packages)
86 		{
87 			if ( pack.name == "cairo" )
88 				continue;
89 
90 			if ( wrapper.useRuntimeLinker )
91 				pack.writeLoaderTable();
92 			else
93 				pack.writeExternalFunctions();
94 
95 			pack.writeTypes();
96 			pack.writeClasses();
97 		}
98 	}
99 	catch (WrapException ex)
100 	{
101 		error(ex);
102 	}
103 }
104 
105 void handlePrintFiles(string[] args, GirWrapper wrapper)
106 {
107 	string value;
108 
109 	args.popFront();
110 
111 	if ( args.front.startsWith("--print-files") )
112 	{
113 		if ( args.front.findSkip("=") )
114 		{
115 			value = args.front;
116 		}
117 
118 		args.popFront();
119 
120 		if ( value.empty && !args.empty && !args.front.startsWith("--") )
121 		{
122 			value = args.front;
123 			args.popFront();
124 		}
125 	}
126 	
127 	if ( !args.empty )
128 	{
129 		writeln("Unable to parse parameters: Unrecognized option ", args.front);
130 		exit(0);
131 	}
132 
133 	wrapper.printFiles = true;
134 
135 	if ( value == "absolute" || value == "full" )
136 	{
137 		wrapper.printFileMethod = PrintFileMethod.Absolute;
138 	}
139 	else if ( value.startsWith("relative") )
140 	{
141 		wrapper.printFileMethod = PrintFileMethod.Relative;
142 
143 		if ( value.findSkip(",") )
144 			wrapper.cwdOrBaseDirectory = value;
145 
146 		if ( !isAbsolute(wrapper.cwdOrBaseDirectory) )
147 			error("The base directory passed to relative must be absolute.");
148 	}
149 	else if ( !value.empty )
150 	{
151 		error("Unknown option: '", value, "' for print-files.");
152 	}
153 }