cmCableDefineSetCommand.cxx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*=========================================================================
  2. Program: Insight Segmentation & Registration Toolkit
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2000 National Library of Medicine
  8. All rights reserved.
  9. See COPYRIGHT.txt for copyright details.
  10. =========================================================================*/
  11. #include "cmCableDefineSetCommand.h"
  12. #include "cmCacheManager.h"
  13. #include "cmRegularExpression.h"
  14. // cmCableDefineSetCommand
  15. bool cmCableDefineSetCommand::Invoke(std::vector<std::string>& args)
  16. {
  17. if(args.size() < 2)
  18. {
  19. this->SetError("called with incorrect number of arguments");
  20. return false;
  21. }
  22. // This command needs access to the Cable data.
  23. this->SetupCableData();
  24. std::vector<std::string>::const_iterator arg = args.begin();
  25. // The first argument is the name of the set.
  26. m_SetName = *arg++;
  27. // All arguments until a "SOURCE_FILES" are the elements to be placed in
  28. // the set.
  29. for(; (arg != args.end()) && (*arg != "SOURCE_FILES"); ++arg)
  30. {
  31. // If the element cannot be added, return an error.
  32. // This can occur when a tag is not specified and can't be generated.
  33. if(!this->AddElement(*arg))
  34. { return false; }
  35. }
  36. // If we are not at the end, the "SOURCE_FILES" keyword has been
  37. // encountered.
  38. if(arg != args.end())
  39. {
  40. // The rest of the arguments are source files to be included in
  41. // any package which references the set.
  42. for(++arg; arg != args.end(); ++arg)
  43. {
  44. if(!this->AddSourceFile(*arg))
  45. { return false; }
  46. }
  47. }
  48. // Write this command's configuration output.
  49. this->WriteConfiguration();
  50. return true;
  51. }
  52. /**
  53. * Write the CABLE configuration code to define this Set.
  54. */
  55. void cmCableDefineSetCommand::WriteConfiguration() const
  56. {
  57. cmRegularExpression needCdataBlock("[&<>]");
  58. // Get the ouptut information from the cmCableData.
  59. std::ostream& os = m_CableData->GetOutputStream();
  60. cmCableData::Indentation indent = m_CableData->GetIndentation();
  61. // Output the code.
  62. os << indent << "<Set name=\"" << m_SetName.c_str() << "\">" << std::endl;
  63. for(std::vector<std::string>::const_iterator e = m_SourceHeaders.begin();
  64. e != m_SourceHeaders.end(); ++e)
  65. {
  66. os << indent << " <File name=\"" << e->c_str() << "\"/>" << std::endl;
  67. }
  68. for(std::vector<std::string>::const_iterator e = m_InstantiationSources.begin();
  69. e != m_InstantiationSources.end(); ++e)
  70. {
  71. os << indent << " <File name=\"" << e->c_str()
  72. << "\" purpose=\"instantiate\"/>" << std::endl;
  73. }
  74. for(Elements::const_iterator e = m_Elements.begin();
  75. e != m_Elements.end(); ++e)
  76. {
  77. os << indent << " <Element";
  78. // Only output the tag if it is not the empty string.
  79. if(e->first.length() > 0)
  80. {
  81. os << " tag=\"" << e->first.c_str() << "\"";
  82. }
  83. os << ">";
  84. if(needCdataBlock.find(e->second.c_str()))
  85. {
  86. os << "<![CDATA[" << e->second.c_str() << "]]>";
  87. }
  88. else
  89. {
  90. os << e->second.c_str();
  91. }
  92. os << "</Element>" << std::endl;
  93. }
  94. os << indent << "</Set>" << std::endl;
  95. }
  96. /**
  97. * Add an element to the set. The given string is the argument to the
  98. * command describing the element. There are two formats allowed:
  99. * "code" = The code describing the element to CABLE is simply given.
  100. * The GenerateTag() method will guess at a good tag for the
  101. * code.
  102. * "tag:code" = The left side of a single colon is text describing the tag.
  103. * GenerateTag() will not be called.
  104. */
  105. bool cmCableDefineSetCommand::AddElement(const std::string& arg)
  106. {
  107. // A regular expression to match the tagged element specification.
  108. cmRegularExpression tagGiven("^([A-Za-z_0-9]*)[ \t]*:[ \t]*([^:].*|::.*)$");
  109. std::string tag;
  110. std::string code;
  111. if(tagGiven.find(arg.c_str()))
  112. {
  113. // A tag was given. Use it.
  114. tag = tagGiven.match(1);
  115. code = tagGiven.match(2);
  116. }
  117. else
  118. {
  119. // No tag was given. Try to generate one.
  120. if(!this->GenerateTag(arg, tag))
  121. { return false; }
  122. code = arg;
  123. }
  124. // Add an element with the given tag and code.
  125. m_Elements.push_back(Element(tag, code));
  126. return true;
  127. }
  128. /**
  129. * Given the string representing a set element, automatically generate
  130. * the CABLE element tag for it.
  131. *
  132. * **This function determines how the output language of all
  133. * CABLE-generated wrappers will look!**
  134. */
  135. bool
  136. cmCableDefineSetCommand::GenerateTag(const std::string& element,
  137. std::string& tag)
  138. {
  139. // Hold the regular expressions for matching against the element.
  140. cmRegularExpression regex;
  141. // If the element's code begins in a $, it is referring to a set name.
  142. // The set's elements have their own tags, so we don't need one.
  143. regex.compile("^[ \t]*\\$");
  144. if(regex.find(element))
  145. { tag = ""; return true; }
  146. // Test for simple integer
  147. regex.compile("^[ \t]*([0-9]*)[ \t]*$");
  148. if(regex.find(element))
  149. {
  150. tag = "_";
  151. tag.append(regex.match(1));
  152. return true;
  153. }
  154. // Test for basic integer type
  155. regex.compile("^[ \t]*(unsigned[ ]|signed[ ])?[ \t]*(char|short|int|long|long[ ]long)[ \t]*$");
  156. if(regex.find(element))
  157. {
  158. tag = "_";
  159. if(regex.match(1) == "unsigned ")
  160. { tag.append("u"); }
  161. if(regex.match(2) == "long long")
  162. { tag.append("llong"); }
  163. else
  164. { tag.append(regex.match(2)); }
  165. return true;
  166. }
  167. // Test for basic floating-point type
  168. regex.compile("^[ \t]*(long[ ])?[ \t]*(float|double)[ \t]*$");
  169. if(regex.find(element))
  170. {
  171. tag = "_";
  172. if(regex.match(1) == "long ")
  173. tag.append("l");
  174. tag.append(regex.match(2));
  175. return true;
  176. }
  177. // Test for basic wide-character type
  178. regex.compile("^[ \t]*(wchar_t)[ \t]*$");
  179. if(regex.find(element))
  180. {
  181. tag = "_wchar";
  182. return true;
  183. }
  184. // Test for plain type name (without template arguments).
  185. regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*$");
  186. if(regex.find(element))
  187. {
  188. // The tag is the same as the type.
  189. tag = regex.match(1);
  190. return true;
  191. }
  192. // Test for template class instance.
  193. regex.compile("^[ \t]*([A-Za-z_][A-Za-z0-9_]*)<.*[ \t]*$");
  194. if(regex.find(element))
  195. {
  196. // The tag is the type without arguments (the arguments may have
  197. // their own tags).
  198. tag = regex.match(1);
  199. return true;
  200. }
  201. // We can't generate a tag.
  202. std::string err =
  203. ("doesn't know how to generate tag for element \""+element+"\" in set \""
  204. +m_SetName+"\"\nPlease specify one with the \"tag:element\" syntax.");
  205. this->SetError(err.c_str());
  206. tag = "";
  207. return false;
  208. }
  209. /**
  210. * Add a source file associated with this set. Any package referencing
  211. * this set will automatically include this source file.
  212. */
  213. bool cmCableDefineSetCommand::AddSourceFile(const std::string& file)
  214. {
  215. // We must locate the file in the include path so that we can detect
  216. // its extension, and whether there is more than one to find.
  217. std::string header = file+".h";
  218. std::string txx = file+".txx";
  219. m_Makefile->ExpandVariablesInString(header);
  220. m_Makefile->ExpandVariablesInString(txx);
  221. // See if the file just exists here. The compiler's search path will
  222. // locate it.
  223. if(cmSystemTools::FileExists(header.c_str()))
  224. {
  225. m_SourceHeaders.push_back(header);
  226. // See if there is a matching .txx as well.
  227. if(cmSystemTools::FileExists(txx.c_str()))
  228. {
  229. m_InstantiationSources.push_back(txx);
  230. }
  231. return true;
  232. }
  233. // We must look for the file in the include search path.
  234. const std::vector<std::string>& includeDirectories =
  235. m_Makefile->GetIncludeDirectories();
  236. for(std::vector<std::string>::const_iterator dir = includeDirectories.begin();
  237. dir != includeDirectories.end(); ++dir)
  238. {
  239. std::string path = *dir + "/";
  240. m_Makefile->ExpandVariablesInString(path);
  241. if(cmSystemTools::FileExists((path+header).c_str()))
  242. {
  243. m_SourceHeaders.push_back(header);
  244. // See if there is a matching .txx as well.
  245. if(cmSystemTools::FileExists((path+txx).c_str()))
  246. {
  247. m_InstantiationSources.push_back(txx);
  248. }
  249. return true;
  250. }
  251. }
  252. // We couldn't locate the source file. Report the error.
  253. std::string err = "couldn't find source file " + header;
  254. this->SetError(err.c_str());
  255. return false;
  256. }