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 	try
68 	{
69 		//Read in the GIR and API files.
70 		if ( wrapper.inputDir.extension == ".gir" )
71 		{
72 			wrapper.proccessGIR(wrapper.inputDir);
73 		}
74 		else
75 		{
76 			if ( wrapper.inputDir.exists && wrapper.inputDir.isFile() )
77 			{
78 				lookupFile = wrapper.inputDir.baseName();
79 				wrapper.inputDir = wrapper.inputDir.dirName();
80 			}
81 			wrapper.proccess(lookupFile);
82 		}
83 
84 		if ( printFree )
85 			wrapper.printFreeFunctions();
86 
87 		//Generate the D binding
88 		foreach(pack; wrapper.packages)
89 		{
90 			if ( pack.name == "cairo" )
91 				continue;
92 
93 			if ( wrapper.useRuntimeLinker )
94 				pack.writeLoaderTable();
95 			else
96 				pack.writeExternalFunctions();
97 
98 			pack.writeTypes();
99 			pack.writeClasses();
100 		}
101 	}
102 	catch (WrapException ex)
103 	{
104 		error(ex);
105 	}
106 }
107 
108 void handlePrintFiles(string[] args, GirWrapper wrapper)
109 {
110 	string value;
111 
112 	args.popFront();
113 
114 	if ( args.front.startsWith("--print-files") )
115 	{
116 		if ( args.front.findSkip("=") )
117 		{
118 			value = args.front;
119 		}
120 
121 		args.popFront();
122 
123 		if ( value.empty && !args.empty && !args.front.startsWith("--") )
124 		{
125 			value = args.front;
126 			args.popFront();
127 		}
128 	}
129 	
130 	if ( !args.empty )
131 	{
132 		writeln("Unable to parse parameters: Unrecognized option ", args.front);
133 		exit(0);
134 	}
135 
136 	wrapper.printFiles = true;
137 
138 	if ( value == "absolute" || value == "full" )
139 	{
140 		wrapper.printFileMethod = PrintFileMethod.Absolute;
141 	}
142 	else if ( value.startsWith("relative") )
143 	{
144 		wrapper.printFileMethod = PrintFileMethod.Relative;
145 
146 		if ( value.findSkip(",") )
147 			wrapper.cwdOrBaseDirectory = value;
148 
149 		if ( !isAbsolute(wrapper.cwdOrBaseDirectory) )
150 			error("The base directory passed to relative must be absolute.");
151 	}
152 	else if ( !value.empty )
153 	{
154 		error("Unknown option: '", value, "' for print-files.");
155 	}
156 }