/* * Copyright 2012 Aleksas Pantechovskis, * All rights reserved. Distributed under the terms of the MIT License. */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; const char* kUsageMessage = \ "proj2make usage:\n" "# proj2make [makePath]\n" "# if makePath parameter doesn't specified makefile will be created in\n" "# the same directory as .proj file\n" "# example: proj2make /boot/home/myprog/myprog.proj\n"; fstream gProjFile; uint32 gProjLength; uint8* gProjData; fstream gMakeFile; fstream gTemplateFile; string gSPthString; string gPPthString; string gFil1String; string gLinkString; string gPLnkString; const char* gAppTypes[] = { "APP", "SHARED", "STAITC", "DRIVER" }; uint8 gAppType; string gAppName; struct hdr { uint32 Id() { return static_cast(B_BENDIAN_TO_HOST_INT32(fId)); } uint32 Size() { return static_cast(B_BENDIAN_TO_HOST_INT32(fSize)); } const char* Data() { return (char*)(this + 1); } private: uint32 fId; uint32 fSize; }; class Error : public std::exception { BString fWhat; public: Error(const char* what, ...); virtual ~Error() throw() {} virtual const char* what() const throw() { return fWhat.String(); } }; Error::Error(const char* what, ...) { const int size = 1024; va_list args; va_start(args, what); vsnprintf(fWhat.LockBuffer(size), size, what, args); fWhat.UnlockBuffer(); va_end(args); } void CheckFiles(const char* projPath, const char* makePath) { gProjFile.open(projPath, fstream::in | fstream::binary); if (!gProjFile.is_open()) throw Error("%s not found", projPath); gProjFile.seekg(0, ios::end); uint32 projFileLength = gProjFile.tellg(); gProjFile.seekg(0, ios::beg); char* name = new char[5]; gProjFile.read(name, 4); uint32 length; gProjFile.read((char*)&length, 4); name[4] = '\0'; length = static_cast(B_BENDIAN_TO_HOST_INT32(length)); gProjLength = length + 8; if (strcmp(name, "MIDE") != 0 || gProjLength > projFileLength) throw Error("File corrupted or it is not BeIDE *.proj file"); gMakeFile.open(makePath, fstream::in); if (gMakeFile.is_open()) throw Error("%s already exists", makePath); gMakeFile.open(makePath, fstream::out); if (!gMakeFile.is_open()) throw Error("Can not create makefile"); BPath templateFileName; // not supporter yet in my haiku rev // find_directory(B_SYSTEM_DEVELOP_DIR, &templateFileName); // templateFileName.Append("etc/makefile"); templateFileName.SetTo("/boot/develop/etc/makefile"); gTemplateFile.open(templateFileName.Path(), fstream::in); if (!gTemplateFile.is_open()) throw Error("Can not open template %s", templateFileName.Path()); } void ParseGenB(hdr* data) { hdr* child = (hdr*)data->Data(); char* name = (char*)(child + 1); int len = strlen(name) + 1; uint32 u = child->Id(); char* c = (char*)&u; printf("\t%c%c%c%c:%d:%s\n", c[3], c[2], c[1], c[0], child->Size(), name); if (strncmp(name, "ProjectPrefsx86", len - 1) == 0) { const char* type = child->Data() + len + 8; if (*type <= 3) gAppType = *type; type++; type += 64; // skip the mime type name gAppName = type; } } class _l { static string _s; public: _l() { _s += " " ; } ~_l() { _s.resize(_s.size() - 1); } char* str() { _s.c_str(); } }; string _l::_s; void Parse(hdr* current, hdr* parent) { _l l; uint32 u = current->Id(); char* c = (char*)&u; printf("%#06x:%s%c%c%c%c:%d\n", (uint8*)current - gProjData, l.str(), c[3], c[2], c[1], c[0], current->Size()); bool useGrandParent = false; size_t off = 0; switch(current->Id()) { case 'Fil1': case 'Link': case 'PLnk': off = 24; break; case 'MIDE': case 'DPrf': case 'GPrf': break; case 'MSFl': off = 8; useGrandParent = true; break; case 'SPth': gSPthString += " \\\n\t"; gSPthString += ¤t->Data()[5]; return; case 'PPth': gPPthString += " \\\n\t"; gPPthString += ¤t->Data()[5]; return; case 'Name': if (parent->Id() == 'Fil1') { gFil1String += " \\\n\t"; gFil1String += ¤t->Data()[4]; } else if (parent->Id() == 'Link') { gLinkString += " \\\n\t"; gLinkString += ¤t->Data()[4]; } else if (parent->Id() == 'PLnk') { gPLnkString += " \\\n\t"; gPLnkString += ¤t->Data()[4]; } return; case 'GenB': ParseGenB(current); return; default: return; } hdr* child = (hdr*)(current->Data() + off); while (off < current->Size()) { Parse(child, useGrandParent ? parent : current); off += child->Size() + sizeof(hdr); child = (hdr*)(child->Data() + child->Size()); } } void ReadProj() { gProjFile.seekg(0, ios::beg); gProjData = new uint8[gProjLength]; gProjFile.read((char*)gProjData, gProjLength); gProjFile.close(); Parse((hdr*)gProjData, NULL); } void Proj2Make() { gFil1String = " "; gLinkString = " "; gPLnkString = " "; gSPthString = " "; gPPthString = " "; ReadProj(); string str; while (gTemplateFile.good()) { getline(gTemplateFile, str); if (str.find("SRCS") == 0) str = str + gFil1String; else if (str.find("LIBS") == 0) str = str + gLinkString; else if (str.find("SYSTEM_INCLUDE_PATHS") == 0) str = str + gSPthString; else if (str.find("LOCAL_INCLUDE_PATHS") == 0) str = str + gPPthString; else if (str.find("TYPE") == 0) str = str + gAppTypes[gAppType]; else if (str.find("NAME") == 0) str = str + gAppName; else if (str.find("RSRCS") == 0) str = str + gPLnkString; gMakeFile << str << endl; } gMakeFile.close(); gTemplateFile.close(); } int main(int argc, char** argv) { try { if (argc <= 1 || (argc > 1 && strcmp(argv[1], "--help") == 0)) throw Error(""); BString projPath = argv[1]; BString makePath; // if makefile path specified if (argc > 2) makePath = argv[2]; // default makefile path else { BPath path(argv[1]); path.GetParent(&path); path.Append("makefile"); makePath = path.Path(); } CheckFiles(projPath.String(), makePath.String()); Proj2Make(); } catch(exception& exc) { cerr << argv[0] << " : " << exc.what() << endl; cerr << kUsageMessage; return B_ERROR; } return B_OK; }