summaryrefslogtreecommitdiff
path: root/tools/doxy2json
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2016-03-24 19:53:27 +0100
committerRobin Gareus <robin@gareus.org>2016-03-24 22:54:20 +0100
commit6188315791709e167b326a8ce8d996b212a1b7d6 (patch)
tree73cf04ef92ea774a18909a18b12c62e9307d742b /tools/doxy2json
parent940c165a313b174216da51d1b2b867ff8a9c206b (diff)
Add small llvm/libclang util to exctract doxygen comments
Diffstat (limited to 'tools/doxy2json')
-rwxr-xr-xtools/doxy2json/ardourdoc.sh55
-rw-r--r--tools/doxy2json/doxy2json.cc183
2 files changed, 238 insertions, 0 deletions
diff --git a/tools/doxy2json/ardourdoc.sh b/tools/doxy2json/ardourdoc.sh
new file mode 100755
index 0000000000..548d403e61
--- /dev/null
+++ b/tools/doxy2json/ardourdoc.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+set -e
+make
+cd ../..
+test -f libs/ardour/ardour/ardour.h
+LLVMINCLUDE="-I /usr/lib/llvm-3.6/include -I /usr/lib/llvm-3.6/lib/clang/3.6.2/include/"
+
+TMPFILE=`mktemp`
+trap 'rm -f $TMPFILE' exit SIGINT SIGTERM
+
+echo "# analyzing source.. -> $TMPFILE"
+./tools/doxy2json/doxy2json \
+ `pkg-config --cflags glib-2.0 glibmm-2.4 cairomm-1.0 gtkmm-2.4 | sed 's/-std=c++11 //;s/-pthread //'` \
+ $LLVMINCLUDE -I /usr/include/linux \
+ -I libs/ardour -I libs/pbd -I libs/lua -I gtk2_ardour -I libs/timecode \
+ -I libs/ltc -I libs/evoral \
+ libs/ardour/ardour/* libs/pbd/pbd/* \
+ gtk2_ardour/*.h \
+ /usr/include/cairomm-1.0/cairomm/context.h \
+> $TMPFILE
+
+ls -lh $TMPFILE
+
+echo "# consolidating JSON"
+php << EOF
+<?php
+\$json = file_get_contents ('$TMPFILE');
+\$api = array ();
+foreach (json_decode (\$json, true) as \$a) {
+ if (!isset (\$a['decl'])) { continue; }
+ if (empty (\$a['decl'])) { continue; }
+ if (\$a['decl'] == '::') { continue; }
+ if (substr (\$a['decl'], 0, 1) == '_') { continue; }
+ if (substr (\$a['decl'], 0, 2) == '::') { continue; }
+ if (substr (\$a['decl'], 0, 4) == 'sigc') { continue; }
+ if (substr (\$a['decl'], 0, 5) == 'Atk::') { continue; }
+ if (substr (\$a['decl'], 0, 5) == 'Gdk::') { continue; }
+ if (substr (\$a['decl'], 0, 5) == 'Gtk::') { continue; }
+ if (substr (\$a['decl'], 0, 5) == 'Gio::') { continue; }
+ if (substr (\$a['decl'], 0, 6) == 'Glib::') { continue; }
+ if (substr (\$a['decl'], 0, 7) == 'Pango::') { continue; }
+ if (substr (\$a['decl'], 0, 11) == 'luabridge::') { continue; }
+
+ \$a['decl'] = str_replace ('size_t', 'unsigned long', \$a['decl']);
+ \$canon = str_replace (' *', '*', \$a['decl']);
+ \$api[\$canon] = \$a;
+ }
+\$jout = array ();
+foreach (\$api as \$k => \$a) {
+ \$jout[] = \$a;
+}
+file_put_contents('doc/ardourapi.json', json_encode (\$jout, JSON_PRETTY_PRINT));
+EOF
+
+ls -l doc/ardourapi.json
diff --git a/tools/doxy2json/doxy2json.cc b/tools/doxy2json/doxy2json.cc
new file mode 100644
index 0000000000..f8242d5d46
--- /dev/null
+++ b/tools/doxy2json/doxy2json.cc
@@ -0,0 +1,183 @@
+/* extract doxygen comments from C++ header files
+ *
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+#include <iomanip>
+#include <clang-c/Index.h>
+#include <clang-c/Documentation.h>
+
+static const char*
+kind_to_txt (CXCursor cursor)
+{
+ CXCursorKind kind = clang_getCursorKind (cursor);
+ switch (kind) {
+ case CXCursor_StructDecl : return "Struct";
+ case CXCursor_EnumDecl : return "Enum";
+ case CXCursor_UnionDecl : return "Union";
+ case CXCursor_FunctionDecl : return "C Function";
+ case CXCursor_VarDecl : return "Variable";
+ case CXCursor_ClassDecl : return "C++ Class";
+ case CXCursor_CXXMethod : return "C++ Method";
+ case CXCursor_Namespace : return "C++ Namespace";
+ case CXCursor_Constructor : return "C++ Constructor";
+ case CXCursor_Destructor : return "C++ Destructor";
+ case CXCursor_FieldDecl : return "Data Member/Field";
+ default: break;
+ }
+ return "";
+}
+
+static std::string
+escape_json (const std::string &s)
+{
+ std::ostringstream o;
+ for (auto c = s.cbegin (); c != s.cend (); c++) {
+ switch (*c) {
+ case '"': o << "\\\""; break;
+ case '\\': o << "\\\\"; break;
+ case '\n': o << "\\n"; break;
+ case '\r': o << "\\r"; break;
+ case '\t': o << "\\t"; break;
+ default:
+ if ('\x00' <= *c && *c <= '\x1f') {
+ o << "\\u" << std::hex << std::setw (4) << std::setfill ('0') << (int)*c;
+ } else {
+ o << *c;
+ }
+ }
+ }
+ return o.str ();
+}
+
+static void recurse_parents (CXCursor cr) {
+ CXCursor pc = clang_getCursorSemanticParent (cr);
+ if (CXCursor_TranslationUnit == clang_getCursorKind (pc)) {
+ return;
+ }
+ if (!clang_Cursor_isNull (pc)) {
+ recurse_parents (pc);
+ printf ("%s::", clang_getCString (clang_getCursorDisplayName (pc)));
+ }
+}
+
+static enum CXChildVisitResult
+traverse (CXCursor cr, CXCursor /*parent*/, CXClientData)
+{
+ CXComment c = clang_Cursor_getParsedComment (cr);
+
+ if (clang_Comment_getKind (c) != CXComment_Null
+ && clang_isDeclaration (clang_getCursorKind (cr))
+ && 0 != strlen (kind_to_txt (cr))
+ ) {
+
+ printf ("{ \"decl\" : \"");
+ recurse_parents (cr);
+
+ // TODO: resolve typedef enum { .. } name;
+ // use clang_getCursorDefinition (clang_getCanonicalCursor (cr)) ??
+ printf ("%s\",\n", clang_getCString (clang_getCursorDisplayName (cr)));
+
+ if (clang_Cursor_isVariadic (cr)) {
+ printf (" \"variadic\" : true,\n");
+ }
+
+ printf (" \"kind\" : \"%s\",\n", kind_to_txt (cr));
+
+ CXSourceLocation loc = clang_getCursorLocation (cr);
+ CXFile file; unsigned line, col, off;
+ clang_getFileLocation (loc, &file, &line, &col, &off);
+
+ printf (" \"src\" : \"%s:%d\",\n",
+ clang_getCString (clang_getFileName (file)), line);
+
+ printf (" \"doc\" : \"%s\"\n",
+ escape_json (clang_getCString (clang_FullComment_getAsHTML (c))).c_str ());
+ printf ("},\n");
+ }
+ return CXChildVisit_Recurse;
+}
+
+static void
+process_file (int argc, char **args, const char *fn)
+{
+ CXIndex index = clang_createIndex (0, 0);
+ CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile (index, fn, argc, args, 0, 0);
+
+ if (tu == NULL) {
+ fprintf (stderr, "Cannot create translation unit for src: %s\n", fn);
+ return;
+ }
+
+ clang_visitChildren (clang_getTranslationUnitCursor (tu), traverse, 0);
+
+ clang_disposeTranslationUnit (tu);
+ clang_disposeIndex (index);
+}
+
+static void
+usage (int status)
+{
+ printf ("doxy2json - extract doxygen doc from C++ headers.\n\n");
+ fprintf (stderr, "Usage: dox2json [-I path]* <filename> [filename]*\n");
+ exit (status);
+}
+
+int main (int argc, char **argv)
+{
+ int cnt = 2;
+ char **args = (char**) malloc (cnt * sizeof (char*));
+ args[0] = strdup ("-x");
+ args[1] = strdup ("c++");
+ int c;
+ while (EOF != (c = getopt (argc, argv, "I:"))) {
+ switch (c) {
+ case 'I':
+ args = (char**) realloc (args, (cnt + 2) * sizeof (char*));
+ args[cnt++] = strdup ("-I");
+ args[cnt++] = strdup (optarg);
+ break;
+ case 'h':
+ usage (0);
+ default:
+ usage (EXIT_FAILURE);
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ usage (EXIT_FAILURE);
+ }
+
+ printf ("[\n");
+ for (int i = optind; i < argc; ++i) {
+ process_file (cnt, args, argv[i]);
+ }
+ printf ("{} ]\n");
+
+ for (int i = 0; i < cnt; ++i) {
+ free (args[i]);
+ }
+ free (args);
+
+ return 0;
+}