cmXCodeObject.cxx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmXCodeObject.h"
  4. #include <CoreFoundation/CoreFoundation.h>
  5. #include <ostream>
  6. #include "cmSystemTools.h"
  7. const char* cmXCodeObject::PBXTypeNames[] = {
  8. /* clang-format needs this comment to break after the opening brace */
  9. "PBXGroup",
  10. "PBXBuildStyle",
  11. "PBXProject",
  12. "PBXHeadersBuildPhase",
  13. "PBXSourcesBuildPhase",
  14. "PBXFrameworksBuildPhase",
  15. "PBXNativeTarget",
  16. "PBXFileReference",
  17. "PBXBuildFile",
  18. "PBXContainerItemProxy",
  19. "PBXTargetDependency",
  20. "PBXShellScriptBuildPhase",
  21. "PBXResourcesBuildPhase",
  22. "PBXApplicationReference",
  23. "PBXExecutableFileReference",
  24. "PBXLibraryReference",
  25. "PBXToolTarget",
  26. "PBXLibraryTarget",
  27. "PBXAggregateTarget",
  28. "XCBuildConfiguration",
  29. "XCConfigurationList",
  30. "PBXCopyFilesBuildPhase",
  31. "None"
  32. };
  33. cmXCodeObject::~cmXCodeObject()
  34. {
  35. this->Version = 15;
  36. }
  37. cmXCodeObject::cmXCodeObject(PBXType ptype, Type type)
  38. {
  39. this->Version = 15;
  40. this->Target = 0;
  41. this->Object = 0;
  42. this->IsA = ptype;
  43. if (type == OBJECT) {
  44. // Set the Id of an Xcode object to a unique string for each instance.
  45. // However the Xcode user file references certain Ids: for those cases,
  46. // override the generated Id using SetId().
  47. //
  48. char cUuid[40] = { 0 };
  49. CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
  50. CFStringRef s = CFUUIDCreateString(kCFAllocatorDefault, uuid);
  51. CFStringGetCString(s, cUuid, sizeof(cUuid), kCFStringEncodingUTF8);
  52. this->Id = cUuid;
  53. CFRelease(s);
  54. CFRelease(uuid);
  55. } else {
  56. this->Id =
  57. "Temporary cmake object, should not be referred to in Xcode file";
  58. }
  59. cmSystemTools::ReplaceString(this->Id, "-", "");
  60. if (this->Id.size() > 24) {
  61. this->Id = this->Id.substr(0, 24);
  62. }
  63. this->TypeValue = type;
  64. if (this->TypeValue == OBJECT) {
  65. this->AddAttribute("isa", 0);
  66. }
  67. }
  68. bool cmXCodeObject::IsEmpty() const
  69. {
  70. switch (this->TypeValue) {
  71. case OBJECT_LIST:
  72. return this->List.empty();
  73. case STRING:
  74. return this->String.empty();
  75. case ATTRIBUTE_GROUP:
  76. return this->ObjectAttributes.empty();
  77. case OBJECT_REF:
  78. case OBJECT:
  79. return this->Object == 0;
  80. }
  81. return true; // unreachable, but quiets warnings
  82. }
  83. void cmXCodeObject::Indent(int level, std::ostream& out)
  84. {
  85. while (level) {
  86. out << "\t";
  87. level--;
  88. }
  89. }
  90. void cmXCodeObject::Print(std::ostream& out)
  91. {
  92. std::string separator = "\n";
  93. int indentFactor = 1;
  94. cmXCodeObject::Indent(2 * indentFactor, out);
  95. if (this->Version > 15 &&
  96. (this->IsA == PBXFileReference || this->IsA == PBXBuildFile)) {
  97. separator = " ";
  98. indentFactor = 0;
  99. }
  100. out << this->Id;
  101. this->PrintComment(out);
  102. out << " = {";
  103. if (separator == "\n") {
  104. out << separator;
  105. }
  106. std::map<std::string, cmXCodeObject*>::iterator i;
  107. cmXCodeObject::Indent(3 * indentFactor, out);
  108. out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator;
  109. for (i = this->ObjectAttributes.begin(); i != this->ObjectAttributes.end();
  110. ++i) {
  111. if (i->first == "isa")
  112. continue;
  113. PrintAttribute(out, 3, separator, indentFactor, i->first, i->second, this);
  114. }
  115. cmXCodeObject::Indent(2 * indentFactor, out);
  116. out << "};\n";
  117. }
  118. void cmXCodeObject::PrintAttribute(std::ostream& out, const int level,
  119. const std::string separator,
  120. const int factor, const std::string& name,
  121. const cmXCodeObject* object,
  122. const cmXCodeObject* parent)
  123. {
  124. cmXCodeObject::Indent(level * factor, out);
  125. switch (object->TypeValue) {
  126. case OBJECT_LIST: {
  127. out << name << " = (";
  128. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  129. out << separator;
  130. }
  131. for (unsigned int i = 0; i < object->List.size(); ++i) {
  132. if (object->List[i]->TypeValue == STRING) {
  133. object->List[i]->PrintString(out);
  134. if (i + 1 < object->List.size()) {
  135. out << ",";
  136. }
  137. } else {
  138. cmXCodeObject::Indent((level + 1) * factor, out);
  139. out << object->List[i]->Id;
  140. object->List[i]->PrintComment(out);
  141. out << "," << separator;
  142. }
  143. }
  144. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  145. cmXCodeObject::Indent(level * factor, out);
  146. }
  147. out << ");" << separator;
  148. } break;
  149. case ATTRIBUTE_GROUP: {
  150. out << name << " = {";
  151. if (separator == "\n") {
  152. out << separator;
  153. }
  154. std::map<std::string, cmXCodeObject*>::const_iterator i;
  155. for (i = object->ObjectAttributes.begin();
  156. i != object->ObjectAttributes.end(); ++i) {
  157. PrintAttribute(out, (level + 1) * factor, separator, factor, i->first,
  158. i->second, object);
  159. }
  160. cmXCodeObject::Indent(level * factor, out);
  161. out << "};" << separator;
  162. } break;
  163. case OBJECT_REF: {
  164. cmXCodeObject::PrintString(out, name);
  165. out << " = " << object->Object->Id;
  166. if (object->Object->HasComment() && name != "remoteGlobalIDString") {
  167. object->Object->PrintComment(out);
  168. }
  169. out << ";" << separator;
  170. } break;
  171. case STRING: {
  172. cmXCodeObject::PrintString(out, name);
  173. out << " = ";
  174. object->PrintString(out);
  175. out << ";" << separator;
  176. } break;
  177. default: {
  178. break;
  179. }
  180. }
  181. }
  182. void cmXCodeObject::PrintList(std::vector<cmXCodeObject*> const& objs,
  183. std::ostream& out)
  184. {
  185. cmXCodeObject::Indent(1, out);
  186. out << "objects = {\n";
  187. for (unsigned int i = 0; i < objs.size(); ++i) {
  188. if (objs[i]->TypeValue == OBJECT) {
  189. objs[i]->Print(out);
  190. }
  191. }
  192. cmXCodeObject::Indent(1, out);
  193. out << "};\n";
  194. }
  195. void cmXCodeObject::CopyAttributes(cmXCodeObject* copy)
  196. {
  197. this->ObjectAttributes = copy->ObjectAttributes;
  198. this->List = copy->List;
  199. this->String = copy->String;
  200. this->Object = copy->Object;
  201. }
  202. void cmXCodeObject::PrintString(std::ostream& os, std::string String)
  203. {
  204. // The string needs to be quoted if it contains any characters
  205. // considered special by the Xcode project file parser.
  206. bool needQuote = (String.empty() || String.find("//") != std::string::npos ||
  207. String.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  208. "abcdefghijklmnopqrstuvwxyz"
  209. "0123456789"
  210. "$_./") != std::string::npos);
  211. const char* quote = needQuote ? "\"" : "";
  212. // Print the string, quoted and escaped as necessary.
  213. os << quote;
  214. for (std::string::const_iterator i = String.begin(); i != String.end();
  215. ++i) {
  216. if (*i == '"' || *i == '\\') {
  217. // Escape double-quotes and backslashes.
  218. os << '\\';
  219. }
  220. os << *i;
  221. }
  222. os << quote;
  223. }
  224. void cmXCodeObject::PrintString(std::ostream& os) const
  225. {
  226. cmXCodeObject::PrintString(os, this->String);
  227. }
  228. void cmXCodeObject::SetString(const std::string& s)
  229. {
  230. this->String = s;
  231. }