xref: /haiku/3rdparty/proj2make/proj2make.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
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 	"STAITC",
49 	"DRIVER"
50 };
51 
52 uint8 gAppType;
53 string gAppName;
54 
55 struct hdr
56 {
57 			uint32	Id() { return
58 						static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fId)); }
59 			uint32	Size() { return
60 						static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fSize)); }
61 			const char* Data() { return (char*)(this + 1); }
62 private:
63 			uint32 fId;
64 			uint32 fSize;
65 };
66 
67 
68 class Error : public std::exception
69 {
70 			BString		fWhat;
71 public:
72 						Error(const char* what, ...);
73 	virtual				~Error() throw() {}
74 	virtual const char*	what() const throw() { return fWhat.String(); }
75 };
76 
77 
78 Error::Error(const char* what, ...)
79 {
80 	const int size = 1024;
81 	va_list args;
82 	va_start(args, what);
83 	vsnprintf(fWhat.LockBuffer(size), size, what, args);
84 	fWhat.UnlockBuffer();
85 	va_end(args);
86 }
87 
88 
89 void
90 CheckFiles(const char* projPath, const char* makePath)
91 {
92 	gProjFile.open(projPath, fstream::in | fstream::binary);
93 	if (!gProjFile.is_open())
94 		throw Error("%s not found", projPath);
95 
96 	gProjFile.seekg(0, ios::end);
97 	uint32 projFileLength = gProjFile.tellg();
98 	gProjFile.seekg(0, ios::beg);
99 
100 	char* name = new char[5];
101 	gProjFile.read(name, 4);
102 
103 	uint32 length;
104 	gProjFile.read((char*)&length, 4);
105 	name[4] = '\0';
106 	length = static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(length));
107 	gProjLength = length + 8;
108 
109 	if (strcmp(name, "MIDE") != 0 || gProjLength > projFileLength)
110 		throw Error("File corrupted or it is not BeIDE *.proj file");
111 
112 	gMakeFile.open(makePath, fstream::in);
113 	if (gMakeFile.is_open())
114 		throw Error("%s already exists", makePath);
115 
116 	gMakeFile.open(makePath, fstream::out);
117 	if (!gMakeFile.is_open())
118 		throw Error("Can not create makefile");
119 
120 	BPath templateFileName;
121 	// not supporter yet in my haiku rev
122 	// find_directory(B_SYSTEM_DEVELOP_DIR, &templateFileName);
123 	// templateFileName.Append("etc/makefile");
124 	templateFileName.SetTo("/boot/develop/etc/makefile");
125 
126 	gTemplateFile.open(templateFileName.Path(), fstream::in);
127 	if (!gTemplateFile.is_open())
128 		throw Error("Can not open template %s", templateFileName.Path());
129 }
130 
131 
132 void
133 ParseGenB(hdr* data)
134 {
135 	hdr* child = (hdr*)data->Data();
136 	char* name = (char*)(child + 1);
137 	int len = strlen(name) + 1;
138 
139 	uint32 u = child->Id();
140 	char* c = (char*)&u;
141 	printf("\t%c%c%c%c:%d:%s\n", c[3], c[2], c[1], c[0], child->Size(), name);
142 
143 	if (strncmp(name, "ProjectPrefsx86", len - 1) == 0) {
144 		const char* type = child->Data() + len + 8;
145 		if (*type <= 3)
146 			gAppType = *type;
147 		type++;
148 		type += 64; // skip the mime type name
149 		gAppName = type;
150 	}
151 }
152 
153 
154 class _l {
155 	static string _s;
156 public:
157 	_l() { _s += " " ; }
158 	~_l() { _s.resize(_s.size() - 1); }
159 
160 	char* str() { _s.c_str(); }
161 };
162 
163 string _l::_s;
164 
165 void
166 Parse(hdr* current, hdr* parent)
167 {
168 	_l l;
169 
170 	uint32 u = current->Id();
171 	char* c = (char*)&u;
172 	printf("%#06x:%s%c%c%c%c:%d\n",
173 		(uint8*)current - gProjData, l.str(),
174 		c[3], c[2], c[1], c[0], current->Size());
175 
176 	bool useGrandParent = false;
177 	size_t off = 0;
178 	switch(current->Id()) {
179 		case 'Fil1':
180 		case 'Link':
181 		case 'PLnk':
182 			off = 24;
183 			break;
184 		case 'MIDE':
185 		case 'DPrf':
186 		case 'GPrf':
187 			break;
188 		case 'MSFl':
189 			off = 8;
190 			useGrandParent = true;
191 			break;
192 		case 'SPth':
193 			gSPthString += " \\\n\t";
194 			gSPthString += &current->Data()[5];
195 			return;
196 		case 'PPth':
197 			gPPthString += " \\\n\t";
198 			gPPthString += &current->Data()[5];
199 			return;
200 		case 'Name':
201 			if (parent->Id() == 'Fil1') {
202 				gFil1String += " \\\n\t";
203 				gFil1String += &current->Data()[4];
204 			} else if (parent->Id() == 'Link') {
205 				gLinkString += " \\\n\t";
206 				gLinkString += &current->Data()[4];
207 			} else if (parent->Id() == 'PLnk') {
208 				gPLnkString += " \\\n\t";
209 				gPLnkString += &current->Data()[4];
210 			}
211 			return;
212 		case 'GenB':
213 			ParseGenB(current);
214 			return;
215 		default:
216 			return;
217 	}
218 
219 	hdr* child = (hdr*)(current->Data() + off);
220 	while (off < current->Size()) {
221 		Parse(child, useGrandParent ? parent : current);
222 		off += child->Size() + sizeof(hdr);
223 		child = (hdr*)(child->Data() + child->Size());
224 	}
225 }
226 
227 
228 void
229 ReadProj()
230 {
231 	gProjFile.seekg(0, ios::beg);
232 	gProjData = new uint8[gProjLength];
233 	gProjFile.read((char*)gProjData, gProjLength);
234 	gProjFile.close();
235 
236 	Parse((hdr*)gProjData, NULL);
237 }
238 
239 
240 void
241 Proj2Make()
242 {
243 	gFil1String = " ";
244 	gLinkString = " ";
245 	gPLnkString = " ";
246 	gSPthString = " ";
247 	gPPthString = " ";
248 
249 	ReadProj();
250 	string str;
251 	while (gTemplateFile.good()) {
252 		getline(gTemplateFile, str);
253 
254 		if (str.find("SRCS") == 0)
255 			str = str + gFil1String;
256 		else if (str.find("LIBS") == 0)
257 			str = str + gLinkString;
258 		else if (str.find("SYSTEM_INCLUDE_PATHS") == 0)
259 			str = str + gSPthString;
260 		else if (str.find("LOCAL_INCLUDE_PATHS") == 0)
261 			str = str + gPPthString;
262 		else if (str.find("TYPE") == 0)
263 			str = str + gAppTypes[gAppType];
264 		else if (str.find("NAME") == 0)
265 			str = str + gAppName;
266 		else if (str.find("RSRCS") == 0)
267 			str = str + gPLnkString;
268 
269 		gMakeFile << str << endl;
270 	}
271 
272 	gMakeFile.close();
273 	gTemplateFile.close();
274 }
275 
276 
277 int
278 main(int argc, char** argv)
279 {
280 	try {
281 		if (argc <= 1 || (argc > 1 && strcmp(argv[1], "--help") == 0))
282 			throw Error("");
283 
284 		BString projPath = argv[1];
285 
286 		BString makePath;
287 		// if makefile path specified
288 		if (argc > 2)
289 			makePath = argv[2];
290 		// default makefile path
291 		else {
292 			BPath path(argv[1]);
293 			path.GetParent(&path);
294 			path.Append("makefile");
295 			makePath = path.Path();
296 		}
297 
298 		CheckFiles(projPath.String(), makePath.String());
299 
300 		Proj2Make();
301 
302 	} catch(exception& exc) {
303 		cerr << argv[0] << " : " << exc.what() << endl;
304 		cerr << kUsageMessage;
305 		return B_ERROR;
306 	}
307 
308 	return B_OK;
309 }
310 
311