#include "cmt_syntax.h"
#include "cmt.h"
#include "cmt_symbol.h"
#include "cmt_constituent.h"
#include "cmt_pattern.h"
#include "cmt_error.h"
#include "cmt_branch.h"
#include "cmt_error.h"
#include "cmt_script.h"
#include "cmt_language.h"
#include "cmt_project.h"
#include "cmt_cmtpath_pattern.h"
class KwdAlias : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandAlias, use);
}
};
class KwdApplication : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (use == &(Use::current ()))
{
Constituent::action (Application, words);
}
}
};
class KwdApplyPattern : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
ApplyPattern::action (words, use);
}
};
class KwdApplyTag : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Tag::action_apply (words, use);
}
};
class KwdAuthor : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
use->author_action (words);
}
};
class KwdBranches : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (use == &(Use::current ()))
{
Branch::action (words);
}
}
};
class KwdBuildStrategy : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
int strategy = Cmt::get_current_build_strategy ();
for (int i = 1; i < words.size (); i++)
{
const cmt_string& w = words[i];
if (w == "prototypes")
{
strategy |= Prototypes;
}
else if (w == "no_prototypes")
{
strategy |= NoPrototypes;
}
else if (w == "keep_makefiles")
{
strategy |= KeepMakefiles;
}
else if (w == "rebuild_makefiles")
{
strategy |= RebuildMakefiles;
}
else if (w == "with_install_area")
{
strategy |= WithInstallArea;
}
else if (w == "without_install_area")
{
strategy |= WithoutInstallArea;
}
if ((Cmt::get_action () == action_show_strategies) && !Cmt::get_quiet ())
{
cout << "# Package " << use->get_package_name ()
<< " adds " << w << " to build strategy" << endl;
}
}
Cmt::set_current_build_strategy (strategy);
}
};
class KwdCleanupScript : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Script::action (words, CleanupScript, use);
Symbol::action (words, CommandCleanupScript, use);
}
};
class KwdCmtPathPattern : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& /*file_name*/,
int /*line_number*/)
{
CmtPathPattern::action (words, use);
}
};
class KwdDocument : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (use == &(Use::current ()))
{
Constituent::action (Document, words);
}
}
};
class KwdIgnorePattern : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
IgnorePattern::action (words, use);
}
};
class KwdIncludeDirs : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Include::action (words, use);
}
};
class KwdIncludePath : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (words.size () > 1)
{
use->set_include_path (words[1]);
}
}
};
class KwdLanguage : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Language::action (words);
}
};
class KwdLibrary : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (use == &(Use::current ()))
{
Constituent::action (Library, words);
}
}
};
class KwdMacro : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandMacro, use);
}
};
class KwdMacroPrepend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandMacroPrepend, use);
}
};
class KwdMacroAppend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandMacroAppend, use);
}
};
class KwdMacroRemove : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandMacroRemove, use);
}
};
class KwdMacroRemoveAll : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandMacroRemoveAll, use);
}
};
class KwdMakeFragment : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Fragment::action (words, use);
}
};
class KwdManager : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
use->manager_action (words);
}
};
class KwdPackage : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
/*
if (words.size () > 1)
{
if (use == &(Use::current()))
{
m_current_package = words[1];
build_prefix (m_current_package, m_current_prefix);
if ((use->get_package_name () != "") &&
(use->get_package_name () != m_current_package))
{
if (!m_quiet)
{
// cout << "#CMT> package name mismatch in requirements of " <<
// use->get_package_name () << " " <<
// use->version << " line #" << line_number;
// cout << " : " << m_current_package << " versus " <<
// use->get_package_name () << endl;
}
}
use->set (m_current_package,
m_current_version,
m_current_path,
"",
"");
use->change_path (m_current_path);
use->style = m_current_style;
}
}
*/
}
};
class KwdPath : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandPath, use);
}
};
class KwdPathAppend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandPathAppend, use);
}
};
class KwdPathPrepend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandPathPrepend, use);
}
};
class KwdPathRemove : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandPathRemove, use);
}
};
class KwdPattern : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Pattern::action (words, use);
}
};
class KwdPrivate : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Cmt::set_scope (ScopePrivate);
}
};
class KwdProject : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Project::action (words, use);
}
};
class KwdPublic : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Cmt::set_scope (ScopePublic);
}
};
class KwdSet : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandSet, use);
}
};
class KwdSetAppend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandSetAppend, use);
}
};
class KwdSetPrepend : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandSetPrepend, use);
}
};
class KwdSetRemove : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Symbol::action (words, CommandSetRemove, use);
}
};
class KwdSetupScript : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Script::action (words, SetupScript, use);
Symbol::action (words, CommandSetupScript, use);
}
};
class KwdSetupStrategy : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
int strategy = Cmt::get_current_setup_strategy ();
for (int i = 1; i < words.size (); i++)
{
const cmt_string& w = words[i];
if (w == "config")
{
strategy |= SetupConfig;
}
else if (w == "no_config")
{
strategy |= SetupNoConfig;
}
else if (w == "root")
{
strategy |= SetupRoot;
}
else if (w == "no_root")
{
strategy |= SetupNoRoot;
}
else if (w == "cleanup")
{
strategy |= SetupCleanup;
}
else if (w == "no_cleanup")
{
strategy |= SetupNoCleanup;
}
if ((Cmt::get_action () == action_show_strategies) && !Cmt::get_quiet ())
{
cout << "# Package " << use->get_package_name ()
<< " adds " << w << " to setup strategy" << endl;
}
}
Cmt::set_current_setup_strategy (strategy);
}
};
class KwdTag : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Tag::action (words, use);
}
};
class KwdTagExclude : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Tag::action_exclude (words, use);
}
};
class KwdUse : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
Use::action (words, use);
}
};
class KwdVersionStrategy : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
if (words.size () > 1)
{
const cmt_string& w = words[1];
if (w == "best_fit")
{
Cmt::set_current_strategy (BestFit);
}
else if (w == "best_fit_no_check")
{
Cmt::set_current_strategy (BestFitNoCheck);
}
else if (w == "first_choice")
{
Cmt::set_current_strategy (FirstChoice);
}
else if (w == "last_choice")
{
Cmt::set_current_strategy (LastChoice);
}
else if (w == "keep_all")
{
Cmt::set_current_strategy (KeepAll);
}
if ((Cmt::get_action () == action_show_strategies) && !Cmt::get_quiet ())
{
cout << "# Package " << use->get_package_name () <<
" sets version strategy to " << w << endl;
}
}
}
};
class KwdVersion : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
}
};
class KwdDefault : public Kwd
{
public:
void action (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
/*
Unknown keyword : just ignore the line
*/
if (!Cmt::get_quiet ())
{
cout << "#CMT> bad syntax in requirements of " << use->get_package_name ()
<< " " << use->version << " line #" << line_number;
cout << " [" << words[0] << "...]" << endl;
}
CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
}
};
SyntaxParser& SyntaxParser::instance ()
{
static SyntaxParser p;
return (p);
}
/**
* Parse the input file, rejecting comments and
* rebuilding complete lines (from sections separated by
* \ characters.
*
* Each reformatted line is parsed by filter_line
*/
void SyntaxParser::parse_requirements (const cmt_string& file_name, Use* use)
{
SyntaxParser& me = instance ();
me.do_parse_requirements (file_name, use);
}
/**
* Parse a text, rejecting comments and
* rebuilding complete lines (from sections separated by
* \ characters.
*
* Each reformatted line is parsed by filter_line
*/
void SyntaxParser::parse_requirements_text (const cmt_string& text,
const cmt_string& file_name,
Use* use)
{
SyntaxParser& me = instance ();
/**
*
* We have to preserve m_current_access since it reflects whether
* the current cmt action is run in the context of the current package.
* (the opposite is when the cmt command specifies the current package
* in its arguments -use=... therefore the pwd is NOT the directory
* of the current package)
*
* m_current_access is Developer when pwd = current
* User when pwd != current
*
* Therefore, as soon as we reach a used package, this must be switched to User
*
* On the other hand, Cmt::scope reflects the status of the public/private
* statements. By default, we are in public context when entering a new requirements
* file.
*
*/
AccessMode saved_current_access;
ScopeType saved_scope;
saved_current_access = Cmt::get_current_access ();
saved_scope = Cmt::get_scope ();
if (use == 0) use = &(Use::current ());
if (use != &(Use::current ()))
{
Cmt::set_current_access (UserMode);
}
else
{
Cmt::set_current_access (DeveloperMode);
}
Cmt::set_scope (ScopePublic);
me.do_parse_requirements_text (text, file_name, use);
Cmt::set_current_access (saved_current_access);
Cmt::set_scope (saved_scope);
}
/**
* Apply the basic parser to one single line :
*
* o Append to global text if previous back_slash
* o Split into words
* o Apply the generic Select operator
*/
void SyntaxParser::parse_requirements_line (const cmt_string& line,
Use* use,
const cmt_string& file_name,
int line_number)
{
SyntaxParser& me = instance ();
me.do_parse_requirements_line (line, use, file_name, line_number);
}
void SyntaxParser::parse (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
SyntaxParser& me = instance ();
me.do_parse (words, use, file_name, line_number);
}
SyntaxParser::SyntaxParser ()
{
m_keywords.add ("alias", new KwdAlias ());
m_keywords.add ("application", new KwdApplication ());
m_keywords.add ("apply_pattern", new KwdApplyPattern ());
m_keywords.add ("apply_tag", new KwdApplyTag ());
m_keywords.add ("author", new KwdAuthor ());
m_keywords.add ("branches", new KwdBranches ());
m_keywords.add ("build_strategy", new KwdBuildStrategy ());
m_keywords.add ("cleanup_script", new KwdCleanupScript ());
m_keywords.add ("cmtpath_pattern", new KwdCmtPathPattern ());
m_keywords.add ("document", new KwdDocument ());
m_keywords.add ("ignore_pattern", new KwdIgnorePattern ());
m_keywords.add ("include_dirs", new KwdIncludeDirs ());
m_keywords.add ("include_path", new KwdIncludePath ());
m_keywords.add ("language", new KwdLanguage ());
m_keywords.add ("library", new KwdLibrary ());
m_keywords.add ("macro", new KwdMacro ());
m_keywords.add ("macro+", new KwdMacroAppend ());
m_keywords.add ("macro_prepend", new KwdMacroPrepend ());
m_keywords.add ("macro_append", new KwdMacroAppend ());
m_keywords.add ("macro_remove", new KwdMacroRemove ());
m_keywords.add ("macro_remove_all", new KwdMacroRemoveAll ());
m_keywords.add ("make_fragment", new KwdMakeFragment ());
m_keywords.add ("manager", new KwdManager ());
m_keywords.add ("package", new KwdPackage ());
m_keywords.add ("path", new KwdPath ());
m_keywords.add ("path_append", new KwdPathAppend ());
m_keywords.add ("path_prepend", new KwdPathPrepend ());
m_keywords.add ("path_remove", new KwdPathRemove ());
m_keywords.add ("pattern", new KwdPattern ());
m_keywords.add ("public", new KwdPublic ());
m_keywords.add ("private", new KwdPrivate ());
m_keywords.add ("project", new KwdProject ());
m_keywords.add ("set", new KwdSet ());
m_keywords.add ("set_append", new KwdSetAppend ());
m_keywords.add ("set_prepend", new KwdSetPrepend ());
m_keywords.add ("set_remove", new KwdSetRemove ());
m_keywords.add ("setup_script", new KwdSetupScript ());
m_keywords.add ("setup_strategy", new KwdSetupStrategy ());
m_keywords.add ("tag", new KwdTag ());
m_keywords.add ("tag_exclude", new KwdTagExclude ());
m_keywords.add ("use", new KwdUse ());
m_keywords.add ("version_strategy", new KwdVersionStrategy ());
m_keywords.add ("version", new KwdVersion ());
}
void SyntaxParser::do_parse (const CmtSystem::cmt_string_vector& words,
Use* use,
const cmt_string& file_name,
int line_number)
{
CmtError::clear ();
if (words.size () == 0) return;
const cmt_string& command = words[0];
if (command.size () == 0) return;
//
// First analyze the syntax
//
Kwd* keyword = m_keywords.find (command);
if (keyword == 0)
{
CmtError::set (CmtError::syntax_error, "ParseRequirements> ");
}
if (CmtError::has_pending_error ())
{
if (!Cmt::get_quiet ())
{
cout << "#CMT> bad syntax in requirements of " << use->get_package_name ()
<< " " << use->version
<< " " << use->specified_path
<< " line #" << line_number;
cout << " [" << command << " ...]" << endl;
}
return;
}
//
// Then interpret the action
//
keyword->action (words, use, file_name, line_number);
}
void SyntaxParser::do_parse_requirements (const cmt_string& file_name, Use* use)
{
cmt_string actual_file_name = file_name;
cmt_string text;
CmtError::clear ();
if (!CmtSystem::test_file (actual_file_name))
{
actual_file_name = "..";
actual_file_name += CmtSystem::file_separator ();
actual_file_name += "cmt";
actual_file_name += CmtSystem::file_separator ();
actual_file_name += file_name;
if (!CmtSystem::test_file (actual_file_name))
{
actual_file_name = "..";
actual_file_name += CmtSystem::file_separator ();
actual_file_name += "mgr";
actual_file_name += CmtSystem::file_separator ();
actual_file_name += file_name;
if (!CmtSystem::test_file (actual_file_name))
{
return;
}
}
}
text.read (actual_file_name);
SyntaxParser::parse_requirements_text (text, actual_file_name, use);
//Pattern::apply_all_globals (use);
}
void SyntaxParser::do_parse_requirements_line (const cmt_string& line,
Use* use,
const cmt_string& file_name,
int line_number)
{
int length;
int nl;
int back_slash;
cmt_string temp_line = line;
if (temp_line.size () == 0) return;
if (temp_line[0] == '#') return;
nl = temp_line.find_last_of ('\n');
if (nl != cmt_string::npos) temp_line.erase (nl);
length = temp_line.size ();
if (length == 0) return;
//
// We scan the line for handling backslashes.
//
// o Really terminating backslashes (ie those only followed by spaces/tabs
// mean continued line
//
//
bool finished = true;
length = temp_line.size ();
back_slash = temp_line.find_last_of ('\\');
if (back_slash != cmt_string::npos)
{
//
// This is the last backslash
// check if there are only space chars after it
//
bool at_end = true;
for (int i = (back_slash + 1); i < length; i++)
{
char c = temp_line[i];
if ((c != ' ') && (c != '\t'))
{
at_end = false;
break;
}
}
if (at_end)
{
temp_line.erase (back_slash);
finished = false;
}
else
{
// This was not a trailing backslash.
finished = true;
}
}
m_filtered_text += temp_line;
if (!finished)
{
// We still need to accumulate forthcoming lines
// before parsing the resulting text.
return;
}
/*
Here a full line (possibly accumulating several lines
ended by backslashes) is parsed :
o Special characters are filtered now :
: