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 = ¤t->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 += ¤t->Data()[5];
208 return;
209 case 'Name':
210 if (parent->Id() == 'Fil1') {
211 gFil1String += " \\\n\t";
212 gFil1String += ¤t->Data()[4];
213 } else if (parent->Id() == 'Link') {
214 gLinkString += " \\\n\t";
215 gLinkString += ¤t->Data()[4];
216 } else if (parent->Id() == 'PLnk') {
217 gPLnkString += " \\\n\t";
218 gPLnkString += ¤t->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