You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/03/09 18:14:55 UTC
[lucy-commits] [1/16] git commit: refs/heads/c-bindings-wip3 - Generate man pages
for C bindings
Generate man pages for C bindings
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/05d6117d
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/05d6117d
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/05d6117d
Branch: refs/heads/c-bindings-wip3
Commit: 05d6117d9e91b32c21450569d90ce2c515729769
Parents: c0e8814
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Sun Dec 23 16:39:57 2012 +0100
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sat Mar 9 17:51:54 2013 +0100
----------------------------------------------------------------------
clownfish/compiler/c/cfc.c | 1 +
clownfish/compiler/src/CFCC.c | 54 ++++++
clownfish/compiler/src/CFCC.h | 5 +
clownfish/compiler/src/CFCCClass.c | 283 +++++++++++++++++++++++++++++++
clownfish/compiler/src/CFCCClass.h | 5 +
5 files changed, 348 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy/blob/05d6117d/clownfish/compiler/c/cfc.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/c/cfc.c b/clownfish/compiler/c/cfc.c
index 9fa27f8..70bb820 100644
--- a/clownfish/compiler/c/cfc.c
+++ b/clownfish/compiler/c/cfc.c
@@ -188,6 +188,7 @@ main(int argc, char **argv) {
c_binding = CFCC_new(hierarchy, header, footer);
CFCC_write_callbacks(c_binding);
+ CFCC_write_man_pages(c_binding);
CFCBase_decref((CFCBase*)c_binding);
CFCBase_decref((CFCBase*)core_binding);
http://git-wip-us.apache.org/repos/asf/lucy/blob/05d6117d/clownfish/compiler/src/CFCC.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCC.c b/clownfish/compiler/src/CFCC.c
index 0a1b9cb..6b62f69 100644
--- a/clownfish/compiler/src/CFCC.c
+++ b/clownfish/compiler/src/CFCC.c
@@ -113,4 +113,58 @@ CFCC_write_callbacks(CFCC *self) {
FREEMEM(file_content);
}
+void
+CFCC_write_man_pages(CFCC *self) {
+ CFCHierarchy *hierarchy = self->hierarchy;
+ CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy);
+
+ size_t num_classes = 0;
+ for (size_t i = 0; ordered[i] != NULL; i++) {
+ CFCClass *klass = ordered[i];
+ if (!CFCClass_included(klass)) { ++num_classes; }
+ }
+ char **man_pages = (char**)CALLOCATE(num_classes, sizeof(char*));
+
+ // Generate man pages, but don't write. That way, if there's an error
+ // while generating the pages, we leak memory but don't clutter up the file
+ // system.
+ for (size_t i = 0, j = 0; ordered[i] != NULL; i++) {
+ CFCClass *klass = ordered[i];
+ if (CFCClass_included(klass)) { continue; }
+
+ char *man_page = CFCCClass_create_man_page(klass);
+ man_pages[j++] = man_page;
+ }
+
+ const char *dest = CFCHierarchy_get_dest(hierarchy);
+ char *man3_path
+ = CFCUtil_sprintf("%s" CHY_DIR_SEP "man" CHY_DIR_SEP "man3", dest);
+ if (!CFCUtil_is_dir(man3_path)) {
+ CFCUtil_make_path(man3_path);
+ if (!CFCUtil_is_dir(man3_path)) {
+ CFCUtil_die("Can't make path %s", man3_path);
+ }
+ }
+
+ // Write out any man pages that have changed.
+ for (size_t i = 0, j = 0; ordered[i] != NULL; i++) {
+ CFCClass *klass = ordered[i];
+ if (CFCClass_included(klass)) { continue; }
+
+ char *man_page = man_pages[j++];
+ if (!man_page) { continue; }
+
+ const char *class_name = CFCClass_get_class_name(klass);
+ char *filename
+ = CFCUtil_sprintf("%s" CHY_DIR_SEP "%s.3", man3_path, class_name);
+ CFCUtil_write_if_changed(filename, man_page, strlen(man_page));
+ FREEMEM(filename);
+ FREEMEM(man_page);
+ }
+
+ FREEMEM(man3_path);
+ FREEMEM(man_pages);
+ FREEMEM(ordered);
+}
+
http://git-wip-us.apache.org/repos/asf/lucy/blob/05d6117d/clownfish/compiler/src/CFCC.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCC.h b/clownfish/compiler/src/CFCC.h
index 694b4e7..e66a900 100644
--- a/clownfish/compiler/src/CFCC.h
+++ b/clownfish/compiler/src/CFCC.h
@@ -49,6 +49,11 @@ CFCC_destroy(CFCC *self);
void
CFCC_write_callbacks(CFCC *self);
+/** Write all man pages.
+ */
+void
+CFCC_write_man_pages(CFCC *self);
+
#ifdef __cplusplus
}
#endif
http://git-wip-us.apache.org/repos/asf/lucy/blob/05d6117d/clownfish/compiler/src/CFCCClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCCClass.c b/clownfish/compiler/src/CFCCClass.c
index b694ba7..7b65530 100644
--- a/clownfish/compiler/src/CFCCClass.c
+++ b/clownfish/compiler/src/CFCCClass.c
@@ -14,11 +14,36 @@
* limitations under the License.
*/
+#include <string.h>
+
#include "CFCCClass.h"
#include "CFCClass.h"
+#include "CFCDocuComment.h"
+#include "CFCFunction.h"
#include "CFCMethod.h"
+#include "CFCParamList.h"
+#include "CFCType.h"
#include "CFCUtil.h"
+static char*
+S_man_create_synopsis(CFCClass *klass);
+
+static char*
+S_man_create_functions(CFCClass *klass);
+
+static char*
+S_man_create_methods(CFCClass *klass);
+
+static char*
+S_man_create_func(CFCClass *klass, CFCFunction *func, const char *short_sym,
+ const char *full_sym);
+
+static char*
+S_man_create_inheritance(CFCClass *klass);
+
+static char*
+S_man_escape_content(const char *content);
+
// Declare dummy host callbacks.
char*
CFCCClass_callback_decs(CFCClass *klass) {
@@ -41,3 +66,261 @@ CFCCClass_callback_decs(CFCClass *klass) {
return cb_decs;
}
+char*
+CFCCClass_create_man_page(CFCClass *klass) {
+ const char *class_name = CFCClass_get_class_name(klass);
+
+ CFCDocuComment *docucom = CFCClass_get_docucomment(klass);
+ if (!docucom) { return NULL; }
+
+ // Get the class's brief description.
+ const char *raw_brief = CFCDocuComment_get_brief(docucom);
+ char *brief = S_man_escape_content(raw_brief);
+
+ // Get the class's long description.
+ const char *raw_description = CFCDocuComment_get_long(docucom);
+ char *description = S_man_escape_content(raw_description);
+
+ // Create SYNOPSIS.
+ char *synopsis = S_man_create_synopsis(klass);
+
+ // Create CONSTRUCTORS.
+ char *functions_man = S_man_create_functions(klass);
+
+ // Create METHODS, possibly including an ABSTRACT METHODS section.
+ char *methods_man = S_man_create_methods(klass);
+
+ // Build an INHERITANCE section describing class ancestry.
+ char *inheritance = S_man_create_inheritance(klass);
+
+ // Put it all together.
+ const char pattern[] =
+ ".\\\" Licensed to the Apache Software Foundation (ASF) under one or more\n"
+ ".\\\" contributor license agreements. See the NOTICE file distributed with\n"
+ ".\\\" this work for additional information regarding copyright ownership.\n"
+ ".\\\" The ASF licenses this file to You under the Apache License, Version 2.0\n"
+ ".\\\" (the \"License\"); you may not use this file except in compliance with\n"
+ ".\\\" the License. You may obtain a copy of the License at\n"
+ ".\\\"\n"
+ ".\\\" http://www.apache.org/licenses/LICENSE-2.0\n"
+ ".\\\"\n"
+ ".\\\" Unless required by applicable law or agreed to in writing, software\n"
+ ".\\\" distributed under the License is distributed on an \"AS IS\" BASIS,\n"
+ ".\\\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n"
+ ".\\\" See the License for the specific language governing permissions and\n"
+ ".\\\" limitations under the License.\n"
+ ".TH %s 3\n"
+ ".SH NAME\n"
+ "%s - %s\n"
+ "%s"
+ ".SH DESCRIPTION\n"
+ "%s\n"
+ "%s"
+ "%s"
+ "%s";
+ char *man_page
+ = CFCUtil_sprintf(pattern, class_name, class_name, brief, synopsis,
+ description, functions_man, methods_man,
+ inheritance);
+
+ FREEMEM(brief);
+ FREEMEM(synopsis);
+ FREEMEM(description);
+ FREEMEM(functions_man);
+ FREEMEM(methods_man);
+ FREEMEM(inheritance);
+
+ return man_page;
+}
+
+static char*
+S_man_create_synopsis(CFCClass *klass) {
+ return CFCUtil_strdup("");
+}
+
+static char*
+S_man_create_functions(CFCClass *klass) {
+ CFCFunction **functions = CFCClass_functions(klass);
+ const char *class_name = CFCClass_get_class_name(klass);
+ char *result = CFCUtil_strdup(".SH FUNCTIONS\n");
+
+ for (int func_num = 0; functions[func_num] != NULL; func_num++) {
+ CFCFunction *func = functions[func_num];
+ if (!CFCFunction_public(func)) { continue; }
+
+ const char *micro_sym = CFCFunction_micro_sym(func);
+ const char *full_func_sym = CFCFunction_full_func_sym(func);
+
+ char *redman = S_man_create_func(klass, func, micro_sym,
+ full_func_sym);
+ result = CFCUtil_cat(result, redman, NULL);
+ FREEMEM(redman);
+ }
+
+ return result;
+}
+
+static char*
+S_man_create_methods(CFCClass *klass) {
+ CFCMethod **fresh_methods = CFCClass_fresh_methods(klass);
+ const char *class_name = CFCClass_get_class_name(klass);
+ char *result = CFCUtil_strdup(".SH METHODS\n");
+
+ for (int meth_num = 0; fresh_methods[meth_num] != NULL; meth_num++) {
+ CFCMethod *method = fresh_methods[meth_num];
+ if (!CFCMethod_public(method)) { continue; }
+
+ const char *macro_sym = CFCMethod_get_macro_sym(method);
+ char *full_method_sym = CFCMethod_full_method_sym(method, NULL);
+
+ char *method_man = S_man_create_func(klass, (CFCFunction*)method,
+ macro_sym, full_method_sym);
+ result = CFCUtil_cat(result, method_man, NULL);
+
+ FREEMEM(method_man);
+ FREEMEM(full_method_sym);
+ }
+
+ FREEMEM(fresh_methods);
+
+ return result;
+}
+
+static char*
+S_man_create_func(CFCClass *klass, CFCFunction *func, const char *short_sym,
+ const char *full_sym) {
+ CFCType *return_type
+ = CFCFunction_get_return_type(func);
+ const char *return_type_c = CFCType_to_c(return_type);
+
+ CFCParamList *param_list
+ = CFCFunction_get_param_list(func);
+ const char *param_list_c = CFCParamList_to_c(param_list);
+
+ const char *pattern =
+ ".TP\n"
+ ".B %s\n"
+ ".na\n"
+ "%s\n"
+ ".br\n"
+ ".BR \"%s\" \"(%s);\"\n"
+ ".ad\n";
+ char *result = CFCUtil_sprintf(pattern, short_sym, return_type_c, full_sym,
+ param_list_c);
+
+ // Get documentation, which may be inherited.
+ CFCDocuComment *docucomment = CFCFunction_get_docucomment(func);
+ if (!docucomment) {
+ const char *micro_sym = CFCFunction_micro_sym(func);
+ CFCClass *parent = klass;
+ while (NULL != (parent = CFCClass_get_parent(parent))) {
+ CFCFunction *parent_func
+ = (CFCFunction*)CFCClass_method(parent, micro_sym);
+ if (!parent_func) { break; }
+ docucomment = CFCFunction_get_docucomment(parent_func);
+ if (docucomment) { break; }
+ }
+ }
+
+ if (docucomment) {
+ // Description
+ const char *raw_desc = CFCDocuComment_get_description(docucomment);
+ char *desc = S_man_escape_content(raw_desc);
+ result = CFCUtil_cat(result, ".IP\n", desc, "\n", NULL);
+ FREEMEM(desc);
+
+ // Params
+ const char **param_names
+ = CFCDocuComment_get_param_names(docucomment);
+ const char **param_docs
+ = CFCDocuComment_get_param_docs(docucomment);
+ if (param_names[0]) {
+ result = CFCUtil_cat(result, ".RS\n", NULL);
+ for (size_t i = 0; param_names[i] != NULL; i++) {
+ char *doc = S_man_escape_content(param_docs[i]);
+ result = CFCUtil_cat(result, ".TP\n.I ", param_names[i],
+ "\n", doc, "\n", NULL);
+ FREEMEM(doc);
+ }
+ result = CFCUtil_cat(result, ".RE\n", NULL);
+ }
+
+ // Return value
+ const char *retval_doc = CFCDocuComment_get_retval(docucomment);
+ if (retval_doc && strlen(retval_doc)) {
+ char *doc = S_man_escape_content(retval_doc);
+ result = CFCUtil_cat(result, ".IP\n.B Returns:\n", doc, "\n",
+ NULL);
+ FREEMEM(doc);
+ }
+ }
+
+ return result;
+}
+
+static char*
+S_man_create_inheritance(CFCClass *klass) {
+ CFCClass *ancestor = CFCClass_get_parent(klass);
+ char *result = CFCUtil_strdup("");
+
+ if (!ancestor) { return result; }
+
+ const char *class_name = CFCClass_get_class_name(klass);
+ result = CFCUtil_cat(result, ".SH INHERITANCE\n", class_name, NULL);
+ while (ancestor) {
+ const char *ancestor_name = CFCClass_get_class_name(ancestor);
+ result = CFCUtil_cat(result, " is a ", ancestor_name, NULL);
+ ancestor = CFCClass_get_parent(ancestor);
+ }
+ result = CFCUtil_cat(result, ".\n", NULL);
+
+ return result;
+}
+
+static char*
+S_man_escape_content(const char *content) {
+ size_t result_len = 0;
+ size_t result_cap = strlen(content) + 20;
+ char *result = (char*)MALLOCATE(result_cap + 1);
+ int fill = 1;
+
+ for (size_t i = 0; content[i]; i++) {
+ char c[8];
+ int num_chars = 1;
+
+ c[0] = content[i];
+
+ switch (c[0]) {
+ case '\\':
+ c[1] = 'e';
+ num_chars = 2;
+ break;
+ case '-':
+ c[0] = '\\';
+ c[1] = '-';
+ num_chars = 2;
+ break;
+ case '\n':
+ if (content[i+1] == '.') {
+ memcpy(c + num_chars, "\\&", 2);
+ num_chars += 2;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (result_len + num_chars > result_cap) {
+ result_cap += 50;
+ result = (char*)REALLOCATE(result, result_cap + 1);
+ }
+
+ memcpy(result + result_len, c, num_chars);
+ result_len += num_chars;
+ }
+
+ result[result_len] = '\0';
+
+ return result;
+}
+
http://git-wip-us.apache.org/repos/asf/lucy/blob/05d6117d/clownfish/compiler/src/CFCCClass.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCCClass.h b/clownfish/compiler/src/CFCCClass.h
index c701d2f..b319596 100644
--- a/clownfish/compiler/src/CFCCClass.h
+++ b/clownfish/compiler/src/CFCCClass.h
@@ -28,6 +28,11 @@ struct CFCClass;
char*
CFCCClass_callback_decs(struct CFCClass *klass);
+/** Return the man page for the class.
+ */
+char*
+CFCCClass_create_man_page(struct CFCClass *klass);
+
#ifdef __cplusplus
}
#endif