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 { 57 uint32 Id() { return static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fId)); } 58 uint32 Size() { return static_cast<uint32>(B_BENDIAN_TO_HOST_INT32(fSize)); } 59 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, ...); 71 virtual ~Error() throw() {} 72 virtual const char* what() const throw() { return fWhat.String(); } 73 }; 74 75 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 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 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: 154 _l() { _s += " "; } 155 ~_l() { _s.resize(_s.size() - 1); } 156 157 const char* str() { return _s.c_str(); } 158 }; 159 160 string _l::_s; 161 162 163 void 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 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 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 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