PageRenderTime 61ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/bindings/smoke/smokeapi/main.cpp

https://github.com/0xd34df00d/Qross
C++ | 315 lines | 242 code | 54 blank | 19 comment | 104 complexity | 3331d16ec9baa802eee0b10912a1be6c MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, BSD-3-Clause, LGPL-2.1
  1. /*
  2. Command line introspection tool for SMOKE libs
  3. Copyright (C) 2010 Arno Rehn <arno@arnorehn.de>
  4. Copyright (C) 2010 Richard Dale <richard.j.dale@gmail.com>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include <QtCore>
  18. #include <QtDebug>
  19. #include <smoke.h>
  20. #include <qtcore_smoke.h>
  21. static QTextStream qOut(stdout);
  22. typedef void (*InitSmokeFn)();
  23. typedef QPair<Smoke::ModuleIndex,int> ClassEntry;
  24. static QList<Smoke*> smokeModules;
  25. static bool showClassNamesOnly;
  26. static bool showParents;
  27. static bool matchPattern;
  28. static bool caseInsensitive;
  29. static QRegExp targetPattern;
  30. static Smoke*
  31. loadSmokeModule(QString moduleName) {
  32. QFileInfo file(QString("libsmoke") + moduleName);
  33. QLibrary lib(file.filePath());
  34. if (moduleName == "qtcore") {
  35. init_qtcore_Smoke();
  36. return qtcore_Smoke;
  37. }
  38. QString init_name = "init_" + moduleName + "_Smoke";
  39. InitSmokeFn init = (InitSmokeFn) lib.resolve(init_name.toLatin1());
  40. if (!init)
  41. qFatal("Couldn't resolve %s: %s", qPrintable(init_name), qPrintable(lib.errorString()));
  42. (*init)();
  43. QString smoke_name = moduleName + "_Smoke";
  44. Smoke** smoke = (Smoke**) lib.resolve(smoke_name.toLatin1());
  45. if (!smoke)
  46. qFatal("Couldn't resolve %s: %s", qPrintable(smoke_name), qPrintable(lib.errorString()));
  47. return *smoke;
  48. }
  49. static QString
  50. methodToString(Smoke::ModuleIndex methodId)
  51. {
  52. QString result;
  53. Smoke * smoke = methodId.smoke;
  54. Smoke::Method& methodRef = smoke->methods[methodId.index];
  55. if ((methodRef.flags & Smoke::mf_signal) != 0) {
  56. result.append("signal ");
  57. }
  58. if ((methodRef.flags & Smoke::mf_slot) != 0) {
  59. result.append("slot ");
  60. }
  61. const char * typeName = smoke->types[methodRef.ret].name;
  62. if ((methodRef.flags & Smoke::mf_enum) != 0) {
  63. result.append(QString("enum %1::%2")
  64. .arg(smoke->classes[methodRef.classId].className)
  65. .arg(smoke->methodNames[methodRef.name]) );
  66. return result;
  67. }
  68. if ((methodRef.flags & Smoke::mf_virtual) != 0) {
  69. result.append("virtual ");
  70. }
  71. if ( (methodRef.flags & Smoke::mf_static) != 0
  72. && (smoke->classes[methodRef.classId].flags & Smoke::cf_namespace) == 0 )
  73. {
  74. result.append("static ");
  75. }
  76. if ((methodRef.flags & Smoke::mf_ctor) == 0) {
  77. result.append((typeName != 0 ? typeName : "void"));
  78. result.append(" ");
  79. }
  80. result.append( QString("%1::%2(")
  81. .arg(smoke->classes[methodRef.classId].className)
  82. .arg(smoke->methodNames[methodRef.name]) );
  83. for (int i = 0; i < methodRef.numArgs; i++) {
  84. if (i > 0) {
  85. result.append(", ");
  86. }
  87. typeName = smoke->types[smoke->argumentList[methodRef.args+i]].name;
  88. result.append((typeName != 0 ? typeName : "void"));
  89. }
  90. result.append(")");
  91. if ((methodRef.flags & Smoke::mf_const) != 0) {
  92. result.append(" const");
  93. }
  94. if ((methodRef.flags & Smoke::mf_purevirtual) != 0) {
  95. result.append(" = 0");
  96. }
  97. return result;
  98. }
  99. static QList<ClassEntry>
  100. getAllParents(const Smoke::ModuleIndex& classId, int indent)
  101. {
  102. Smoke* smoke = classId.smoke;
  103. QList<ClassEntry> result;
  104. for ( Smoke::Index * parent = smoke->inheritanceList + smoke->classes[classId.index].parents;
  105. *parent != 0;
  106. parent++ )
  107. {
  108. Smoke::ModuleIndex parentId = Smoke::findClass(smoke->classes[*parent].className);
  109. Q_ASSERT(parentId != Smoke::NullModuleIndex);
  110. result << getAllParents(parentId, indent + 1);
  111. }
  112. result << ClassEntry(classId, indent);
  113. return result;
  114. }
  115. static void
  116. showClass(const Smoke::ModuleIndex& classId, int indent)
  117. {
  118. if (showClassNamesOnly) {
  119. QString className = QString::fromLatin1(classId.smoke->classes[classId.index].className);
  120. if (!matchPattern || targetPattern.indexIn(className) != -1) {
  121. while (indent > 0) {
  122. qOut << " ";
  123. indent--;
  124. }
  125. qOut << className << "\n";
  126. }
  127. return;
  128. }
  129. Smoke * smoke = classId.smoke;
  130. Smoke::Index imax = smoke->numMethodMaps;
  131. Smoke::Index imin = 0, icur = -1, methmin, methmax;
  132. methmin = -1; methmax = -1; // kill warnings
  133. int icmp = -1;
  134. while (imax >= imin) {
  135. icur = (imin + imax) / 2;
  136. icmp = smoke->leg(smoke->methodMaps[icur].classId, classId.index);
  137. if (icmp == 0) {
  138. Smoke::Index pos = icur;
  139. while (icur != 0 && smoke->methodMaps[icur-1].classId == classId.index) {
  140. icur --;
  141. }
  142. methmin = icur;
  143. icur = pos;
  144. while (icur < imax && smoke->methodMaps[icur+1].classId == classId.index) {
  145. icur ++;
  146. }
  147. methmax = icur;
  148. break;
  149. }
  150. if (icmp > 0) {
  151. imax = icur - 1;
  152. } else {
  153. imin = icur + 1;
  154. }
  155. }
  156. if (icmp == 0) {
  157. for (Smoke::Index i = methmin ; i <= methmax ; i++) {
  158. Smoke::Index ix = smoke->methodMaps[i].method;
  159. if (ix >= 0) { // single match
  160. QString method = methodToString(Smoke::ModuleIndex(smoke, ix));
  161. if (!matchPattern || targetPattern.indexIn(method) != -1) {
  162. qOut << method << "\n";
  163. }
  164. } else { // multiple match
  165. ix = -ix; // turn into ambiguousMethodList index
  166. while (smoke->ambiguousMethodList[ix]) {
  167. QString method = methodToString(Smoke::ModuleIndex(smoke, smoke->ambiguousMethodList[ix]));
  168. if (!matchPattern || targetPattern.indexIn(method) != -1) {
  169. qOut << method << "\n";
  170. }
  171. ix++;
  172. }
  173. }
  174. }
  175. }
  176. }
  177. #define PRINT_USAGE() \
  178. qDebug() << "Usage:" << argv[0] << "-r <smoke lib> [-r more smoke libs..] [-c] [-p] [-m pattern] [-i] [<classname(s)>..]"
  179. int main(int argc, char** argv)
  180. {
  181. QCoreApplication app(argc, argv);
  182. QStringList arguments = app.arguments();
  183. showClassNamesOnly = false;
  184. showParents = false;
  185. caseInsensitive = false;
  186. matchPattern = false;
  187. if (argc == 1) {
  188. PRINT_USAGE();
  189. return 0;
  190. }
  191. int i = 1;
  192. while (i < arguments.length()) {
  193. if (arguments[i] == QLatin1String("-h") || arguments[i] == QLatin1String("--help")) {
  194. PRINT_USAGE();
  195. return 0;
  196. } else if (arguments[i] == QLatin1String("-r") || arguments[i] == QLatin1String("--require")) {
  197. i++;
  198. if (i < arguments.length()) {
  199. smokeModules << loadSmokeModule(arguments[i]);
  200. }
  201. i++;
  202. } else if (arguments[i] == QLatin1String("-c") || arguments[i] == QLatin1String("--classes")) {
  203. showClassNamesOnly = true;
  204. i++;
  205. } else if (arguments[i] == QLatin1String("-p") || arguments[i] == QLatin1String("--parents")) {
  206. showParents = true;
  207. i++;
  208. } else if (arguments[i] == QLatin1String("-i") || arguments[i] == QLatin1String("--insensitive")) {
  209. caseInsensitive = true;
  210. i++;
  211. } else if (arguments[i] == QLatin1String("-m") || arguments[i] == QLatin1String("--match")) {
  212. i++;
  213. if (i < arguments.length()) {
  214. targetPattern = QRegExp(arguments[i]);
  215. matchPattern = true;
  216. }
  217. i++;
  218. } else {
  219. break;
  220. }
  221. }
  222. if (caseInsensitive) {
  223. targetPattern.setCaseSensitivity(Qt::CaseInsensitive);
  224. }
  225. smokeModules << loadSmokeModule("qtcore");
  226. if (i >= arguments.length()) {
  227. if (targetPattern.isEmpty()) {
  228. PRINT_USAGE();
  229. return 0;
  230. } else {
  231. foreach (Smoke * smoke, smokeModules) {
  232. for (int i = 1; i <= smoke->numClasses; i++) {
  233. if (!smoke->classes[i].external) {
  234. showClass(Smoke::ModuleIndex(smoke, i), 0);
  235. }
  236. }
  237. }
  238. return 0;
  239. }
  240. }
  241. while (i < arguments.length()) {
  242. QString className = arguments[i];
  243. Smoke::ModuleIndex classId = Smoke::findClass(className.toLatin1());
  244. if (classId == Smoke::NullModuleIndex) {
  245. qFatal("Error: class '%s' not found", className.toLatin1().constData());
  246. }
  247. if (showParents) {
  248. QList<ClassEntry> parents = getAllParents(classId, 0);
  249. foreach (ClassEntry parent, parents) {
  250. showClass(parent.first, parent.second);
  251. }
  252. } else {
  253. showClass(classId, 0);
  254. }
  255. i++;
  256. }
  257. return 0;
  258. }