diff --git a/buildtool.cpp b/buildtool.cpp
index 471a8194cac220c321b6f9e496377405ea07122a..c3b0a29530cc9b8e079104e02b387fca4b9ac9b3 100644 (file)
--- a/buildtool.cpp
+++ b/buildtool.cpp
*
* Authors:
* Bob Jamison
+ * Jasper van de Gronde
*
* Copyright (C) 2006-2008 Bob Jamison
*
*
*/
-#define BUILDTOOL_VERSION "BuildTool v0.9.3"
+#define BUILDTOOL_VERSION "BuildTool v0.9.5"
#include <stdio.h>
#include <fcntl.h>
#include <map>
#include <set>
#include <vector>
+#include <algorithm>
+
#ifdef __WIN32__
#include <windows.h>
@@ -688,7 +691,7 @@ static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *s
return cur;
}
case OP_WB:
- if(str == exp->_bol && !isspace(*str)
+ if((str == exp->_bol && !isspace(*str))
|| (str == exp->_eol && !isspace(*(str-1)))
|| (!isspace(*str) && isspace(*(str+1)))
|| (isspace(*str) && !isspace(*(str+1))) ) {
/**
*
*/
- String getDirectory()
+ String getDirectory() const
{ return directory; }
/**
/**
*
*/
- std::vector<String> getFiles()
+ std::vector<String> getFiles() const
{ return files; }
/**
/**
*
*/
- std::vector<String> getIncludes()
+ std::vector<String> getIncludes() const
{ return includes; }
/**
/**
*
*/
- std::vector<String> getExcludes()
+ std::vector<String> getExcludes() const
{ return excludes; }
/**
*
*/
- unsigned int size()
+ unsigned int size() const
{ return files.size(); }
/**
*
*/
- String operator[](int index)
+ String operator[](int index) const
{ return files[index]; }
/**
+
+#ifdef __WIN32__
+
/**
* Execute a system call, using pipes to send data to the
* program's stdin, and reading stdout and stderr.
outbuf.clear();
errbuf.clear();
-#ifdef __WIN32__
/*
I really hate having win32 code in this program, but the
return ret;
-#else //do it unix-style
+}
+
+#else /*do it unix style*/
+
+#include <sys/wait.h>
+
+
- String pipeCommand = command;
- pipeCommand.append(" 2>&1");
- String s;
- FILE *f = popen(pipeCommand.c_str(), "r");
- int errnum = 0;
- if (f)
+/**
+ * Execute a system call, using pipes to send data to the
+ * program's stdin, and reading stdout and stderr.
+ */
+bool MakeBase::executeCommand(const String &command,
+ const String &inbuf,
+ String &outbuf,
+ String &errbuf)
+{
+
+ status("============ cmd ============\n%s\n=============================",
+ command.c_str());
+
+ outbuf.clear();
+ errbuf.clear();
+
+
+ int outfds[2];
+ if (pipe(outfds) < 0)
+ return false;
+ int errfds[2];
+ if (pipe(errfds) < 0)
+ return false;
+ int pid = fork();
+ if (pid < 0)
+ {
+ close(outfds[0]);
+ close(outfds[1]);
+ close(errfds[0]);
+ close(errfds[1]);
+ error("launch of command '%s' failed : %s",
+ command.c_str(), strerror(errno));
+ return false;
+ }
+ else if (pid > 0) // parent
+ {
+ close(outfds[1]);
+ close(errfds[1]);
+ }
+ else // == 0, child
{
- while (true)
+ close(outfds[0]);
+ dup2(outfds[1], STDOUT_FILENO);
+ close(outfds[1]);
+ close(errfds[0]);
+ dup2(errfds[1], STDERR_FILENO);
+ close(errfds[1]);
+
+ char *args[4];
+ args[0] = (char *)"sh";
+ args[1] = (char *)"-c";
+ args[2] = (char *)command.c_str();
+ args[3] = NULL;
+ execv("/bin/sh", args);
+ exit(EXIT_FAILURE);
+ }
+
+ String outb;
+ String errb;
+
+ int outRead = outfds[0];
+ int errRead = errfds[0];
+ int max = outRead;
+ if (errRead > max)
+ max = errRead;
+
+ bool outOpen = true;
+ bool errOpen = true;
+
+ while (outOpen || errOpen)
+ {
+ char ch;
+ fd_set fdset;
+ FD_ZERO(&fdset);
+ if (outOpen)
+ FD_SET(outRead, &fdset);
+ if (errOpen)
+ FD_SET(errRead, &fdset);
+ int ret = select(max+1, &fdset, NULL, NULL, NULL);
+ if (ret < 0)
+ break;
+ if (FD_ISSET(outRead, &fdset))
{
- int ch = fgetc(f);
- if (ch < 0)
- break;
- s.push_back((char)ch);
+ if (read(outRead, &ch, 1) <= 0)
+ { outOpen = false; }
+ else if (ch <= 0)
+ { /* outOpen = false; */ }
+ else
+ { outb.push_back(ch); }
+ }
+ if (FD_ISSET(errRead, &fdset))
+ {
+ if (read(errRead, &ch, 1) <= 0)
+ { errOpen = false; }
+ else if (ch <= 0)
+ { /* errOpen = false; */ }
+ else
+ { errb.push_back(ch); }
}
- errnum = pclose(f);
}
- outbuf = s;
- if (errnum != 0)
+
+ int childReturnValue;
+ wait(&childReturnValue);
+
+ close(outRead);
+ close(errRead);
+
+ outbuf = outb;
+ errbuf = errb;
+
+ if (childReturnValue != 0)
{
error("exec of command '%s' failed : %s",
- command.c_str(), strerror(errno));
+ command.c_str(), strerror(childReturnValue));
return false;
}
- else
- return true;
-#endif
+ return true;
}
+#endif
+
if (s.size()==0)
return defaultVal;
String val = eval(s, "false");
- if (s == "true" || s == "TRUE")
+ if (val.size()==0)
+ return defaultVal;
+ if (val == "true" || val == "TRUE")
return true;
else
- return defaultVal;
+ return false;
}
fname.append(".pc");
if (!readFile(fname))
+ {
+ error("Cannot find package '%s'. Do you have it installed?",
+ pkgName.c_str());
return false;
+ }
return true;
}
TASK_NONE,
TASK_CC,
TASK_COPY,
+ TASK_CXXTEST_PART,
+ TASK_CXXTEST_ROOT,
TASK_DELETE,
TASK_ECHO,
TASK_JAR,
};
+/**
+ * Generate CxxTest files
+ */
+class TaskCxxTestPart: public Task
+{
+public:
+
+ TaskCxxTestPart(MakeBase &par) : Task(par)
+ {
+ type = TASK_CXXTEST_PART;
+ name = "cxxtestpart";
+ }
+
+ virtual ~TaskCxxTestPart()
+ {}
+
+ virtual bool execute()
+ {
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
+
+ String fullDest = parent.resolve(parent.eval(destPathOpt, "."));
+ String cmd = parent.eval(commandOpt, "cxxtestgen.py");
+ cmd.append(" --part -o ");
+ cmd.append(fullDest);
+
+ unsigned int newFiles = 0;
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fileName = fileSet[i];
+ if (getSuffix(fileName) != "h")
+ continue;
+ String sourcePath;
+ if (fileSetDir.size()>0)
+ {
+ sourcePath.append(fileSetDir);
+ sourcePath.append("/");
+ }
+ sourcePath.append(fileName);
+ String fullSource = parent.resolve(sourcePath);
+
+ cmd.append(" ");
+ cmd.append(fullSource);
+ if (isNewerThan(fullSource, fullDest)) newFiles++;
+ }
+
+ if (newFiles>0) {
+ size_t const lastSlash = fullDest.find_last_of('/');
+ if (lastSlash != fullDest.npos) {
+ String directory(fullDest, 0, lastSlash);
+ if (!createDirectory(directory))
+ return false;
+ }
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<cxxtestpart> problem: %s", errString.c_str());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ if (!parent.getAttribute(elem, "command", commandOpt))
+ return false;
+ if (!parent.getAttribute(elem, "out", destPathOpt))
+ return false;
+
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "fileset")
+ {
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String commandOpt;
+ String destPathOpt;
+ FileSet fileSet;
+
+};
+
+
+/**
+ * Generate the CxxTest root file
+ */
+class TaskCxxTestRoot: public Task
+{
+public:
+
+ TaskCxxTestRoot(MakeBase &par) : Task(par)
+ {
+ type = TASK_CXXTEST_ROOT;
+ name = "cxxtestroot";
+ }
+
+ virtual ~TaskCxxTestRoot()
+ {}
+
+ virtual bool execute()
+ {
+ if (!listFiles(parent, fileSet))
+ return false;
+ String fileSetDir = parent.eval(fileSet.getDirectory(), ".");
+ unsigned int newFiles = 0;
+
+ String fullDest = parent.resolve(parent.eval(destPathOpt, "."));
+ String cmd = parent.eval(commandOpt, "cxxtestgen.py");
+ cmd.append(" --root -o ");
+ cmd.append(fullDest);
+ String templateFile = parent.eval(templateFileOpt, "");
+ if (templateFile.size()>0) {
+ String fullTemplate = parent.resolve(templateFile);
+ cmd.append(" --template=");
+ cmd.append(fullTemplate);
+ if (isNewerThan(fullTemplate, fullDest)) newFiles++;
+ }
+
+ for (unsigned int i=0 ; i<fileSet.size() ; i++)
+ {
+ String fileName = fileSet[i];
+ if (getSuffix(fileName) != "h")
+ continue;
+ String sourcePath;
+ if (fileSetDir.size()>0)
+ {
+ sourcePath.append(fileSetDir);
+ sourcePath.append("/");
+ }
+ sourcePath.append(fileName);
+ String fullSource = parent.resolve(sourcePath);
+
+ cmd.append(" ");
+ cmd.append(fullSource);
+ if (isNewerThan(fullSource, fullDest)) newFiles++;
+ }
+
+ if (newFiles>0) {
+ size_t const lastSlash = fullDest.find_last_of('/');
+ if (lastSlash != fullDest.npos) {
+ String directory(fullDest, 0, lastSlash);
+ if (!createDirectory(directory))
+ return false;
+ }
+
+ String outString, errString;
+ if (!executeCommand(cmd.c_str(), "", outString, errString))
+ {
+ error("<cxxtestroot> problem: %s", errString.c_str());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool parse(Element *elem)
+ {
+ if (!parent.getAttribute(elem, "command", commandOpt))
+ return false;
+ if (!parent.getAttribute(elem, "template", templateFileOpt))
+ return false;
+ if (!parent.getAttribute(elem, "out", destPathOpt))
+ return false;
+
+ std::vector<Element *> children = elem->getChildren();
+ for (unsigned int i=0 ; i<children.size() ; i++)
+ {
+ Element *child = children[i];
+ String tagName = child->getName();
+ if (tagName == "fileset")
+ {
+ if (!parseFileSet(child, parent, fileSet))
+ return false;
+ }
+ }
+ return true;
+ }
+
+private:
+
+ String commandOpt;
+ String templateFileOpt;
+ String destPathOpt;
+ FileSet fileSet;
+
+};
+
+
/**
*
*/
task = new TaskCC(parent);
else if (tagName == "copy")
task = new TaskCopy(parent);
+ else if (tagName == "cxxtestpart")
+ task = new TaskCxxTestPart(parent);
+ else if (tagName == "cxxtestroot")
+ task = new TaskCxxTestRoot(parent);
else if (tagName == "delete")
task = new TaskDelete(parent);
else if (tagName == "echo")