1
0

cmXCodeObject.cxx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file LICENSE.rst or https://cmake.org/licensing for details. */
  3. #include "cmXCodeObject.h"
  4. #include <ostream>
  5. #include <cm/string_view>
  6. #include <cmext/string_view>
  7. char const* 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, std::string id)
  38. {
  39. this->Version = 15;
  40. this->Target = nullptr;
  41. this->Object = nullptr;
  42. this->IsA = ptype;
  43. this->Id = std::move(id);
  44. this->TypeValue = type;
  45. if (this->TypeValue == OBJECT) {
  46. this->AddAttribute("isa", nullptr);
  47. }
  48. }
  49. bool cmXCodeObject::IsEmpty() const
  50. {
  51. switch (this->TypeValue) {
  52. case OBJECT_LIST:
  53. return this->List.empty();
  54. case STRING:
  55. return this->String.empty();
  56. case ATTRIBUTE_GROUP:
  57. return this->ObjectAttributes.empty();
  58. case OBJECT_REF:
  59. case OBJECT:
  60. return this->Object == nullptr;
  61. }
  62. return true; // unreachable, but quiets warnings
  63. }
  64. void cmXCodeObject::Indent(int level, std::ostream& out)
  65. {
  66. while (level) {
  67. out << "\t";
  68. level--;
  69. }
  70. }
  71. void cmXCodeObject::Print(std::ostream& out)
  72. {
  73. std::string separator = "\n";
  74. int indentFactor = 1;
  75. cmXCodeObject::Indent(2 * indentFactor, out);
  76. if (this->Version > 15 &&
  77. (this->IsA == PBXFileReference || this->IsA == PBXBuildFile)) {
  78. separator = " ";
  79. indentFactor = 0;
  80. }
  81. out << this->Id;
  82. this->PrintComment(out);
  83. out << " = {";
  84. if (separator == "\n"_s) {
  85. out << separator;
  86. }
  87. cmXCodeObject::Indent(3 * indentFactor, out);
  88. out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator;
  89. for (auto const& keyVal : this->ObjectAttributes) {
  90. if (keyVal.first == "isa"_s) {
  91. continue;
  92. }
  93. PrintAttribute(out, 3, separator, indentFactor, keyVal.first,
  94. keyVal.second, this);
  95. }
  96. cmXCodeObject::Indent(2 * indentFactor, out);
  97. out << "};\n";
  98. }
  99. void cmXCodeObject::PrintAttribute(std::ostream& out, int level,
  100. std::string const& separator, int factor,
  101. std::string const& name,
  102. cmXCodeObject const* object,
  103. cmXCodeObject const* parent)
  104. {
  105. cmXCodeObject::Indent(level * factor, out);
  106. switch (object->TypeValue) {
  107. case OBJECT_LIST: {
  108. out << name << " = (";
  109. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  110. out << separator;
  111. }
  112. for (unsigned int i = 0; i < object->List.size(); ++i) {
  113. if (object->List[i]->TypeValue == STRING) {
  114. object->List[i]->PrintString(out);
  115. if (i + 1 < object->List.size()) {
  116. out << ",";
  117. }
  118. } else {
  119. cmXCodeObject::Indent((level + 1) * factor, out);
  120. out << object->List[i]->Id;
  121. object->List[i]->PrintComment(out);
  122. out << "," << separator;
  123. }
  124. }
  125. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  126. cmXCodeObject::Indent(level * factor, out);
  127. }
  128. out << ");" << separator;
  129. } break;
  130. case ATTRIBUTE_GROUP: {
  131. out << name << " = {";
  132. if (separator == "\n"_s) {
  133. out << separator;
  134. }
  135. for (auto const& keyVal : object->ObjectAttributes) {
  136. PrintAttribute(out, (level + 1) * factor, separator, factor,
  137. keyVal.first, keyVal.second, object);
  138. }
  139. cmXCodeObject::Indent(level * factor, out);
  140. out << "};" << separator;
  141. } break;
  142. case OBJECT_REF: {
  143. cmXCodeObject::PrintString(out, name);
  144. out << " = " << object->Object->Id;
  145. if (object->Object->HasComment() && name != "remoteGlobalIDString"_s) {
  146. object->Object->PrintComment(out);
  147. }
  148. out << ";" << separator;
  149. } break;
  150. case STRING: {
  151. cmXCodeObject::PrintString(out, name);
  152. out << " = ";
  153. object->PrintString(out);
  154. out << ";" << separator;
  155. } break;
  156. default: {
  157. break;
  158. }
  159. }
  160. }
  161. void cmXCodeObject::PrintList(std::vector<cmXCodeObject*> const& objs,
  162. std::ostream& out)
  163. {
  164. cmXCodeObject::Indent(1, out);
  165. out << "objects = {\n";
  166. for (auto* obj : objs) {
  167. if (obj->TypeValue == OBJECT) {
  168. obj->Print(out);
  169. }
  170. }
  171. cmXCodeObject::Indent(1, out);
  172. out << "};\n";
  173. }
  174. void cmXCodeObject::CopyAttributes(cmXCodeObject* copy)
  175. {
  176. this->ObjectAttributes = copy->ObjectAttributes;
  177. this->List = copy->List;
  178. this->String = copy->String;
  179. this->Object = copy->Object;
  180. }
  181. void cmXCodeObject::PrintString(std::ostream& os, std::string const& String)
  182. {
  183. // The string needs to be quoted if it contains any characters
  184. // considered special by the Xcode project file parser.
  185. bool needQuote = (String.empty() || String.find("//") != std::string::npos ||
  186. String.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  187. "abcdefghijklmnopqrstuvwxyz"
  188. "0123456789"
  189. "$_./") != std::string::npos);
  190. char const* quote = needQuote ? "\"" : "";
  191. // Print the string, quoted and escaped as necessary.
  192. os << quote;
  193. for (auto c : String) {
  194. if (c == '"' || c == '\\') {
  195. // Escape double-quotes and backslashes.
  196. os << '\\';
  197. }
  198. os << c;
  199. }
  200. os << quote;
  201. }
  202. void cmXCodeObject::PrintString(std::ostream& os) const
  203. {
  204. cmXCodeObject::PrintString(os, this->String);
  205. }
  206. void cmXCodeObject::SetString(cm::string_view s)
  207. {
  208. this->String = std::string(s);
  209. }