/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define CFC_NEED_BASE_STRUCT_DEF
#include <stdio.h>
#include <string.h>
#include "CFCBindClass.h"
#include "CFCBindFunction.h"
#include "CFCBindMethod.h"
#include "CFCBase.h"
#include "CFCClass.h"
#include "CFCFunction.h"
#include "CFCMethod.h"
#include "CFCParamList.h"
#include "CFCType.h"
#include "CFCVariable.h"
#include "CFCUtil.h"
struct CFCBindClass {
CFCBase base;
CFCClass *client;
char *full_callbacks_var;
char *full_name_var;
char *short_names_macro;
};
// Generate C header for an inert class.
static char*
S_to_c_header_inert(CFCBindClass *self);
// Generate C header for a dynamic class.
static char*
S_to_c_header_dynamic(CFCBindClass *self);
// Create the definition for the instantiable object struct.
static char*
S_struct_definition(CFCBindClass *self);
/* C code defining the ZombieCharBuf which contains the class name for this
* class.
*/
static char*
S_name_var_definition(CFCBindClass *self);
// Return C code defining the class's VTable.
static char*
S_vtable_definition(CFCBindClass *self);
// Declare cfish_Callback objects.
static char*
S_callback_declarations(CFCBindClass *self);
// Declare typedefs for novel methods, to ease casting.
static char*
S_method_typedefs(CFCBindClass *self);
// If class inherits from something, include the parent class's header.
static char*
S_parent_include(CFCBindClass *self);
// Add a C function definition for each method and each function.
static char*
S_sub_declarations(CFCBindClass *self);
// Declare class (a.k.a. "inert") variables.
static char*
S_inert_var_declarations(CFCBindClass *self);
// Define method invocation inline functions.
static char*
S_method_defs(CFCBindClass *self);
// Define the virtual table singleton object.
static char*
S_vt_singleton_def(CFCBindClass *self);
// Define short names for all of the symbols associated with this class.
static char*
S_short_names(CFCBindClass *self);
const static CFCMeta CFCBINDCLASS_META = {
"Clownfish::CFC::Binding::Core::Class",
sizeof(CFCBindClass),
(CFCBase_destroy_t)CFCBindClass_destroy
};
CFCBindClass*
CFCBindClass_new(CFCClass *client) {
CFCBindClass *self = (CFCBindClass*)CFCBase_allocate(&CFCBINDCLASS_META);
return CFCBindClass_init(self, client);
}
CFCBindClass*
CFCBindClass_init(CFCBindClass *self, CFCClass *client) {
CFCUTIL_NULL_CHECK(client);
self->client = (CFCClass*)CFCBase_incref((CFCBase*)client);
const char *full_vtable_var = CFCClass_full_vtable_var(client);
const char *PREFIX = CFCClass_get_PREFIX(client);
self->full_callbacks_var = (char*)MALLOCATE(strlen(full_vtable_var) + 20);
self->full_name_var = (char*)MALLOCATE(strlen(full_vtable_var) + 20);
self->short_names_macro = (char*)MALLOCATE(strlen(PREFIX) + 20);
sprintf(self->full_callbacks_var, "%s_CALLBACKS", full_vtable_var);
sprintf(self->full_name_var, "%s_CLASS_NAME", full_vtable_var);
sprintf(self->short_names_macro, "%sUSE_SHORT_NAMES", PREFIX);
return self;
}
void
CFCBindClass_destroy(CFCBindClass *self) {
FREEMEM(self->full_callbacks_var);
FREEMEM(self->full_name_var);
FREEMEM(self->short_names_macro);
CFCBase_decref((CFCBase*)self->client);
CFCBase_destroy((CFCBase*)self);
}
static int
S_method_is_novel(CFCMethod *method, CFCMethod **novel_methods) {
for (int i = 0; novel_methods[i] != NULL; i++) {
if (method == novel_methods[i]) { return 1; }
}
return 0;
}
char*
CFCBindClass_to_c_header(CFCBindClass *self) {
if (CFCClass_inert(self->client)) {
// Inert classes only output inert functions and vars.
return S_to_c_header_inert(self);
}
else {
return S_to_c_header_dynamic(self);
}
}
static char*
S_to_c_header_inert(CFCBindClass *self) {
char *inert_func_decs = S_sub_declarations(self);
char *inert_var_defs = S_inert_var_declarations(self);
char *short_names = S_short_names(self);
char pattern[] =
"#include \"charmony.h\"\n"
"#include \"parcel.h\"\n"
"\n"
"/* Declare this class's inert variables.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Declare this class's inert functions.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define \"short names\" for this class's symbols.\n"
" */\n"
"\n"
"%s\n"
"\n";
size_t size = sizeof(pattern)
+ strlen(inert_var_defs)
+ strlen(inert_func_decs)
+ strlen(short_names)
+ 50;
char *content = (char*)MALLOCATE(size);
sprintf(content, pattern, inert_var_defs, inert_func_decs, short_names);
FREEMEM(inert_var_defs);
FREEMEM(inert_func_decs);
FREEMEM(short_names);
return content;
}
static char*
S_to_c_header_dynamic(CFCBindClass *self) {
const char *privacy_symbol = CFCClass_privacy_symbol(self->client);
char *struct_def = S_struct_definition(self);
char *parent_include = S_parent_include(self);
char *sub_declarations = S_sub_declarations(self);
char *inert_var_defs = S_inert_var_declarations(self);
char *method_typedefs = S_method_typedefs(self);
char *method_defs = S_method_defs(self);
char *vt_singleton_def = S_vt_singleton_def(self);
char *callback_declarations = S_callback_declarations(self);
char *short_names = S_short_names(self);
char pattern[] =
"#include \"charmony.h\"\n"
"#include \"parcel.h\"\n"
"\n"
"/* Include the header for this class's parent. \n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define the struct layout for instances of this class.\n"
" */\n"
"\n"
"#ifdef %s\n"
"%s\n"
"#endif /* %s */\n"
"\n"
"/* Declare this class's inert variables.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Declare both this class's inert functions and the C functions which\n"
" * implement this class's dynamic methods.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Declare the cfish_Callback objects which provide the introspection\n"
" * information needed to perform method overriding at runtime.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define typedefs for each dynamic method, allowing us to cast generic\n"
" * pointers to the appropriate function pointer type more cleanly.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define the inline functions which implement this class's virtual methods.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define the VTable singleton for this class.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define \"short names\" for this class's symbols.\n"
" */\n"
"\n"
"%s\n"
"\n";
size_t size = sizeof(pattern)
+ strlen(parent_include)
+ strlen(privacy_symbol)
+ strlen(struct_def)
+ strlen(privacy_symbol)
+ strlen(inert_var_defs)
+ strlen(sub_declarations)
+ strlen(callback_declarations)
+ strlen(method_typedefs)
+ strlen(method_defs)
+ strlen(vt_singleton_def)
+ strlen(short_names)
+ 100;
char *content = (char*)MALLOCATE(size);
sprintf(content, pattern, parent_include, privacy_symbol, struct_def,
privacy_symbol, inert_var_defs, sub_declarations,
callback_declarations, method_typedefs, method_defs,
vt_singleton_def, short_names);
FREEMEM(struct_def);
FREEMEM(parent_include);
FREEMEM(sub_declarations);
FREEMEM(inert_var_defs);
FREEMEM(method_typedefs);
FREEMEM(method_defs);
FREEMEM(vt_singleton_def);
FREEMEM(callback_declarations);
FREEMEM(short_names);
return content;
}
char*
CFCBindClass_to_c(CFCBindClass *self) {
CFCClass *client = self->client;
if (CFCClass_inert(client)) {
return CFCUtil_strdup(CFCClass_get_autocode(client));
}
const char *include_h = CFCClass_include_h(client);
const char *autocode = CFCClass_get_autocode(client);
const char *vt_type = CFCClass_full_vtable_type(client);
const char *cnick = CFCClass_get_cnick(client);
char *class_name_def = S_name_var_definition(self);
char *vtable_def = S_vtable_definition(self);
CFCMethod **methods = CFCClass_methods(client);
CFCMethod **novel_methods = CFCClass_novel_methods(client);
char *offsets = CFCUtil_strdup("");
char *cb_funcs = CFCUtil_strdup("");
char *cb_objects = CFCUtil_strdup("");
/* Start a NULL-terminated array of cfish_Callback vars. Since C89
* doesn't allow us to initialize a pointer to an anonymous array inside a
* global struct, we have to give it a real symbol and then store a pointer
* to that symbol inside the VTable struct. */
char *cb_var = CFCUtil_strdup("");
cb_var = CFCUtil_cat(cb_var, "cfish_Callback *", self->full_callbacks_var,
"[] = {\n ", NULL);
for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) {
CFCMethod *method = methods[meth_num];
int method_is_novel = S_method_is_novel(method, novel_methods);
size_t off_sym_size
= CFCMethod_full_offset_sym(method, cnick, NULL, 0);
char *full_offset_sym = (char*)MALLOCATE(off_sym_size);
CFCMethod_full_offset_sym(method, cnick, full_offset_sym,
off_sym_size);
char meth_num_str[20];
sprintf(meth_num_str, "%d", meth_num);
// Create offset in bytes for the method from the top of the VTable
// object.
char *offset_str = CFCUtil_cat(CFCUtil_strdup(""), "(offsetof(", vt_type,
", methods) + ", meth_num_str,
" * sizeof(cfish_method_t))", NULL);
offsets = CFCUtil_cat(offsets, "size_t ", full_offset_sym, " = ",
offset_str, ";\n", NULL);
FREEMEM(full_offset_sym);
// Create a default implementation for abstract methods.
if (method_is_novel && CFCMethod_abstract(method)) {
char *method_def = CFCBindMeth_abstract_method_def(method);
cb_funcs = CFCUtil_cat(cb_funcs, method_def, "\n", NULL);
FREEMEM(method_def);
}
// Define callbacks for methods that can be overridden via the
// host.
if (CFCMethod_public(method) || CFCMethod_abstract(method)) {
const char *full_cb_sym = CFCMethod_full_callback_sym(method);
if (method_is_novel) {
char *cb_def = CFCBindMeth_callback_def(method);
char *cb_obj_def
= CFCBindMeth_callback_obj_def(method, offset_str);
cb_funcs = CFCUtil_cat(cb_funcs, cb_def, "\n", NULL);
cb_objects = CFCUtil_cat(cb_objects, cb_obj_def, NULL);
FREEMEM(cb_def);
FREEMEM(cb_obj_def);
}
cb_var = CFCUtil_cat(cb_var, "&", full_cb_sym, ",\n ", NULL);
}
FREEMEM(offset_str);
}
// Close callbacks variable definition.
cb_var = CFCUtil_cat(cb_var, "NULL\n};\n", NULL);
const char pattern[] =
"#include \"%s\"\n"
"\n"
"/* Offsets for method pointers, measured in bytes, from the top\n"
" * of this class's vtable.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define functions which implement host callbacks for the methods\n"
" * of this class which can be overridden via the host.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define the cfish_Callback objects which provide introspection\n"
" * information and allow runtime overriding of dynamic methods.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Assemble all the cfish_Callback objects for this class so that\n"
" * they can be searched when performing method overriding.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define the variable which holds this class's class name.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Define this class's VTable.\n"
" */\n"
"\n"
"%s\n"
"\n"
"/* Include auxilary automatically generated code for this class.\n"
" */\n"
"\n"
"%s\n"
"\n";
size_t size = sizeof(pattern)
+ strlen(include_h)
+ strlen(offsets)
+ strlen(cb_funcs)
+ strlen(cb_objects)
+ strlen(cb_var)
+ strlen(class_name_def)
+ strlen(vtable_def)
+ strlen(autocode)
+ 100;
char *code = (char*)MALLOCATE(size);
sprintf(code, pattern, include_h, offsets, cb_funcs, cb_objects, cb_var,
class_name_def, vtable_def, autocode);
FREEMEM(novel_methods);
FREEMEM(offsets);
FREEMEM(cb_funcs);
FREEMEM(cb_objects);
FREEMEM(cb_var);
FREEMEM(class_name_def);
FREEMEM(vtable_def);
return code;
}
// Create the definition for the instantiable object struct.
static char*
S_struct_definition(CFCBindClass *self) {
const char *struct_sym = CFCClass_full_struct_sym(self->client);
CFCVariable **member_vars = CFCClass_member_vars(self->client);
char *member_decs = CFCUtil_strdup("");
for (int i = 0; member_vars[i] != NULL; i++) {
const char *member_dec = CFCVariable_local_declaration(member_vars[i]);
size_t needed = strlen(member_decs) + strlen(member_dec) + 10;
member_decs = (char*)REALLOCATE(member_decs, needed);
strcat(member_decs, "\n ");
strcat(member_decs, member_dec);
}
char pattern[] = "struct %s {%s\n};\n";
size_t size = sizeof(pattern)
+ strlen(struct_sym)
+ strlen(member_decs)
+ 10;
char *struct_def = (char*)MALLOCATE(size);
sprintf(struct_def, pattern, struct_sym, member_decs);
FREEMEM(member_decs);
return struct_def;
}
static char*
S_name_var_definition(CFCBindClass *self) {
const char *class_name = CFCClass_get_class_name(self->client);
unsigned class_name_len = (unsigned)strlen(class_name);
const char pattern[] =
"static cfish_ZombieCharBuf %s = {\n"
" CFISH_ZOMBIECHARBUF,\n"
" {1}, /* ref.count */\n"
" \"%s\",\n"
" %u,\n"
" 0\n"
"};\n\n";
size_t size = sizeof(pattern)
+ strlen(self->full_name_var)
+ class_name_len
+ 15 // class_name_len
+ 20;
char *name_var_def = (char*)MALLOCATE(size);
sprintf(name_var_def, pattern, self->full_name_var, class_name,
class_name_len);
return name_var_def;
}
// Return C code defining the class's VTable.
static char*
S_vtable_definition(CFCBindClass *self) {
CFCClass *client = self->client;
CFCClass *parent = CFCClass_get_parent(client);
CFCMethod **methods = CFCClass_methods(client);
const char *vt_type = CFCClass_full_vtable_type(client);
const char *vt_var = CFCClass_full_vtable_var(client);
const char *struct_sym = CFCClass_full_struct_sym(client);
// Create a pointer to the parent class's vtable.
const char *parent_ref = parent
? CFCClass_full_vtable_var(parent)
: "NULL"; // No parent, e.g. Obj or inert classes.
// Spec functions which implement the methods, casting to quiet compiler.
char *method_str = CFCUtil_strdup("");
int num_methods = 0;
for (; methods[num_methods] != NULL; num_methods++) {
CFCMethod *method = methods[num_methods];
const char *implementing_sym = CFCMethod_implementing_func_sym(method);
size_t size = strlen(method_str) + strlen(implementing_sym) + 50;
method_str = (char*)REALLOCATE(method_str, size);
if (strlen(method_str)) {
strcat(method_str, ",\n");
}
strcat(method_str, " (cfish_method_t)");
strcat(method_str, implementing_sym);
}
char pattern[] =
"\n"
"%s %s_vt = {\n"
" CFISH_VTABLE, /* vtable vtable */\n"
" {1}, /* ref.count */\n"
" %s, /* parent */\n"
" (cfish_CharBuf*)&%s,\n"
" 0, /* flags */\n"
" NULL, /* \"void *x\" member reserved for future use */\n"
" sizeof(%s), /* obj_alloc_size */\n"
" offsetof(cfish_VTable, methods)\n"
" + %d * sizeof(cfish_method_t), /* vt_alloc_size */\n"
" &%s, /* callbacks */\n"
" {\n"
"%s\n"
" }\n"
"};\n\n";
size_t size = sizeof(pattern)
+ strlen(vt_type)
+ strlen(vt_var)
+ strlen(parent_ref)
+ strlen(self->full_name_var)
+ strlen(struct_sym)
+ 10 /* num_methods */
+ strlen(self->full_callbacks_var)
+ strlen(method_str)
+ 40;
char *vtable_def = (char*)MALLOCATE(size);
sprintf(vtable_def, pattern, vt_type, vt_var, parent_ref,
self->full_name_var, struct_sym, num_methods,
self->full_callbacks_var, method_str);
FREEMEM(method_str);
return vtable_def;
}
// Declare cfish_Callback objects.
static char*
S_callback_declarations(CFCBindClass *self) {
CFCMethod** novel_methods = CFCClass_novel_methods(self->client);
char *declarations = CFCUtil_strdup("");
for (int i = 0; novel_methods[i] != NULL; i++) {
CFCMethod *method = novel_methods[i];
if (CFCMethod_public(method) || CFCMethod_abstract(method)) {
char *callback = CFCBindMeth_callback_dec(method);
declarations = CFCUtil_cat(declarations, callback, NULL);
FREEMEM(callback);
}
}
FREEMEM(novel_methods);
return declarations;
}
// Declare typedefs for novel methods, to ease casting.
static char*
S_method_typedefs(CFCBindClass *self) {
CFCMethod** novel_methods = CFCClass_novel_methods(self->client);
char *typedefs = CFCUtil_strdup("");
for (int i = 0; novel_methods[i] != NULL; i++) {
CFCMethod *method = novel_methods[i];
char *typedef_str = CFCBindMeth_typdef_dec(method);
typedefs = CFCUtil_cat(typedefs, typedef_str, "\n", NULL);
FREEMEM(typedef_str);
}
FREEMEM(novel_methods);
return typedefs;
}
// If class inherits from something, include the parent class's header.
static char*
S_parent_include(CFCBindClass *self) {
char *parent_include = CFCUtil_strdup("");
CFCClass *parent = CFCClass_get_parent(self->client);
if (parent) {
parent_include = CFCUtil_cat(parent_include, "#include \"",
CFCClass_include_h(parent), "\"", NULL);
}
return parent_include;
}
// Add a C function definition for each method and each function.
static char*
S_sub_declarations(CFCBindClass *self) {
CFCFunction **functions = CFCClass_functions(self->client);
CFCMethod** novel_methods = CFCClass_novel_methods(self->client);
char *declarations = CFCUtil_strdup("");
for (int i = 0; functions[i] != NULL; i++) {
CFCFunction *func = functions[i];
char *dec = CFCBindFunc_func_declaration(func);
declarations = CFCUtil_cat(declarations, dec, "\n\n", NULL);
FREEMEM(dec);
}
for (int i = 0; novel_methods[i] != NULL; i++) {
CFCMethod *method = novel_methods[i];
char *dec = CFCBindFunc_func_declaration((CFCFunction*)method);
declarations = CFCUtil_cat(declarations, dec, "\n\n", NULL);
FREEMEM(dec);
}
FREEMEM(novel_methods);
return declarations;
}
// Declare class (a.k.a. "inert") variables.
static char*
S_inert_var_declarations(CFCBindClass *self) {
CFCVariable **inert_vars = CFCClass_inert_vars(self->client);
char *declarations = CFCUtil_strdup("");
for (int i = 0; inert_vars[i] != NULL; i++) {
const char *global_c = CFCVariable_global_c(inert_vars[i]);
declarations = CFCUtil_cat(declarations, "extern ", global_c, ";\n",
NULL);
}
return declarations;
}
// Define method invocation inline functions.
static char*
S_method_defs(CFCBindClass *self) {
CFCMethod **methods = CFCClass_methods(self->client);
char *method_defs = CFCUtil_strdup("");
for (int i = 0; methods[i] != NULL; i++) {
CFCMethod *method = methods[i];
char *def = CFCBindMeth_method_def(method, self->client);
method_defs = CFCUtil_cat(method_defs, def, "\n", NULL);
FREEMEM(def);
}
return method_defs;
}
// Define the virtual table singleton object.
static char*
S_vt_singleton_def(CFCBindClass *self) {
CFCClass *client = self->client;
const char *vt_type = CFCClass_full_vtable_type(client);
const char *vt_var = CFCClass_full_vtable_var(client);
const char *vt_hidden = CFCClass_full_vtable_hidden(client);
size_t num_methods = CFCClass_num_methods(client);
const char pattern[] =
"typedef struct %s {\n"
" cfish_VTable *vtable;\n"
" cfish_ref_t ref;\n"
" cfish_VTable *parent;\n"
" cfish_CharBuf *name;\n"
" uint32_t flags;\n"
" void *x;\n"
" size_t obj_alloc_size;\n"
" size_t vt_alloc_size;\n"
" void *callbacks;\n"
" cfish_method_t methods[%lu];\n"
"} %s;\n"
"extern struct %s %s;\n"
"#define %s ((cfish_VTable*)&%s)\n";
size_t size = sizeof(pattern)
+ strlen(vt_type)
+ 40 // num_methods
+ strlen(vt_type)
+ strlen(vt_type)
+ strlen(vt_hidden)
+ strlen(vt_var)
+ strlen(vt_hidden)
+ 30;
char *def = (char*)MALLOCATE(size);
sprintf(def, pattern, vt_type, (unsigned long)num_methods, vt_type,
vt_type, vt_hidden, vt_var, vt_hidden);
return def;
}
// Define short names for all of the symbols associated with this class.
static char*
S_short_names(CFCBindClass *self) {
CFCClass *client = self->client;
char *short_names = CFCUtil_strdup("");
short_names = CFCUtil_cat(short_names, "#ifdef ", self->short_names_macro,
"\n", NULL);
if (!CFCClass_inert(client)) {
const char *short_struct = CFCClass_get_struct_sym(client);
const char *full_struct = CFCClass_full_struct_sym(client);
const char *short_vt_var = CFCClass_short_vtable_var(client);
const char *full_vt_var = CFCClass_full_vtable_var(client);
short_names = CFCUtil_cat(short_names, " #define ",
short_struct, " ", full_struct, "\n",
" #define ", short_vt_var, " ",
full_vt_var, "\n", NULL);
}
CFCFunction **functions = CFCClass_functions(client);
for (int i = 0; functions[i] != NULL; i++) {
CFCFunction *func = functions[i];
short_names = CFCUtil_cat(short_names, " #define ",
CFCFunction_short_func_sym(func), " ",
CFCFunction_full_func_sym(func), "\n",
NULL);
}
CFCVariable **inert_vars = CFCClass_inert_vars(client);
for (int i = 0; inert_vars[i] != NULL; i++) {
CFCVariable *var = inert_vars[i];
short_names = CFCUtil_cat(short_names, " #define ",
CFCVariable_short_sym(var), " ",
CFCVariable_full_sym(var), "\n", NULL);
}
if (!CFCClass_inert(client)) {
CFCMethod **novel_methods = CFCClass_novel_methods(client);
for (int i = 0; novel_methods[i] != NULL; i++) {
CFCMethod *meth = novel_methods[i];
const char *short_typedef = CFCMethod_short_typedef(meth);
const char *full_typedef = CFCMethod_full_typedef(meth);
short_names = CFCUtil_cat(short_names, " #define ",
short_typedef, " ", full_typedef, "\n",
NULL);
const char *short_func = CFCMethod_short_implementing_func_sym(meth);
const char *full_func = CFCMethod_implementing_func_sym(meth);
short_names = CFCUtil_cat(short_names, " #define ", short_func,
" ", full_func, "\n", NULL);
}
FREEMEM(novel_methods);
CFCMethod **methods = CFCClass_methods(client);
const char *cnick = CFCClass_get_cnick(client);
for (int i = 0; methods[i] != NULL; i++) {
CFCMethod *meth = methods[i];
size_t size = CFCMethod_short_method_sym(meth, cnick, NULL, 0);
char *short_sym = (char*)MALLOCATE(size);
CFCMethod_short_method_sym(meth, cnick, short_sym, size);
size = CFCMethod_full_method_sym(meth, cnick, NULL, 0);
char *full_sym = (char*)MALLOCATE(size);
CFCMethod_full_method_sym(meth, cnick, full_sym, size);
short_names = CFCUtil_cat(short_names, " #define ", short_sym,
" ", full_sym, "\n", NULL);
FREEMEM(short_sym);
FREEMEM(full_sym);
}
}
short_names = CFCUtil_cat(short_names, "#endif /* ",
self->short_names_macro, " */\n", NULL);
return short_names;
}