cmXCodeObject.cxx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 <cmext/string_view>
  6. char const* cmXCodeObject::PBXTypeNames[] = {
  7. /* clang-format needs this comment to break after the opening brace */
  8. "PBXGroup",
  9. "PBXBuildStyle",
  10. "PBXProject",
  11. "PBXHeadersBuildPhase",
  12. "PBXSourcesBuildPhase",
  13. "PBXFrameworksBuildPhase",
  14. "PBXNativeTarget",
  15. "PBXFileReference",
  16. "PBXBuildFile",
  17. "PBXContainerItemProxy",
  18. "PBXTargetDependency",
  19. "PBXShellScriptBuildPhase",
  20. "PBXResourcesBuildPhase",
  21. "PBXApplicationReference",
  22. "PBXExecutableFileReference",
  23. "PBXLibraryReference",
  24. "PBXToolTarget",
  25. "PBXLibraryTarget",
  26. "PBXAggregateTarget",
  27. "XCBuildConfiguration",
  28. "XCConfigurationList",
  29. "PBXCopyFilesBuildPhase",
  30. "None"
  31. };
  32. cmXCodeObject::~cmXCodeObject()
  33. {
  34. this->Version = 15;
  35. }
  36. cmXCodeObject::cmXCodeObject(PBXType ptype, Type type, std::string id)
  37. {
  38. this->Version = 15;
  39. this->Target = nullptr;
  40. this->Object = nullptr;
  41. this->IsA = ptype;
  42. this->Id = std::move(id);
  43. this->TypeValue = type;
  44. if (this->TypeValue == OBJECT) {
  45. this->AddAttribute("isa", nullptr);
  46. }
  47. }
  48. bool cmXCodeObject::IsEmpty() const
  49. {
  50. switch (this->TypeValue) {
  51. case OBJECT_LIST:
  52. return this->List.empty();
  53. case STRING:
  54. return this->String.empty();
  55. case ATTRIBUTE_GROUP:
  56. return this->ObjectAttributes.empty();
  57. case OBJECT_REF:
  58. case OBJECT:
  59. return this->Object == nullptr;
  60. }
  61. return true; // unreachable, but quiets warnings
  62. }
  63. void cmXCodeObject::Indent(int level, std::ostream& out)
  64. {
  65. while (level) {
  66. out << "\t";
  67. level--;
  68. }
  69. }
  70. void cmXCodeObject::Print(std::ostream& out)
  71. {
  72. std::string separator = "\n";
  73. int indentFactor = 1;
  74. cmXCodeObject::Indent(2 * indentFactor, out);
  75. if (this->Version > 15 &&
  76. (this->IsA == PBXFileReference || this->IsA == PBXBuildFile)) {
  77. separator = " ";
  78. indentFactor = 0;
  79. }
  80. out << this->Id;
  81. this->PrintComment(out);
  82. out << " = {";
  83. if (separator == "\n"_s) {
  84. out << separator;
  85. }
  86. cmXCodeObject::Indent(3 * indentFactor, out);
  87. out << "isa = " << PBXTypeNames[this->IsA] << ";" << separator;
  88. for (auto const& keyVal : this->ObjectAttributes) {
  89. if (keyVal.first == "isa"_s) {
  90. continue;
  91. }
  92. PrintAttribute(out, 3, separator, indentFactor, keyVal.first,
  93. keyVal.second, this);
  94. }
  95. cmXCodeObject::Indent(2 * indentFactor, out);
  96. out << "};\n";
  97. }
  98. void cmXCodeObject::PrintAttribute(std::ostream& out, int level,
  99. std::string const& separator, int factor,
  100. std::string const& name,
  101. cmXCodeObject const* object,
  102. cmXCodeObject const* parent)
  103. {
  104. cmXCodeObject::Indent(level * factor, out);
  105. switch (object->TypeValue) {
  106. case OBJECT_LIST: {
  107. out << name << " = (";
  108. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  109. out << separator;
  110. }
  111. for (unsigned int i = 0; i < object->List.size(); ++i) {
  112. if (object->List[i]->TypeValue == STRING) {
  113. object->List[i]->PrintString(out);
  114. if (i + 1 < object->List.size()) {
  115. out << ",";
  116. }
  117. } else {
  118. cmXCodeObject::Indent((level + 1) * factor, out);
  119. out << object->List[i]->Id;
  120. object->List[i]->PrintComment(out);
  121. out << "," << separator;
  122. }
  123. }
  124. if (parent->TypeValue != ATTRIBUTE_GROUP) {
  125. cmXCodeObject::Indent(level * factor, out);
  126. }
  127. out << ");" << separator;
  128. } break;
  129. case ATTRIBUTE_GROUP: {
  130. out << name << " = {";
  131. if (separator == "\n"_s) {
  132. out << separator;
  133. }
  134. for (auto const& keyVal : object->ObjectAttributes) {
  135. PrintAttribute(out, (level + 1) * factor, separator, factor,
  136. keyVal.first, keyVal.second, object);
  137. }
  138. cmXCodeObject::Indent(level * factor, out);
  139. out << "};" << separator;
  140. } break;
  141. case OBJECT_REF: {
  142. cmXCodeObject::PrintString(out, name);
  143. out << " = " << object->Object->Id;
  144. if (object->Object->HasComment() && name != "remoteGlobalIDString"_s) {
  145. object->Object->PrintComment(out);
  146. }
  147. out << ";" << separator;
  148. } break;
  149. case STRING: {
  150. cmXCodeObject::PrintString(out, name);
  151. out << " = ";
  152. object->PrintString(out);
  153. out << ";" << separator;
  154. } break;
  155. default: {
  156. break;
  157. }
  158. }
  159. }
  160. void cmXCodeObject::PrintList(std::vector<cmXCodeObject*> const& objs,
  161. std::ostream& out)
  162. {
  163. cmXCodeObject::Indent(1, out);
  164. out << "objects = {\n";
  165. for (auto* obj : objs) {
  166. if (obj->TypeValue == OBJECT) {
  167. obj->Print(out);
  168. }
  169. }
  170. cmXCodeObject::Indent(1, out);
  171. out << "};\n";
  172. }
  173. void cmXCodeObject::CopyAttributes(cmXCodeObject* copy)
  174. {
  175. this->ObjectAttributes = copy->ObjectAttributes;
  176. this->List = copy->List;
  177. this->String = copy->String;
  178. this->Object = copy->Object;
  179. }
  180. void cmXCodeObject::PrintString(std::ostream& os, std::string const& String)
  181. {
  182. // The string needs to be quoted if it contains any characters
  183. // considered special by the Xcode project file parser.
  184. bool needQuote = (String.empty() || String.find("//") != std::string::npos ||
  185. String.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  186. "abcdefghijklmnopqrstuvwxyz"
  187. "0123456789"
  188. "$_./") != std::string::npos);
  189. char const* quote = needQuote ? "\"" : "";
  190. // Print the string, quoted and escaped as necessary.
  191. os << quote;
  192. for (auto c : String) {
  193. if (c == '"' || c == '\\') {
  194. // Escape double-quotes and backslashes.
  195. os << '\\';
  196. }
  197. os << c;
  198. }
  199. os << quote;
  200. }
  201. void cmXCodeObject::PrintString(std::ostream& os) const
  202. {
  203. cmXCodeObject::PrintString(os, this->String);
  204. }
  205. void cmXCodeObject::SetString(std::string const& s)
  206. {
  207. this->String = s;
  208. }