aboutsummaryrefslogtreecommitdiff
path: root/tools/mhmake/src/functions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mhmake/src/functions.cpp')
-rw-r--r--tools/mhmake/src/functions.cpp782
1 files changed, 782 insertions, 0 deletions
diff --git a/tools/mhmake/src/functions.cpp b/tools/mhmake/src/functions.cpp
new file mode 100644
index 000000000..9564610f8
--- /dev/null
+++ b/tools/mhmake/src/functions.cpp
@@ -0,0 +1,782 @@
+/* This file is part of mhmake.
+ *
+ * Copyright (C) 2001-2009 Marc Haesen
+ *
+ * Mhmake is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mhmake is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mhmake. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* $Rev$ */
+
+#include "stdafx.h"
+
+#include "util.h"
+#include "mhmakefileparser.h"
+#include "rule.h"
+
+static const string s_QuoteString("\"");
+
+funcdef mhmakefileparser::m_FunctionsDef[]= {
+ {"filter", &mhmakefileparser::f_filter}
+ ,{"call", &mhmakefileparser::f_call}
+ ,{"subst", &mhmakefileparser::f_subst}
+ ,{"patsubst", &mhmakefileparser::f_patsubst}
+ ,{"concat", &mhmakefileparser::f_concat}
+ ,{"if", &mhmakefileparser::f_if}
+ ,{"findstring", &mhmakefileparser::f_findstring}
+ ,{"firstword", &mhmakefileparser::f_firstword}
+ ,{"wildcard", &mhmakefileparser::f_wildcard}
+ ,{"basename", &mhmakefileparser::f_basename}
+ ,{"notdir", &mhmakefileparser::f_notdir}
+ ,{"dir", &mhmakefileparser::f_dir}
+ ,{"shell", &mhmakefileparser::f_shell}
+ ,{"relpath", &mhmakefileparser::f_relpath}
+ ,{"toupper", &mhmakefileparser::f_toupper}
+ ,{"tolower", &mhmakefileparser::f_tolower}
+ ,{"exist", &mhmakefileparser::f_exist}
+ ,{"filesindirs",&mhmakefileparser::f_filesindirs}
+ ,{"fullname" ,&mhmakefileparser::f_fullname}
+ ,{"addprefix" ,&mhmakefileparser::f_addprefix}
+ ,{"addsuffix" ,&mhmakefileparser::f_addsuffix}
+ ,{"filter-out" ,&mhmakefileparser::f_filterout}
+ ,{"word" ,&mhmakefileparser::f_word}
+ ,{"words" ,&mhmakefileparser::f_words}
+ ,{"strip" ,&mhmakefileparser::f_strip}
+};
+
+map<string,function_f> mhmakefileparser::m_Functions;
+
+bool mhmakefileparser::m_FunctionsInitialised;
+
+///////////////////////////////////////////////////////////////////////////////
+void mhmakefileparser::InitFuncs(void)
+{
+ for (int i=0; i<sizeof(m_FunctionsDef)/sizeof(funcdef); i++)
+ m_Functions[m_FunctionsDef[i].szFuncName]=m_FunctionsDef[i].pFunc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string TrimString(const string &Input)
+{
+ unsigned Start=0;
+ while (strchr(" \t",Input[Start])) Start++;
+ if (Start>=Input.size())
+ return g_EmptyString;
+ unsigned Stop=Input.size()-1;
+ while (strchr(" \t",Input[Stop])) Stop--;
+ return Input.substr(Start,Stop-Start+1);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_filter(const string & Arg) const
+{
+ int ipos=Arg.find(',');
+ #ifdef _DEBUG
+ if (ipos==string::npos) {
+ cerr << "filter func should have 2 arguments: "<<Arg<<endl;
+ throw 1;
+ }
+ #endif
+ string Str=TrimString(Arg.substr(0,ipos));
+ string List=Arg.substr(ipos+1);
+
+ if (Str.empty())
+ return Str;
+
+ bool First=true;
+ string Ret;
+ char *pTok=strtok((char*)List.c_str()," \t"); // doing this is changing string, so this is very dangerous
+ while (pTok)
+ {
+ string Item(pTok);
+ if (PercentMatchList(Item,Str))
+ {
+ if (First)
+ {
+ Ret=Item;
+ First=false;
+ }
+ else
+ {
+ Ret+=g_SpaceString;
+ Ret+=Item;
+ }
+ }
+ pTok=strtok(NULL," \t");
+ }
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_filterout(const string & Arg) const
+{
+ int ipos=Arg.find(',');
+ #ifdef _DEBUG
+ if (ipos==string::npos) {
+ cerr << "filter func should have 2 arguments: "<<Arg<<endl;
+ throw 1;
+ }
+ #endif
+ string Str=TrimString(Arg.substr(0,ipos));
+ string List=Arg.substr(ipos+1);
+
+ if (Str.empty())
+ return Str;
+
+ bool First=true;
+ string Ret;
+ char *pTok=strtok((char*)List.c_str()," \t"); // doing this is changing string, so this is very dangerous
+ while (pTok)
+ {
+ string Item(pTok);
+ if (!PercentMatchList(Item,Str))
+ {
+ if (First)
+ {
+ Ret=Item;
+ First=false;
+ }
+ else
+ {
+ Ret+=g_SpaceString;
+ Ret+=Item;
+ }
+ }
+ pTok=strtok(NULL," \t");
+ }
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_call(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ bool LastCharIsComma=Arg[Arg.length()-1]==',';
+
+ string Func;
+ pTmp=NextCharItem(pTmp,Func,',');
+ map<string,string>::const_iterator pFunc=m_Variables.find(Func);
+ #ifdef _DEBUG
+ if (pFunc==m_Variables.end())
+ {
+ fprintf(stderr,"call to non existing function %s\n",Func.c_str());
+ throw(1);
+ }
+ #endif
+ Func=pFunc->second;
+ int i=0;
+ while (*pTmp || LastCharIsComma) {
+ if (!*pTmp)
+ LastCharIsComma=false; /* To stop the loop */
+ string Repl;
+ pTmp=NextCharItem(pTmp,Repl,',');
+ i++;
+ char Tmp[10];
+ ::sprintf(Tmp,"$(%d)",i);
+ int Len=::strlen(Tmp);
+ int Pos=Func.find(Tmp);
+ while (Func.npos!=Pos)
+ {
+ Func=Func.substr(0,Pos)+Repl+Func.substr(Pos+Len);
+ Pos=Func.find(Tmp,Pos+Len);
+ }
+ }
+
+ return ExpandExpression(Func);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_subst(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string FromString;
+ pTmp=NextCharItem(pTmp,FromString,',');
+ #ifdef _DEBUG
+ if (!*pTmp) {
+ cerr << "Wrong number of arguments in function subst" << endl;
+ throw(1);
+ }
+ #endif
+
+ string ToString;
+ pTmp=NextCharItem(pTmp,ToString,',');
+ string Text;
+ NextCharItem(pTmp,Text,',');
+
+ if (FromString.empty())
+ return Text;
+
+ string Ret;
+ int Pos=Text.find(FromString);
+ int PrevPos=0;
+ while (Pos!=string::npos)
+ {
+ Ret+=Text.substr(PrevPos,Pos-PrevPos);
+ Ret+=ToString;
+ PrevPos=Pos+FromString.length();
+ Pos=Text.find(FromString,PrevPos);
+ }
+ Ret+=Text.substr(PrevPos);
+
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_patsubst(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string FromString;
+ pTmp=NextCharItem(pTmp,FromString,',');
+ #ifdef _DEBUG
+ if (!*pTmp) {
+ cerr << "Wrong number of arguments in function subst" << endl;
+ throw(1);
+ }
+ #endif
+
+ string ToString;
+ pTmp=NextCharItem(pTmp,ToString,',');
+ string Text;
+ NextCharItem(pTmp,Text,',');
+
+ if (FromString.empty())
+ return Text;
+
+ return Substitute(Text,FromString,ToString);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_concat(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string JoinString;
+ pTmp=NextCharItem(pTmp,JoinString,',');
+
+ string List;
+ pTmp=NextCharItem(pTmp,List,',');
+
+ if (JoinString.empty() && List.empty())
+ {
+ /* assume as $(concat ,,items) construct */
+ JoinString=",";
+ pTmp=NextCharItem(pTmp,List,',');
+ }
+
+ bool First=true;
+ string Ret;
+ char *pTok=strtok((char*)List.c_str()," \t"); // doing this is changing string, so this is very dangerous
+ while (pTok)
+ {
+ if (First)
+ {
+ First=false;
+ }
+ else
+ {
+ Ret+=JoinString;
+ }
+ Ret+=pTok;
+ pTok=strtok(NULL," \t");
+ }
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_if(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string Cond;
+ pTmp=NextCharItem(pTmp,Cond,',');
+ string Ret;
+ if (Cond.empty())
+ {
+ pTmp=NextCharItem(pTmp,Ret,',');
+ }
+ NextCharItem(pTmp,Ret,',');
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_findstring(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+ string find;
+ pTmp=NextCharItem(pTmp,find,',');
+ string instr;
+ NextCharItem(pTmp,instr,',');
+
+ if (instr.find(find) != instr.npos)
+ return find;
+ else
+ return g_EmptyString;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_firstword(const string & Arg) const
+{
+ string FirstWord;
+ NextItem(Arg.c_str(),FirstWord);
+ return FirstWord;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_wildcard(const string & Arg) const
+{
+ string FileSpec=TrimString(Arg);
+ int LastSep=FileSpec.find_last_of(OSPATHSEP)+1;
+ string Dir=FileSpec.substr(0,LastSep);
+#ifdef WIN32
+ struct _finddata_t FileInfo;
+ long hFile=_findfirst(FileSpec.c_str(),&FileInfo);
+ if (hFile==-1)
+ return g_EmptyString;
+
+ string Ret=g_EmptyString;
+
+ /* We have to verify with percentmatch since the find functions *.ext also matches the functions *.xmlbrol */
+ string CheckSpec=FileSpec.substr(LastSep);
+ if (PercentMatch(FileInfo.name,CheckSpec,NULL,'*'))
+ {
+ Ret=Dir+FileInfo.name;
+ }
+ while (-1!=_findnext(hFile,&FileInfo))
+ {
+ if (PercentMatch(FileInfo.name,CheckSpec,NULL,'*'))
+ {
+ Ret+=g_SpaceString;
+ Ret+=Dir;
+ Ret+=FileInfo.name;
+ }
+ }
+ _findclose(hFile);
+#else
+ glob_t Res;
+ if (glob (FileSpec.c_str(), GLOB_ERR|GLOB_NOSORT|GLOB_MARK, NULL, &Res))
+ return g_EmptyString;
+
+ string Ret=g_EmptyString;
+ string SepStr=g_EmptyString;
+ for (int i=0; i<Res.gl_pathc; i++)
+ {
+ if (PercentMatch(Res.gl_pathv[i],FileSpec,NULL,'*'))
+ {
+ Ret+=SepStr;
+ Ret+=Res.gl_pathv[i];
+ SepStr=g_SpaceString;
+ }
+ }
+
+ globfree(&Res);
+#endif
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_exist(const string & Arg) const
+{
+ string File=TrimString(Arg);
+ refptr<fileinfo> pFile=GetFileInfo(File);
+ if (pFile->Exists())
+ {
+ return string("1");
+ }
+ else
+ return g_EmptyString;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_filesindirs(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string strFiles;
+ pTmp=NextCharItem(pTmp,strFiles,',');
+ #ifdef _DEBUG
+ if (!*pTmp) {
+ cerr << "Wrong number of arguments in function filesindirs" << endl;
+ throw(1);
+ }
+ #endif
+ string strDirs;
+ NextCharItem(pTmp,strDirs,',');
+
+ vector< refptr<fileinfo> > Dirs;
+ SplitToItems(strDirs,Dirs);
+
+ pTmp=strFiles.c_str();
+ string Ret=g_EmptyString;
+ bool first=true;
+ while (*pTmp)
+ {
+ string File;
+ refptr<fileinfo> pFile;
+ pTmp=NextItem(pTmp,File);
+
+ vector< refptr<fileinfo> >::iterator It=Dirs.begin();
+ vector< refptr<fileinfo> >::iterator ItEnd=Dirs.end();
+ while (It!=ItEnd)
+ {
+ pFile=GetFileInfo(File,*It++);
+ if (pFile->Exists())
+ {
+ break;
+ }
+ pFile=NullFileInfo;
+ }
+ if (!pFile)
+ continue;
+
+ if (!first)
+ {
+ Ret+=g_SpaceString;
+ }
+ else
+ {
+ first=false;
+ }
+ Ret+=pFile->GetFullFileName();
+ }
+
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_fullname(const string & Arg) const
+{
+ string File=TrimString(Arg);
+ refptr<fileinfo> pFile=GetFileInfo(File);
+ return pFile->GetFullFileName();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string IterList(const string &List,string (*iterFunc)(const string &FileName,const string &Arg),const string &Arg=NullString)
+{
+ const char *pTmp=List.c_str();
+ string Ret=g_EmptyString;
+ bool first=true;
+ while (*pTmp)
+ {
+ if (!first)
+ {
+ Ret+=g_SpaceString;
+ }
+ else
+ {
+ first=false;
+ }
+ string Item;
+ pTmp=NextItem(pTmp,Item);
+ Ret+=iterFunc(Item,Arg);
+ }
+
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string basename(const string &FileName,const string &)
+{
+ string Ret=FileName.substr(0,FileName.find_last_of('.'));
+ if (FileName[0]=='"')
+ Ret+=s_QuoteString;
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_basename(const string & FileNames) const
+{
+ return IterList(FileNames,basename);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string notdir(const string &FileName,const string &)
+{
+ int Pos=FileName.find_last_of(OSPATHSEP);
+ if (Pos==string::npos)
+ {
+ return FileName;
+ }
+ else
+ {
+ string Ret=g_EmptyString;
+ if (FileName[0]=='"')
+ Ret+=s_QuoteString;
+ Ret+=FileName.substr(Pos+1);
+ return Ret;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_notdir(const string & FileNames) const
+{
+ return IterList(FileNames,notdir);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string addprefix(const string &FileName,const string &Prefix)
+{
+ return Prefix+FileName;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_addprefix(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+ string PreFix;
+ pTmp=NextCharItem(pTmp,PreFix,',');
+ #ifdef _DEBUG
+ if (!*pTmp) {
+ cerr << "Wrong number of arguments in function addprefix" << endl;
+ throw(1);
+ }
+ #endif
+ string FileNames;
+ pTmp=NextCharItem(pTmp,FileNames,',');
+ return IterList(FileNames,addprefix,PreFix);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string addsuffix(const string &FileName,const string &Suffix)
+{
+ return FileName+Suffix;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_addsuffix(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+ string SufFix;
+ pTmp=NextCharItem(pTmp,SufFix,',');
+ #ifdef _DEBUG
+ if (!*pTmp) {
+ cerr << "Wrong number of arguments in function addsuffix" << endl;
+ throw(1);
+ }
+ #endif
+ string FileNames;
+ pTmp=NextCharItem(pTmp,FileNames,',');
+ return IterList(FileNames,addsuffix,SufFix);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Returns the n-th word number
+string mhmakefileparser::f_word(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+
+ string strNum;
+ pTmp=NextCharItem(pTmp,strNum,',');
+
+ int WordNbr=atoi(strNum.c_str());
+
+ #ifdef _DEBUG
+ if (!WordNbr)
+ {
+ if (!WordNbr) {
+ cerr << "Expecting a number bigger then 0 for the word function"<<endl;
+ throw(1);
+ }
+ }
+ #endif
+
+ int CurWord=0;
+ while (*pTmp)
+ {
+ string Word;
+ pTmp=NextItem(pTmp,Word);
+ CurWord++;
+ if (CurWord==WordNbr)
+ return Word;
+ }
+
+ return g_EmptyString;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Returns the number of words
+string mhmakefileparser::f_words(const string & Arg) const
+{
+ const char *pTmp=Arg.c_str();
+ int NrWords=0;
+ char szNumber[10];
+ while (*pTmp)
+ {
+ string Word;
+ pTmp=NextItem(pTmp,Word);
+ NrWords++;
+ }
+ sprintf(szNumber,"%d",NrWords);
+
+ return szNumber;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Removes leading and trailing space
+string mhmakefileparser::f_strip(const string & Arg) const
+{
+ string::const_iterator pFirst=Arg.begin();
+ string::const_iterator pLast=Arg.end();
+ while (strchr(" \t",*pFirst) && pFirst!=pLast) pFirst++;
+ if (pFirst==pLast)
+ return "";
+ while (strchr(" \t",*(--pLast)));
+ pLast++;
+ return Arg.substr(pFirst-Arg.begin(),pLast-pFirst);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string dir(const string &FileName,const string &)
+{
+ int Pos=FileName.find_last_of(OSPATHSEP);
+ if (Pos==string::npos)
+ {
+ return g_EmptyString;
+ }
+ else
+ {
+ string Ret=g_EmptyString;
+ Ret+=FileName.substr(0,Pos+1);
+ if (FileName[0]=='"')
+ Ret+=s_QuoteString;
+ return Ret;
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_dir(const string & FileNames) const
+{
+ return IterList(FileNames,dir);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_shell(const string & Command) const
+{
+ string Output;
+
+#ifdef _DEBUG
+ if (g_PrintAdditionalInfo)
+ cout << "shell: executing: Command '"<<Command<<"'"<<endl;
+#endif
+
+ ((mhmakefileparser*)this)->ExecuteCommand(string("@")+Command,&Output); // Make sure that the command is not echoed
+#ifdef _DEBUG
+ if (g_PrintAdditionalInfo)
+ cout << "shell returned '"<<Output<<"'"<<endl;
+#endif
+ return Output;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string relpath(const string &FileName,const string &)
+{
+ refptr<fileinfo> Path=GetFileInfo(FileName);
+ const char *pCur=curdir::GetCurDir()->GetFullFileName().c_str();
+ const char *pPath=Path->GetFullFileName().c_str();
+
+ const char *pLast=pPath;
+ while (*pCur==*pPath)
+ {
+ char Char=*pPath;
+ if (!Char)
+ {
+ return "."; // Means that FileName is the same as the current directory
+ }
+ if (Char==OSPATHSEP)
+ pLast=pPath+1;
+ pCur++;
+ pPath++;
+ }
+ if (*pPath==OSPATHSEP && !*pCur)
+ pLast=pPath+1;
+ string retPath;
+ if (*pCur==OSPATHSEP) {
+ bool first=true;
+ pCur++;
+ retPath="..";
+ while (*pCur)
+ {
+ if (*pCur==OSPATHSEP)
+ retPath+=OSPATHSEPSTR"..";
+ pCur++;
+ }
+ if (!pPath)
+ return retPath;
+ else
+ return retPath+OSPATHSEPSTR+pLast;
+ }
+ else
+ {
+ if (*pCur)
+ retPath=".."OSPATHSEPSTR;
+ while (*pCur)
+ {
+ if (*pCur==OSPATHSEP)
+ retPath+=".."OSPATHSEPSTR;
+ pCur++;
+ }
+ retPath+=pLast;
+ return retPath;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Make a path name relative to the curren directory
+string mhmakefileparser::f_relpath(const string & FileNames) const
+{
+ return IterList(FileNames,relpath);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string makeupper(const string &FileName,const string &)
+{
+ string Ret=FileName;
+ string::const_iterator pSrc=FileName.begin();
+ string::iterator pDest=Ret.begin();
+ while (pSrc!=FileName.end())
+ {
+ *pDest++ = toupper(*pSrc++);
+ }
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_toupper(const string & FileNames) const
+{
+ return IterList(FileNames,makeupper);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+static string makelower(const string &FileName,const string &)
+{
+ string Ret=FileName;
+ string::const_iterator pSrc=FileName.begin();
+ string::iterator pDest=Ret.begin();
+ while (pSrc!=FileName.end())
+ {
+ *pDest++ = tolower(*pSrc++);
+ }
+ return Ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+string mhmakefileparser::f_tolower(const string & FileNames) const
+{
+ return IterList(FileNames,makelower);
+}
+