311 lines
6.3 KiB
C++
311 lines
6.3 KiB
C++
|
/*
|
||
|
* Copyright 2012 Aleksas Pantechovskis, <alexp.frl@gmail.com>
|
||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||
|
*/
|
||
|
|
||
|
#include <exception>
|
||
|
#include <fstream>
|
||
|
#include <iostream>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <ByteOrder.h>
|
||
|
#include <FindDirectory.h>
|
||
|
#include <Path.h>
|
||
|
#include <String.h>
|
||
|
#include <TypeConstants.h>
|
||
|
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
|
||
|
const char* kUsageMessage = \
|
||
|
"proj2make usage:\n"
|
||
|
"# proj2make <projPath> [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<uint32>(B_BENDIAN_TO_HOST_INT32(fId)); }
|
||
|
uint32 Size() { return
|
||
|
static_cast<uint32>(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<uint32>(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;
|
||
|
}
|
||
|
|