From 437bca524595d1007f37988e862db8bfeff329b0 Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 29 Jul 2009 09:17:47 +0000 Subject: Added mhmake GNU make compatible (with extensions) make utility. --- tools/mhmake/src/functions.cpp | 767 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 767 insertions(+) create mode 100644 tools/mhmake/src/functions.cpp (limited to 'tools/mhmake/src/functions.cpp') diff --git a/tools/mhmake/src/functions.cpp b/tools/mhmake/src/functions.cpp new file mode 100644 index 000000000..4ae9ddd2e --- /dev/null +++ b/tools/mhmake/src/functions.cpp @@ -0,0 +1,767 @@ +/* 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 . +*/ + +/* $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} +}; + +map mhmakefileparser::m_Functions; + +bool mhmakefileparser::m_FunctionsInitialised; + +/////////////////////////////////////////////////////////////////////////////// +void mhmakefileparser::InitFuncs(void) +{ + for (int i=0; i=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: "<::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 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 > Dirs; + SplitToItems(strDirs,Dirs); + + pTmp=strFiles.c_str(); + string Ret=g_EmptyString; + bool first=true; + while (*pTmp) + { + string File; + refptr pFile; + pTmp=NextItem(pTmp,File); + + vector< refptr >::iterator It=Dirs.begin(); + vector< refptr >::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 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"<ExecuteCommand(string("@")+Command,&Output); // Make sure that the command is not echoed +#ifdef _DEBUG + if (g_PrintAdditionalInfo) + cout << "shell returned '"< 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); +} + -- cgit v1.2.3