/* 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} ,{"strip" ,&mhmakefileparser::f_strip} }; 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->GetQuotedFullFileName(); } return Ret; } /////////////////////////////////////////////////////////////////////////////// string mhmakefileparser::f_fullname(const string & Arg) const { string File=TrimString(Arg); refptr pFile=GetFileInfo(File); return pFile->GetQuotedFullFileName(); } /////////////////////////////////////////////////////////////////////////////// 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]=='"' && FileName.end()[-1]=='"') 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]=='"' && FileName.end()[-1]=='"') 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) retPath=retPath+OSPATHSEPSTR+pLast; } else { if (*pCur) retPath=".."OSPATHSEPSTR; while (*pCur) { if (*pCur==OSPATHSEP) retPath+=".."OSPATHSEPSTR; pCur++; } retPath+=pLast; } return QuoteFileName(retPath); } /////////////////////////////////////////////////////////////////////////////// // Make a path name relative to the current 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); }