xref: /haiku/3rdparty/proj2make/proj2make.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
1 /*
2  * Copyright 2012 Aleksas Pantechovskis, <alexp.frl@gmail.com>
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include <exception>
7 #include <fstream>
8 #include <iostream>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string>
12 #include <string.h>
13 
14 #include <ByteOrder.h>
15 #include <FindDirectory.h>
16 #include <Path.h>
17 #include <String.h>
18 #include <TypeConstants.h>
19 
20 
21 using namespace std;
22 
23 
24 const char* kUsageMessage = \
25 	"proj2make usage:\n"
26 	"# proj2make <projPath> [makePath]\n"
27 	"# if makePath parameter doesn't specified makefile will be created in\n"
28 	"#	the same directory as .proj file\n"
29 	"# example: proj2make /boot/home/myprog/myprog.proj\n";
30 
31 fstream gProjFile;
32 uint32 gProjLength;
33 uint8* gProjData;
34 
35 fstream gMakeFile;
36 
37 fstream gTemplateFile;
38 
39 string gSPthString;
40 string gPPthString;
41 string gFil1String;
42 string gLinkString;
43 string gPLnkString;
44 
45 const char* gAppTypes[] = {
46 	"APP",
47 	"SHARED",
48 	"STATIC",
49 	"DRIVER"
50 };
51 
52 uint8 gAppType;
53 string gAppName;
54 
55 struct hdr
56 {
Idhdr57 			uint32	Id() { return static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fId)); }
Sizehdr58 			uint32	Size() { return static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fSize)); }
Datahdr59 			const char* Data() { return (char*)(this + 1); }
60 private:
61 			uint32 fId;
62 			uint32 fSize;
63 };
64 
65 
66 class Error : public std::exception
67 {
68 			BString		fWhat;
69 public:
70 						Error(const char* what, ...);
~Error()71 	virtual				~Error() throw() {}
what() const72 	virtual const char*	what() const throw() { return fWhat.String(); }
73 };
74 
75 
Error(const char * what,...)76 Error::Error(const char* what, ...)
77 {
78 	const int size = 1024;
79 	va_list args;
80 	va_start(args, what);
81 	vsnprintf(fWhat.LockBuffer(size), size, what, args);
82 	fWhat.UnlockBuffer();
83 	va_end(args);
84 }
85 
86 
87 void
CheckFiles(const char * projPath,const char * makePath)88 CheckFiles(const char* projPath, const char* makePath)
89 {
90 	gProjFile.open(projPath, fstream::in | fstream::binary);
91 	if (!gProjFile.is_open())
92 		throw Error("%s not found", projPath);
93 
94 	gProjFile.seekg(0, ios::end);
95 	uint32 projFileLength = gProjFile.tellg();
96 	gProjFile.seekg(0, ios::beg);
97 
98 	char* name = new char[5];
99 	gProjFile.read(name, 4);
100 
101 	uint32 length;
102 	gProjFile.read((char*)&length, 4);
103 	name[4] = '\0';
104 	length = static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(length));
105 	gProjLength = length + 8;
106 
107 	if (strcmp(name, "MIDE") != 0 || gProjLength > projFileLength)
108 		throw Error("File corrupted or it is not BeIDE *.proj file");
109 
110 	gMakeFile.open(makePath, fstream::in);
111 	if (gMakeFile.is_open())
112 		throw Error("%s already exists", makePath);
113 
114 	gMakeFile.open(makePath, fstream::out);
115 	if (!gMakeFile.is_open())
116 		throw Error("Can not create makefile");
117 
118 	BPath templateFileName;
119 	find_directory(B_SYSTEM_DEVELOP_DIRECTORY, &templateFileName);
120 	templateFileName.Append("etc/Makefile");
121 
122 	gTemplateFile.open(templateFileName.Path(), fstream::in);
123 	if (!gTemplateFile.is_open())
124 		throw Error("Can not open template %s", templateFileName.Path());
125 }
126 
127 
128 void
ParseGenB(hdr * data)129 ParseGenB(hdr* data)
130 {
131 	hdr* child = (hdr*)data->Data();
132 	char* name = (char*)(child + 1);
133 	int len = strlen(name) + 1;
134 
135 	uint32 u = child->Id();
136 	char* c = (char*)&u;
137 	printf("\t%c%c%c%c:%d:%s\n", c[3], c[2], c[1], c[0], child->Size(), name);
138 
139 	if (strncmp(name, "ProjectPrefsx86", len - 1) == 0) {
140 		const char* type = child->Data() + len + 8;
141 		if (*type <= 3)
142 			gAppType = *type;
143 		type++;
144 		type += 64; // skip the mime type name
145 		gAppName = type;
146 	}
147 }
148 
149 
150 class _l {
151 	static string _s;
152 
153 public:
_l()154 	_l() { _s += " "; }
~_l()155 	~_l() { _s.resize(_s.size() - 1); }
156 
str()157 	const char* str() { return _s.c_str(); }
158 };
159 
160 string _l::_s;
161 
162 
163 void
Parse(hdr * current,hdr * parent)164 Parse(hdr* current, hdr* parent)
165 {
166 	_l l;
167 
168 	uint32 u = current->Id();
169 	char* c = (char*)&u;
170 	printf("%#06x:%s%c%c%c%c:%d\n", (uint8*)current - gProjData, l.str(), c[3], c[2], c[1], c[0],
171 		current->Size());
172 
173 	bool useGrandParent = false;
174 	size_t off = 0;
175 	BString data;
176 	switch (current->Id()) {
177 		case 'Fil1':
178 		case 'Link':
179 		case 'PLnk':
180 			off = 24;
181 			break;
182 		case 'MIDE':
183 		case 'DPrf':
184 		case 'GPrf':
185 			break;
186 		case 'MSFl':
187 			off = 8;
188 			useGrandParent = true;
189 			break;
190 		case 'SPth':
191 			data = &current->Data()[5];
192 			// Avoid adding these library paths as include dirs.
193 			if ((data.FindFirst("/boot/develop/lib") > -1)
194 				|| (data.FindFirst("/boot/beos/system/lib") > -1)) {
195 				return;
196 			}
197 			// Replace BeOS paths with Haiku's.
198 			data.ReplaceFirst("/boot/develop/headers/be", "/boot/system/develop/os");
199 			data.ReplaceFirst("/boot/develop/headers/cpp", "/boot/system/develop/c++");
200 			data.ReplaceFirst("/boot/develop/headers/posix", "/boot/system/develop/headers/posix");
201 
202 			gSPthString += " \\\n\t";
203 			gSPthString += data.String();
204 			return;
205 		case 'PPth':
206 			gPPthString += " \\\n\t";
207 			gPPthString += &current->Data()[5];
208 			return;
209 		case 'Name':
210 			if (parent->Id() == 'Fil1') {
211 				gFil1String += " \\\n\t";
212 				gFil1String += &current->Data()[4];
213 			} else if (parent->Id() == 'Link') {
214 				gLinkString += " \\\n\t";
215 				gLinkString += &current->Data()[4];
216 			} else if (parent->Id() == 'PLnk') {
217 				gPLnkString += " \\\n\t";
218 				gPLnkString += &current->Data()[4];
219 			}
220 			return;
221 		case 'GenB':
222 			ParseGenB(current);
223 			return;
224 		default:
225 			return;
226 	}
227 
228 	hdr* child = (hdr*)(current->Data() + off);
229 	while (off < current->Size()) {
230 		Parse(child, useGrandParent ? parent : current);
231 		off += child->Size() + sizeof(hdr);
232 		child = (hdr*)(child->Data() + child->Size());
233 	}
234 }
235 
236 
237 void
ReadProj()238 ReadProj()
239 {
240 	gProjFile.seekg(0, ios::beg);
241 	gProjData = new uint8[gProjLength];
242 	gProjFile.read((char*)gProjData, gProjLength);
243 	gProjFile.close();
244 
245 	Parse((hdr*)gProjData, NULL);
246 }
247 
248 
249 void
Proj2Make()250 Proj2Make()
251 {
252 	gFil1String = "";
253 	gLinkString = "";
254 	gPLnkString = "";
255 	gSPthString = "";
256 	gPPthString = "";
257 
258 	ReadProj();
259 	string str;
260 	while (gTemplateFile.good()) {
261 		getline(gTemplateFile, str);
262 
263 		if (str.find("SRCS") == 0)
264 			str = str + gFil1String;
265 		else if (str.find("LIBS") == 0)
266 			str = str + gLinkString;
267 		else if (str.find("SYSTEM_INCLUDE_PATHS") == 0)
268 			str = str + gSPthString;
269 		else if (str.find("LOCAL_INCLUDE_PATHS") == 0)
270 			str = str + gPPthString;
271 		else if (str.find("TYPE") == 0)
272 			str = str + " " + gAppTypes[gAppType];
273 		else if (str.find("NAME") == 0)
274 			str = str + " " + gAppName;
275 		else if (str.find("RSRCS") == 0)
276 			str = str + gPLnkString;
277 
278 		gMakeFile << str << endl;
279 	}
280 
281 	gMakeFile.close();
282 	gTemplateFile.close();
283 }
284 
285 
286 int
main(int argc,char ** argv)287 main(int argc, char** argv)
288 {
289 	try {
290 		if (argc <= 1 || (argc > 1 && strcmp(argv[1], "--help") == 0))
291 			throw Error("");
292 
293 		BString projPath = argv[1];
294 
295 		BString makePath;
296 		// if makefile path specified
297 		if (argc > 2)
298 			makePath = argv[2];
299 		// default makefile path
300 		else {
301 			BPath path(argv[1]);
302 			path.GetParent(&path);
303 			path.Append("makefile");
304 			makePath = path.Path();
305 		}
306 
307 		CheckFiles(projPath.String(), makePath.String());
308 
309 		Proj2Make();
310 
311 	} catch (exception& exc) {
312 		cerr << argv[0] << " : " << exc.what() << endl;
313 		cerr << kUsageMessage;
314 		return B_ERROR;
315 	}
316 
317 	return B_OK;
318 }
319