static void emit_c_encoded_array_size(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int __%s_encoded_array_size(const %s *p, int elements)", tn_, tn_); emit(0,"{"); emit(1,"int size = 0, element;"); emit(1, "for (element = 0; element < elements; element++) {"); emit(0,""); for (unsigned int m = 0; m < g_ptr_array_size(ls->members); m++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, m); emit_c_array_loops_start(lcm, f, lm, "p", FLAG_NONE); int indent = 2+imax(0, g_ptr_array_size(lm->dimensions) - 1); emit(indent, "size += __%s_encoded_array_size(%s, %s);", dots_to_underscores (lm->type->lctypename), make_accessor(lm, "p", g_ptr_array_size(lm->dimensions) - 1), make_array_size(lm, "p", g_ptr_array_size(lm->dimensions) - 1)); emit_c_array_loops_end(lcm, f, lm, "p", FLAG_NONE); emit(0,""); } emit(1,"}"); emit(1, "return size;"); emit(0,"}"); emit(0,""); }
static void emit_c_decode_array(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int __%s_decode_array(const void *buf, int offset, int maxlen, %s *p, int elements)", tn_, tn_); emit(0,"{"); emit(1, "int pos = 0, thislen, element;"); emit(0,""); emit(1, "for (element = 0; element < elements; element++) {"); emit(0,""); for (unsigned int m = 0; m < g_ptr_array_size(ls->members); m++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, m); emit_c_array_loops_start(lcm, f, lm, "p", lcm_is_constant_size_array(lm) ? FLAG_NONE : FLAG_EMIT_MALLOCS); int indent = 2+imax(0, g_ptr_array_size(lm->dimensions) - 1); emit(indent, "thislen = __%s_decode_array(buf, offset + pos, maxlen - pos, %s, %s);", dots_to_underscores (lm->type->lctypename), make_accessor(lm, "p", g_ptr_array_size(lm->dimensions) - 1), make_array_size(lm, "p", g_ptr_array_size(lm->dimensions) - 1)); emit(indent, "if (thislen < 0) return thislen; else pos += thislen;"); emit_c_array_loops_end(lcm, f, lm, "p", FLAG_NONE); emit(0,""); } emit(1, "}"); emit(1, "return pos;"); emit(0,"}"); emit(0,""); }
static void emit_c_clone_array(lcmgen_t *lcm, FILE *f, lcm_struct_t *lr) { char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int __%s_clone_array(const %s *p, %s *q, int elements)", tn_, tn_, tn_); emit(0,"{"); emit(1, "int element;"); emit(1, "for (element = 0; element < elements; element++) {"); emit(0,""); for (unsigned int m = 0; m < g_ptr_array_size(lr->members); m++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(lr->members, m); emit_c_array_loops_start(lcm, f, lm, "q", lcm_is_constant_size_array(lm) ? FLAG_NONE : FLAG_EMIT_MALLOCS); int indent = 2+imax(0, g_ptr_array_size(lm->dimensions) - 1); emit(indent, "__%s_clone_array(%s, %s, %s);", dots_to_underscores (lm->type->lctypename), make_accessor(lm, "p", g_ptr_array_size(lm->dimensions) - 1), make_accessor(lm, "q", g_ptr_array_size(lm->dimensions) - 1), make_array_size(lm, "p", g_ptr_array_size(lm->dimensions) - 1)); emit_c_array_loops_end(lcm, f, lm, "p", FLAG_NONE); emit(0,""); } emit(1, "}"); emit(1, "return 0;"); emit(0,"}"); emit(0,""); }
// Some types do not have a 1:1 mapping from lcm types to native C // storage types. Do not free the string pointers returned by this // function. static const char *map_type_name(const char *t) { if (!strcmp(t,"boolean")) return "logical"; if (!strcmp(t,"byte")) return "uint8"; if (!strcmp(t, "int8_t")) return "int8"; if (!strcmp(t, "int16_t")) return "int16"; if (!strcmp(t, "uint16_t")) return "uint16"; if (!strcmp(t, "int32_t")) return "int32"; if (!strcmp(t, "uint32_t")) return "uint32"; if (!strcmp(t, "int64_t")) return "int64"; if (!strcmp(t,"float")) return "single"; return dots_to_underscores (t); }
static void emit_c_struct_get_hash(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0, "static int __%s_hash_computed;", tn_); emit(0, "static uint64_t __%s_hash;", tn_); emit(0, ""); emit(0, "uint64_t __%s_hash_recursive(const __lcm_hash_ptr *p)", tn_); emit(0, "{"); emit(1, "const __lcm_hash_ptr *fp;"); emit(1, "for (fp = p; fp != NULL; fp = fp->parent)"); emit(2, "if (fp->v == __%s_get_hash)", tn_); emit(3, "return 0;"); emit(0, ""); emit(1, "__lcm_hash_ptr cp;"); emit(1, "cp.parent = p;"); emit(1, "cp.v = (void*)__%s_get_hash;", tn_); emit(1, "(void) cp;"); emit(0, ""); emit(1, "uint64_t hash = (uint64_t)0x%016"PRIx64"LL", ls->hash); for (unsigned int m = 0; m < g_ptr_array_size(ls->members); m++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, m); emit(2, " + __%s_hash_recursive(&cp)", dots_to_underscores(lm->type->lctypename)); } emit(2,";"); emit(0, ""); emit(1, "return (hash<<1) + ((hash>>63)&1);"); emit(0, "}"); emit(0, ""); emit(0, "int64_t __%s_get_hash(void)", tn_); emit(0, "{"); emit(1, "if (!__%s_hash_computed) {", tn_); emit(2, "__%s_hash = (int64_t)__%s_hash_recursive(NULL);", tn_, tn_); emit(2, "__%s_hash_computed = 1;", tn_); emit(1, "}"); emit(0, ""); emit(1, "return __%s_hash;", tn_); emit(0, "}"); emit(0, ""); }
static void emit_c_decode_cleanup(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int %s_decode_cleanup(%s *p)", tn_, tn_); emit(0,"{"); emit(1, "return __%s_decode_array_cleanup(p, 1);", tn_); emit(0,"}"); emit(0,""); }
static void emit_c_num_fields(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int %s_num_fields(void)", tn_); emit(0,"{"); emit(1, "return %d;", g_ptr_array_size(ls->members)); emit(0,"}"); emit(0,""); }
static void emit_c_struct_size(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"size_t %s_struct_size(void)", tn_); emit(0,"{"); emit(1, "return sizeof(%s);", tn_); emit(0,"}"); emit(0,""); }
static void emit_c_encoded_size(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int %s_encoded_size(const %s *p)", tn_, tn_); emit(0,"{"); emit(1, "return 8 + __%s_encoded_array_size(p, 1);", tn_); emit(0,"}"); emit(0,""); }
static void emit_c_destroy(lcmgen_t *lcm, FILE *f, lcm_struct_t *lr) { char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"void %s_destroy(%s *p)", tn_, tn_); emit(0,"{"); emit(1, "__%s_decode_array_cleanup(p, 1);", tn_); emit(1, "free(p);"); emit(0,"}"); emit(0,""); }
// Some types do not have a 1:1 mapping from lcm types to native C // storage types. Do not free the string pointers returned by this // function. static const char *map_type_name(const char *t) { if (!strcmp(t,"boolean")) return "int8_t"; if (!strcmp(t,"string")) return "char*"; if (!strcmp(t,"byte")) return "uint8_t"; return dots_to_underscores (t); }
static void emit_c_copy(lcmgen_t *lcm, FILE *f, lcm_struct_t *lr) { char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"%s *%s_copy(const %s *p)", tn_, tn_, tn_); emit(0,"{"); emit(1, "%s *q = (%s*) malloc(sizeof(%s));", tn_, tn_, tn_); emit(1, "__%s_clone_array(p, q, 1);", tn_); emit(1, "return q;"); emit(0,"}"); emit(0,""); }
static void emit_c_struct_publish(lcmgen_t *lcm, FILE *f, lcm_struct_t *lr) { char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); fprintf(f, "int %s_publish(lcm_t *lc, const char *channel, const %s *p)\n" "{\n" " int max_data_size = %s_encoded_size (p);\n" " uint8_t *buf = (uint8_t*) malloc (max_data_size);\n" " if (!buf) return -1;\n" " int data_size = %s_encode (buf, 0, max_data_size, p);\n" " if (data_size < 0) {\n" " free (buf);\n" " return data_size;\n" " }\n" " int status = lcm_publish (lc, channel, buf, data_size);\n" " free (buf);\n" " return status;\n" "}\n\n", tn_, tn_, tn_, tn_); }
static void emit_c_encode(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int %s_encode(void *buf, int offset, int maxlen, const %s *p)", tn_, tn_); emit(0,"{"); emit(1, "int pos = 0, thislen;"); emit(1, "int64_t hash = __%s_get_hash();", tn_); emit(0,""); emit(1, "thislen = __int64_t_encode_array(buf, offset + pos, maxlen - pos, &hash, 1);"); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(0,""); emit(1, "thislen = __%s_encode_array(buf, offset + pos, maxlen - pos, p, 1);", tn_); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(0,""); emit(1, "return pos;"); emit(0,"}"); emit(0,""); }
static void emit_c_get_type_info(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"const lcm_type_info_t *%s_get_type_info(void)", tn_); emit(0,"{"); emit(1,"static int init = 0;"); emit(1,"static lcm_type_info_t typeinfo;"); emit(1,"if (!init) {"); emit(2,"typeinfo.encode = (lcm_encode_t) %s_encode;", tn_); emit(2,"typeinfo.decode = (lcm_decode_t) %s_decode;", tn_); emit(2,"typeinfo.decode_cleanup = (lcm_decode_cleanup_t) %s_decode_cleanup;", tn_); emit(2,"typeinfo.encoded_size = (lcm_encoded_size_t) %s_encoded_size;", tn_); emit(2,"typeinfo.struct_size = (lcm_struct_size_t) %s_struct_size;", tn_); emit(2,"typeinfo.num_fields = (lcm_num_fields_t) %s_num_fields;", tn_); emit(2,"typeinfo.get_field = (lcm_get_field_t) %s_get_field;", tn_); emit(2,"typeinfo.get_hash = (lcm_get_hash_t) __%s_get_hash;", tn_); emit(1,"}"); emit(1,""); emit(1,"return &typeinfo;"); emit(0,"}"); }
static void emit_c_struct_subscribe(lcmgen_t *lcm, FILE *f, lcm_struct_t *lr) { const char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); fprintf(f, "struct _%s_subscription_t {\n" " %s_handler_t user_handler;\n" " void *userdata;\n" // " char *channel;\n" " lcm_subscription_t *lc_h;\n" "};\n", tn_, tn_); fprintf(f, "static\n" "void %s_handler_stub (const lcm_recv_buf_t *rbuf,\n" " const char *channel, void *userdata)\n" "{\n" " int status;\n" " %s p;\n" " memset(&p, 0, sizeof(%s));\n" " status = %s_decode (rbuf->data, 0, rbuf->data_size, &p);\n" " if (status < 0) {\n" " fprintf (stderr, \"error %%d decoding %s!!!\\n\", status);\n" " return;\n" " }\n" "\n" " %s_subscription_t *h = (%s_subscription_t*) userdata;\n" " h->user_handler (rbuf, channel, &p, h->userdata);\n" "\n" " %s_decode_cleanup (&p);\n" "}\n\n", tn_, tn_, tn_, tn_, tn_, tn_, tn_, tn_ ); fprintf(f, "%s_subscription_t* %s_subscribe (lcm_t *lcm,\n" " const char *channel,\n" " %s_handler_t f, void *userdata)\n" "{\n" // " int chan_len = strlen (channel) + 1;\n" " %s_subscription_t *n = (%s_subscription_t*)\n" " malloc(sizeof(%s_subscription_t));\n" " n->user_handler = f;\n" " n->userdata = userdata;\n" // " n->channel = (char*) malloc (chan_len);\n" // " memcpy (n->channel, channel, chan_len);\n" " n->lc_h = lcm_subscribe (lcm, channel,\n" " %s_handler_stub, n);\n" " if (n->lc_h == NULL) {\n" " fprintf (stderr,\"couldn't reg %s LCM handler!\\n\");\n" " free (n);\n" " return NULL;\n" " }\n" " return n;\n" "}\n\n", tn_, tn_, tn_, tn_, tn_, tn_, tn_, tn_ ); fprintf(f, "int %s_subscription_set_queue_capacity (%s_subscription_t* subs,\n" " int num_messages)\n" "{\n" " return lcm_subscription_set_queue_capacity (subs->lc_h, num_messages);\n" "}\n\n", tn_, tn_); fprintf(f, "int %s_unsubscribe(lcm_t *lcm, %s_subscription_t* hid)\n" "{\n" " int status = lcm_unsubscribe (lcm, hid->lc_h);\n" " if (0 != status) {\n" " fprintf(stderr,\n" " \"couldn't unsubscribe %s_handler %%p!\\n\", hid);\n" " return -1;\n" " }\n" // " free (hid->channel);\n" " free (hid);\n" " return 0;\n" "}\n\n", tn_, tn_, tn_ ); }
int emit_struct(lcmgen_t *lcmgen, lcm_struct_t *lr) { char *tn = lr->structname->lctypename; char *tn_ = dots_to_underscores(tn); char *header_name = g_strdup_printf("%s/%s.h", getopt_get_string(lcmgen->gopt, "c-hpath"), tn_); char *c_name = g_strdup_printf("%s/%s.c", getopt_get_string(lcmgen->gopt, "c-cpath"), tn_); if (lcm_needs_generation(lcmgen, lr->lcmfile, header_name)) { FILE *f = fopen(header_name, "w"); if (f == NULL) return -1; emit_header_top(lcmgen, f, tn_); emit_header_struct(lcmgen, f, lr); emit_header_prototypes(lcmgen, f, lr); emit_header_bottom(lcmgen, f); fclose(f); } // STRUCT C file if (lcm_needs_generation(lcmgen, lr->lcmfile, c_name)) { FILE *f = fopen(c_name, "w"); if (f == NULL) return -1; emit_auto_generated_warning(f); fprintf(f, "#include <string.h>\n"); fprintf(f, "#include \"%s%s%s.h\"\n", getopt_get_string(lcmgen->gopt, "cinclude"), strlen(getopt_get_string(lcmgen->gopt, "cinclude"))>0 ? "/" : "", tn_); fprintf(f, "\n"); emit_c_struct_get_hash(lcmgen, f, lr); emit_c_encode_array(lcmgen, f, lr); emit_c_encode(lcmgen, f, lr); emit_c_encoded_array_size(lcmgen, f, lr); emit_c_encoded_size(lcmgen, f, lr); if(getopt_get_bool(lcmgen->gopt, "c-typeinfo")) { emit_c_struct_size(lcmgen, f, lr); emit_c_num_fields(lcmgen, f, lr); emit_c_get_field(lcmgen, f, lr); emit_c_get_type_info(lcmgen, f, lr); } emit_c_decode_array(lcmgen, f, lr); emit_c_decode_array_cleanup(lcmgen, f, lr); emit_c_decode(lcmgen, f, lr); emit_c_decode_cleanup(lcmgen, f, lr); emit_c_clone_array(lcmgen, f, lr); emit_c_copy(lcmgen, f, lr); emit_c_destroy(lcmgen, f, lr); if(!getopt_get_bool(lcmgen->gopt, "c-no-pubsub")) { emit_c_struct_publish(lcmgen, f, lr ); emit_c_struct_subscribe(lcmgen, f, lr ); } fclose(f); } return 0; }
/** Emit header file output specific to a particular type of struct. **/ static void emit_header_struct(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); char *tn_upper = g_utf8_strup(tn_, -1); // include header files required by members for (unsigned int i = 0; i < g_ptr_array_size(ls->members); i++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, i); if (!lcm_is_primitive_type(lm->type->lctypename) && strcmp(lm->type->lctypename, ls->structname->lctypename)) { char *other_tn = dots_to_underscores (lm->type->lctypename); fprintf(f, "#include \"%s%s%s.h\"\n", getopt_get_string(lcm->gopt, "cinclude"), strlen(getopt_get_string(lcm->gopt, "cinclude"))>0 ? "/" : "", other_tn); free (other_tn); } } // output constants for (unsigned int i = 0; i < g_ptr_array_size(ls->constants); i++) { lcm_constant_t *lc = (lcm_constant_t *) g_ptr_array_index(ls->constants, i); assert(lcm_is_legal_const_type(lc->lctypename)); const char *suffix = ""; if (!strcmp(lc->lctypename, "int64_t")) { suffix = "LL"; } emit_comment(f, 0, lc->comment); emit(0, "#define %s_%s %s%s", tn_upper, lc->membername, lc->val_str, suffix); } if (g_ptr_array_size(ls->constants) > 0) { emit(0, ""); } // define the struct emit_comment(f, 0, ls->comment); emit(0, "typedef struct _%s %s;", tn_, tn_); emit(0, "struct _%s", tn_); emit(0, "{"); for (unsigned int m = 0; m < g_ptr_array_size(ls->members); m++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, m); emit_comment(f, 1, lm->comment); int ndim = g_ptr_array_size(lm->dimensions); if (ndim == 0) { emit(1, "%-10s %s;", map_type_name(lm->type->lctypename), lm->membername); } else { if (lcm_is_constant_size_array(lm)) { emit_start(1, "%-10s %s", map_type_name(lm->type->lctypename), lm->membername); for (unsigned int d = 0; d < ndim; d++) { lcm_dimension_t *ld = (lcm_dimension_t *) g_ptr_array_index(lm->dimensions, d); emit_continue("[%s]", ld->size); } emit_end(";"); } else { emit_start(1, "%-10s ", map_type_name(lm->type->lctypename)); for (unsigned int d = 0; d < ndim; d++) emit_continue("*"); emit_end("%s;", lm->membername); } } } emit(0, "};"); emit(0, ""); free(tn_); g_free(tn_upper); }
static void emit_c_get_field(lcmgen_t *lcm, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0,"int %s_get_field(const %s *p, int i, lcm_field_t *f)", tn_, tn_); emit(0,"{"); emit(1,"if (0 > i || i >= %s_num_fields())", tn_); emit(2,"return 1;"); emit(1,""); emit(1,"switch (i) {"); emit(1,""); int num_fields = g_ptr_array_size(ls->members); for(int i = 0; i < num_fields; i++) { emit(2,"case %d: {", i); lcm_member_t *m = (lcm_member_t *)g_ptr_array_index(ls->members, i); const char *type_val = NULL; if(lcm_is_primitive_type(m->type->shortname)) { type_val = str_toupper(g_strdup_printf("LCM_FIELD_%s", m->type->shortname)); } else { emit(3,"/* %s */", m->type->shortname); type_val = "LCM_FIELD_USER_TYPE"; } emit(3,"f->name = \"%s\";", m->membername); emit(3,"f->type = %s;", type_val); emit(3,"f->typestr = \"%s\";", m->type->shortname); int num_dim = g_ptr_array_size(m->dimensions); emit(3,"f->num_dim = %d;", num_dim); if(num_dim != 0) { for(int j = 0; j < num_dim; j++) { lcm_dimension_t *d = (lcm_dimension_t*) g_ptr_array_index(m->dimensions, j); if(d->mode == LCM_VAR) emit(3,"f->dim_size[%d] = p->%s;", j, d->size); else emit(3,"f->dim_size[%d] = %s;", j, d->size); } for(int j = 0; j < num_dim; j++) { lcm_dimension_t *d = (lcm_dimension_t*) g_ptr_array_index(m->dimensions, j); emit(3,"f->dim_is_variable[%d] = %d;", j, d->mode == LCM_VAR); } } emit(3, "f->data = (void *) &p->%s;", m->membername); emit(3, "return 0;"); emit(2,"}"); emit(2,""); } emit(2,"default:"); emit(3,"return 1;"); emit(1,"}"); emit(0,"}"); emit(0,""); }
static void emit_header_prototypes(lcmgen_t *lcmgen, FILE *f, lcm_struct_t *ls) { char *xd = getopt_get_string(lcmgen->gopt, "c-export-symbol"); char *xd_ = add_space_or_empty(xd); char *tn = ls->structname->lctypename; char *tn_ = dots_to_underscores(tn); emit(0, "/**"); emit(0, " * Create a deep copy of a %s.", tn_); emit(0, " * When no longer needed, destroy it with %s_destroy()", tn_); emit(0, " */"); emit(0,"%s%s* %s_copy(const %s* to_copy);", xd_, tn_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Destroy an instance of %s created by %s_copy()", tn_, tn_); emit(0, " */"); emit(0,"%svoid %s_destroy(%s* to_destroy);", xd_, tn_, tn_); emit(0,""); if (!getopt_get_bool(lcmgen->gopt, "c-no-pubsub")) { emit(0, "/**"); emit(0, " * Identifies a single subscription. This is an opaque data type."); emit(0, " */"); emit(0,"typedef struct _%s_subscription_t %s_subscription_t;", tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Prototype for a callback function invoked when a message of type"); emit(0, " * %s is received.", tn_); emit(0, " */"); emit(0,"typedef void(*%s_handler_t)(const lcm_recv_buf_t *rbuf,\n" " const char *channel, const %s *msg, void *userdata);", tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Publish a message of type %s using LCM.", tn_); emit(0, " *"); emit(0, " * @param lcm The LCM instance to publish with."); emit(0, " * @param channel The channel to publish on."); emit(0, " * @param msg The message to publish."); emit(0, " * @return 0 on success, <0 on error. Success means LCM has transferred"); emit(0, " * responsibility of the message data to the OS."); emit(0, " */"); emit(0,"%sint %s_publish(lcm_t *lcm, const char *channel, const %s *msg);", xd_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Subscribe to messages of type %s using LCM.", tn_); emit(0, " *"); emit(0, " * @param lcm The LCM instance to subscribe with."); emit(0, " * @param channel The channel to subscribe to."); emit(0, " * @param handler The callback function invoked by LCM when a message is received."); emit(0, " * This function is invoked by LCM during calls to lcm_handle() and"); emit(0, " * lcm_handle_timeout()."); emit(0, " * @param userdata An opaque pointer passed to @p handler when it is invoked."); emit(0, " * @return 0 on success, <0 if an error occured"); emit(0, " */"); emit(0,"%s%s_subscription_t* %s_subscribe(lcm_t *lcm, const char *channel, %s_handler_t handler, void *userdata);", xd_, tn_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Removes and destroys a subscription created by %s_subscribe()", tn_); emit(0, " */"); emit(0,"%sint %s_unsubscribe(lcm_t *lcm, %s_subscription_t* hid);", xd_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Sets the queue capacity for a subscription."); emit(0, " * Some LCM providers (e.g., the default multicast provider) are implemented"); emit(0, " * using a background receive thread that constantly revceives messages from"); emit(0, " * the network. As these messages are received, they are buffered on"); emit(0, " * per-subscription queues until dispatched by lcm_handle(). This function"); emit(0, " * how many messages are queued before dropping messages."); emit(0, " *"); emit(0, " * @param subs the subscription to modify."); emit(0, " * @param num_messages The maximum number of messages to queue"); emit(0, " * on the subscription."); emit(0, " * @return 0 on success, <0 if an error occured"); emit(0, " */"); emit(0,"%sint %s_subscription_set_queue_capacity(%s_subscription_t* subs,\n" " int num_messages);\n", xd_, tn_, tn_); } emit(0, "/**"); emit(0, " * Encode a message of type %s into binary form.", tn_); emit(0, " *"); emit(0, " * @param buf The output buffer."); emit(0, " * @param offset Encoding starts at this byte offset into @p buf."); emit(0, " * @param maxlen Maximum number of bytes to write. This should generally"); emit(0, " * be equal to %s_encoded_size().", tn_); emit(0, " * @param msg The message to encode."); emit(0, " * @return The number of bytes encoded, or <0 if an error occured."); emit(0, " */"); emit(0,"%sint %s_encode(void *buf, int offset, int maxlen, const %s *p);", xd_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Decode a message of type %s from binary form.", tn_); emit(0, " * When decoding messages containing strings or variable-length arrays, this"); emit(0, " * function may allocate memory. When finished with the decoded message,"); emit(0, " * release allocated resources with %s_decode_cleanup().", tn_); emit(0, " *"); emit(0, " * @param buf The buffer containing the encoded message"); emit(0, " * @param offset The byte offset into @p buf where the encoded message starts."); emit(0, " * @param maxlen The maximum number of bytes to read while decoding."); emit(0, " * @param msg Output parameter where the decoded message is stored"); emit(0, " * @return The number of bytes decoded, or <0 if an error occured."); emit(0, " */"); emit(0,"%sint %s_decode(const void *buf, int offset, int maxlen, %s *msg);", xd_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Release resources allocated by %s_decode()", tn_); emit(0, " * @return 0"); emit(0, " */"); emit(0,"%sint %s_decode_cleanup(%s *p);", xd_, tn_, tn_); emit(0, ""); emit(0, "/**"); emit(0, " * Check how many bytes are required to encode a message of type %s", tn_); emit(0, " */"); emit(0,"%sint %s_encoded_size(const %s *p);", xd_, tn_, tn_); if(getopt_get_bool(lcmgen->gopt, "c-typeinfo")) { emit(0,"%ssize_t %s_struct_size(void);", xd_, tn_); emit(0,"%sint %s_num_fields(void);", xd_, tn_); emit(0,"%sint %s_get_field(const %s *p, int i, lcm_field_t *f);", xd_, tn_, tn_); emit(0,"%sconst lcm_type_info_t *%s_get_type_info(void);", xd_, tn_); } emit(0,""); emit(0,"// LCM support functions. Users should not call these"); emit(0,"%sint64_t __%s_get_hash(void);", xd_, tn_); emit(0,"%suint64_t __%s_hash_recursive(const __lcm_hash_ptr *p);", xd_, tn_); emit(0,"%sint __%s_encode_array(void *buf, int offset, int maxlen, const %s *p, int elements);", xd_, tn_, tn_); emit(0,"%sint __%s_decode_array(const void *buf, int offset, int maxlen, %s *p, int elements);", xd_, tn_, tn_); emit(0,"%sint __%s_decode_array_cleanup(%s *p, int elements);", xd_, tn_, tn_); emit(0,"%sint __%s_encoded_array_size(const %s *p, int elements);", xd_, tn_, tn_); emit(0,"%sint __%s_clone_array(const %s *p, %s *q, int elements);", xd_, tn_, tn_, tn_); emit(0,""); }
int emit_enum(lcmgen_t *lcmgen, lcm_enum_t *le) { char *tn = le->enumname->lctypename; char *tn_ = dots_to_underscores(tn); char *header_name = g_strdup_printf("%s/%s.h", getopt_get_string(lcmgen->gopt, "c-hpath"), tn_); char *c_name = g_strdup_printf("%s/%s.c", getopt_get_string(lcmgen->gopt, "c-cpath"), tn_); // ENUM header file if (lcm_needs_generation(lcmgen, le->lcmfile, header_name)) { FILE *f = fopen(header_name, "w"); if (f == NULL) return -1; emit_header_top(lcmgen, f, tn_); char *tn_upper = g_ascii_strup (tn_, strlen (tn_)); /////////////////////////////////////////////////////////////////// // the enum declaration itself emit(0, "enum _%s {", tn_); for (unsigned int i = 0; i < g_ptr_array_size(le->values); i++) { lcm_enum_value_t *lev = (lcm_enum_value_t *) g_ptr_array_index(le->values, i); emit(1," %s_%s = %d%s", tn_upper, lev->valuename, lev->value, i==(g_ptr_array_size(le->values)-1) ? "" : ","); } free (tn_upper); emit(0, "};"); emit(0, ""); emit(0, "typedef enum _%s %s;", tn_, tn_); emit(0, ""); emit(0, "const char * %s_name(%s val);", tn_, tn_); emit(0, ""); /////////////////////////////////////////////////////////////////// emit(0, "static inline int64_t __%s_hash_recursive(const __lcm_hash_ptr *p)", tn_); emit(0, "{"); emit(1, "return 0x%016"PRIx64"LL;", le->hash); emit(0, "}"); emit(0, ""); emit(0, "static inline int64_t __%s_get_hash()", tn_); emit(0, "{"); emit(1, "return 0x%016"PRIx64"LL;", le->hash); emit(0, "}"); emit(0, ""); // enums are always "ints", but "ints" are not always int32_t. We // always store an enum as an int32_t, however. Consequently, we // jump through some hoops here in order to allow the compiler to // convert from an int32_t to whatever the native size of "int" // is. emit(0, "static inline int __%s_encode_array(void *_buf, int offset, int maxlen, const %s *p, int elements)", tn_, tn_); emit(0, "{"); emit(1, "int pos = 0, thislen, element;"); emit(1, "for (element = 0; element < elements; element++) {"); emit(2, "int32_t v = (int32_t) p[element];"); emit(2, "thislen = __int32_t_encode_array(_buf, offset + pos, maxlen - pos, &v, 1);"); emit(2, "if (thislen < 0) return thislen; else pos += thislen;"); emit(1, "}"); emit(1, "return thislen;"); emit(0, "}"); emit(0, ""); emit(0,"static inline int %s_encode(void *buf, int offset, int maxlen, const %s *p)", tn_, tn_); emit(0,"{"); emit(1, "int pos = 0, thislen;"); emit(1, "int64_t hash = 0x%016"PRIx64"LL;", le->hash); emit(0,""); emit(1, "thislen = __int64_t_encode_array(buf, offset + pos, maxlen - pos, &hash, 1);"); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(0,""); emit(1, "thislen = __%s_encode_array(buf, offset + pos, maxlen - pos, p, 1);", tn_); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(0,""); emit(1, "return pos;"); emit(0,"}"); emit(0,""); emit(0, "static inline int __%s_decode_array(const void *_buf, int offset, int maxlen, %s *p, int elements)", tn_, tn_); emit(0, "{"); emit(1, "int pos = 0, thislen, element;"); emit(1, "for (element = 0; element < elements; element++) {"); emit(2, "int32_t v;"); emit(2, "thislen = __int32_t_decode_array(_buf, offset + pos, maxlen - pos, &v, 1);"); emit(2, "if (thislen < 0) return thislen; else pos += thislen;"); emit(2, "p[element] = (%s) v;", tn_); emit(1, "}"); emit(1, "return thislen;"); emit(0, "}"); emit(0, ""); emit(0, "static inline int __%s_clone_array(const %s *p, %s *q, int elements)", tn_, tn_, tn_); emit(0, "{"); emit(1, "memcpy(q, p, elements * sizeof(%s));", tn_); emit(1, "return 0;"); emit(0, "}"); emit(0, ""); emit(0,"static inline int %s_decode(const void *buf, int offset, int maxlen, %s *p)", tn_, tn_); emit(0,"{"); emit(1, "int pos = 0, thislen;"); emit(1, "int64_t hash = 0x%016"PRIx64"LL;", le->hash); emit(0,""); emit(1, "int64_t this_hash;"); emit(1, "thislen = __int64_t_decode_array(buf, offset + pos, maxlen - pos, &this_hash, 1);"); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(1, "if (this_hash != hash) return -1;"); emit(0,""); emit(1, "thislen = __%s_decode_array(buf, offset + pos, maxlen - pos, p, 1);", tn_); emit(1, "if (thislen < 0) return thislen; else pos += thislen;"); emit(0,""); emit(1, "return pos;"); emit(0,"}"); emit(0,""); emit(0, "static inline int __%s_decode_array_cleanup(%s *in, int elements)", tn_, tn_); emit(0, "{"); emit(1, "return 0;"); emit(0, "}"); emit(0, ""); emit(0,"static inline int %s_decode_cleanup(%s *p)", tn_, tn_); emit(0,"{"); emit(1, "return 0;"); emit(0,"}"); emit(0,""); emit(0, "static inline int __%s_encoded_array_size(const %s *p, int elements)", tn_, tn_); emit(0, "{"); emit(1, "return __int32_t_encoded_array_size((const int32_t*)p, elements);"); emit(0, "}"); emit(0, ""); emit(0, "static inline int %s_encoded_size(const %s *in)", tn_, tn_); emit(0, "{"); emit(1, "return int32_t_encoded_size((const int32_t*)in);"); emit(0, "}"); emit(0, ""); emit_header_bottom(lcmgen, f); fclose(f); } // ENUM C file if (lcm_needs_generation(lcmgen, le->lcmfile, c_name)) { char *tn_upper = g_ascii_strup (tn_, strlen (tn_)); FILE *f = fopen(c_name, "w"); emit_auto_generated_warning(f); fprintf(f, "#include \"%s%s%s.h\"\n", getopt_get_string(lcmgen->gopt, "cinclude"), strlen(getopt_get_string(lcmgen->gopt, "cinclude"))>0 ? "/" : "", tn_); emit(0, "const char * %s_name(%s val)", tn_, tn_); emit(0, "{"); emit(1, "switch (val) {"); for (unsigned int i = 0; i < g_ptr_array_size(le->values); i++) { lcm_enum_value_t *lev = (lcm_enum_value_t *) g_ptr_array_index(le->values, i); emit(2, "case %s_%s:", tn_upper, lev->valuename); emit(3, "return \"%s\";", lev->valuename); } emit(2, "default:"); emit(3, "return NULL;"); emit(1, "}"); emit(0, "}"); fclose(f); free (tn_upper); } return 0; }
/** Emit header file **/ static void emit_header_start(lcmgen_t *lcmgen, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *sn = ls->structname->shortname; char *tn_ = dots_to_underscores(tn); emit_auto_generated_warning(f); fprintf(f, "#include <lcm/lcm_coretypes.h>\n"); fprintf(f, "\n"); fprintf(f, "#ifndef __%s_hpp__\n", tn_); fprintf(f, "#define __%s_hpp__\n", tn_); fprintf(f, "\n"); // do we need to #include <vector> ? int emit_include_vector = 0; for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *)g_ptr_array_index(ls->members, mind); if (g_ptr_array_size(lm->dimensions) != 0 && !lcm_is_constant_size_array(lm) && !emit_include_vector) { emit(0, "#include <vector>"); emit_include_vector = 1; } } emit(0, "#include <cmath>\t// For fabs to compare floats"); emit(0, "#include <string>\t// For return type of toStr()"); emit(0, "#include <sstream>\t// For stringstream in toStr()"); // include header files for other LCM types for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, mind); if (!lcm_is_primitive_type(lm->type->lctypename) && strcmp(lm->type->lctypename, ls->structname->lctypename)) { char *other_tn = dots_to_slashes (lm->type->lctypename); emit(0, "#include \"%s%s%s.hpp\"", getopt_get_string(lcmgen->gopt, "cpp-include"), strlen(getopt_get_string(lcmgen->gopt, "cpp-include"))>0 ? G_DIR_SEPARATOR_S : "", other_tn); free(other_tn); } } fprintf(f, "\n"); emit_package_namespace_start(lcmgen, f, ls); // define the class emit(0, ""); emit_comment(f, 0, ls->comment); emit(0, "class %s", sn); emit(0, "{"); // data members if(g_ptr_array_size(ls->members)) { emit(1, "public:"); for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, mind); emit_comment(f, 2, lm->comment); char const* mapped_typename = map_type_name(lm->type->lctypename); int ndim = g_ptr_array_size(lm->dimensions); if (ndim == 0) { emit(2, "%-10s %s;", mapped_typename, lm->membername); } else { if (lcm_is_constant_size_array(lm)) { emit_start(2, "%-10s %s", mapped_typename, lm->membername); for (unsigned int d = 0; d < ndim; d++) { lcm_dimension_t *ld = (lcm_dimension_t *) g_ptr_array_index(lm->dimensions, d); emit_continue("[%s]", ld->size); } emit_end(";"); } else { emit_start(2, ""); for (unsigned int d = 0; d < ndim; d++) emit_continue("std::vector< "); emit_continue("%s", mapped_typename); for (unsigned int d = 0; d < ndim; d++) emit_continue(" >"); emit_end(" %s;", lm->membername); } } if (mind < g_ptr_array_size(ls->members) - 1) { emit(0, ""); } } emit(0, ""); } // constants if (g_ptr_array_size(ls->constants) > 0) { emit(1, "public:"); for (unsigned int i = 0; i < g_ptr_array_size(ls->constants); i++) { lcm_constant_t *lc = (lcm_constant_t *) g_ptr_array_index(ls->constants, i); assert(lcm_is_legal_const_type(lc->lctypename)); emit_comment(f, 2, lc->comment); // For int32_t only, we emit enums instead of static const // values because the former can be passed by reference while // the latter cannot. if (!strcmp(lc->lctypename, "int32_t")) { emit(2, "enum { %s = %s };", lc->membername, lc->val_str); } else { const char *suffix = ""; if (!strcmp(lc->lctypename, "int64_t")) suffix = "LL"; char const* mapped_typename = map_type_name(lc->lctypename); char *cpp_std = getopt_get_string(lcmgen->gopt, "cpp-std"); if(strcmp("c++98",cpp_std) && strcmp("c++11",cpp_std)) { printf("%s is not a valid cpp_std. Use --cpp-std=c++98 or --cpp-std=c++11 instead\n\n", cpp_std); fflush(stdout); _exit(1); } if(!strcmp (cpp_std, "c++11")) { emit(2, "static constexpr %-8s %s = %s%s;", mapped_typename, lc->membername, lc->val_str, suffix); } else { emit(2, "// If you're using C++11 and are getting compiler errors saying things like"); emit(2, "// ‘constexpr’ needed for in-class initialization of static data member"); emit(2, "// then re-run lcm-gen with '--cpp-std=c++11' to generate code that is"); emit(2, "// compliant with C++11"); emit(2, "static const %-8s %s = %s%s;", mapped_typename, lc->membername, lc->val_str, suffix); } } } emit(0, ""); } emit(1, "public:"); emit(2, "/**"); emit(2, " * Encode a message into binary form."); emit(2, " *"); emit(2, " * @param buf The output buffer."); emit(2, " * @param offset Encoding starts at thie byte offset into @p buf."); emit(2, " * @param maxlen Maximum number of bytes to write. This should generally be"); emit(2, " * equal to getEncodedSize()."); emit(2, " * @return The number of bytes encoded, or <0 on error."); emit(2, " */"); emit(2, "inline int encode(void *buf, int offset, int maxlen) const;"); emit(0, ""); emit(2, "/**"); emit(2, " * Check how many bytes are required to encode this message."); emit(2, " */"); emit(2, "inline int getEncodedSize() const;"); emit(0, ""); emit(2, "/**"); emit(2, " * Decode a message from binary form into this instance."); emit(2, " *"); emit(2, " * @param buf The buffer containing the encoded message."); emit(2, " * @param offset The byte offset into @p buf where the encoded message starts."); emit(2, " * @param maxlen The maximum number of bytes to reqad while decoding."); emit(2, " * @return The number of bytes decoded, or <0 if an error occured."); emit(2, " */"); emit(2, "inline int decode(const void *buf, int offset, int maxlen);"); emit(0, ""); emit(2, "/**"); emit(2, " * Compare two instances of the same type."); emit(2, " *"); emit(2, " * @param[in] other The object to compare."); emit(2, " * @return true if all elements are equal, false otherwise."); emit(2, " */"); emit(2, "inline bool operator==(%s const & other) const;", sn); emit(0, ""); emit(2, "/**"); emit(2, " * Construct a string from the object for debugging purposes."); emit(2, " * Note that arrays are cropped for readability. Only the first and last elements are shown."); emit(2, " *"); emit(2, " * @param[in] layout A placeholder for the tree structure."); emit(2, " */"); emit(2, "inline std::string toDebugStr(std::string const & layout=\"|-\") const;"); emit(0, ""); emit(2, "/**"); emit(2, " * Initialize all values of a test object to pre-defined values."); emit(2, " * The values used are much more informative than using 0 because"); emit(2, " * they are type-dependant. This way, the user knows directly whether"); emit(2, " * the type is correct or not. Typically the default values are the"); emit(2, " * maximum value allowed by the type minus 5, and 1.0 for float and double."); emit(2, " * Note that for arrays only the first and last elements are considered."); emit(2, " *"); emit(2, " * @return success."); emit(2, " */"); emit(2, "inline bool initTestObject();"); emit(0, ""); emit(2, "/**"); emit(2, " * Increment every variable in the object."); emit(2, " * Works well with initTestObject() and compareTestObject()."); emit(2, " * Note that for arrays only the first and last elements are considered."); emit(2, " *"); emit(2, " * @return success."); emit(2, " */"); emit(2, "inline bool incTestObject();"); emit(0, ""); emit(2, "/**"); emit(2, " * Compare two instances of the same type."); emit(2, " * Works well with initTestObject() and incTestObject()."); emit(2, " * Note that for arrays only the first and last elements are considered."); emit(2, " *"); emit(2, " * @param[in] other The object to compare."); emit(2, " * @return true if all elements are equal, false otherwise."); emit(2, " */"); emit(2, "inline bool compareTestObject(%s const & other) const;", sn); emit(0, ""); emit(2, "/**"); emit(2, " * Retrieve the 64-bit fingerprint identifying the structure of the message."); emit(2, " * Note that the fingerprint is the same for all instances of the same"); emit(2, " * message type, and is a fingerprint on the message type definition, not on"); emit(2, " * the message contents."); emit(2, " */"); emit(2, "inline static int64_t getHash();"); emit(0, ""); emit(2, "/**"); emit(2, " * Returns \"%s\"", ls->structname->shortname); emit(2, " */"); emit(2, "inline static const char* getTypeName();"); emit(0, ""); emit(2, "// LCM support functions. Users should not call these"); emit(2, "inline int _encodeNoHash(void *buf, int offset, int maxlen) const;"); emit(2, "inline int _getEncodedSizeNoHash() const;"); emit(2, "inline int _decodeNoHash(const void *buf, int offset, int maxlen);"); emit(2, "inline static uint64_t _computeHash(const __lcm_hash_ptr *p);"); emit(0, "};"); emit(0, ""); free(tn_); }
/** Emit header file **/ static void emit_header_start(lcmgen_t *lcmgen, FILE *f, lcm_struct_t *ls) { char *tn = ls->structname->lctypename; char *sn = ls->structname->shortname; char *tn_ = dots_to_underscores(tn); emit_auto_generated_warning(f); fprintf(f, "#include <lcm/lcm_coretypes.h>\n"); fprintf(f, "\n"); fprintf(f, "#ifndef __%s_hpp__\n", tn_); fprintf(f, "#define __%s_hpp__\n", tn_); fprintf(f, "\n"); // do we need to #include <vector> and/or <string>? int emit_include_vector = 0; int emit_include_string = 0; for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *)g_ptr_array_index(ls->members, mind); if (g_ptr_array_size(lm->dimensions) != 0 && !lcm_is_constant_size_array(lm) && !emit_include_vector) { emit(0, "#include <vector>"); emit_include_vector = 1; } if(!emit_include_string && !strcmp(lm->type->lctypename, "string")) { emit(0, "#include <string>"); emit_include_string = 1; } } // include header files for other LCM types for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, mind); if (!lcm_is_primitive_type(lm->type->lctypename) && strcmp(lm->type->lctypename, ls->structname->lctypename)) { char *other_tn = dots_to_slashes (lm->type->lctypename); emit(0, "#include \"%s%s%s.hpp\"", getopt_get_string(lcmgen->gopt, "cpp-include"), strlen(getopt_get_string(lcmgen->gopt, "cpp-include"))>0 ? G_DIR_SEPARATOR_S : "", other_tn); free(other_tn); } } fprintf(f, "\n"); emit_package_namespace_start(lcmgen, f, ls); // define the class emit(0, ""); emit_comment(f, 0, ls->comment); emit(0, "class %s", sn); emit(0, "{"); // data members if(g_ptr_array_size(ls->members)) { emit(1, "public:"); for (unsigned int mind = 0; mind < g_ptr_array_size(ls->members); mind++) { lcm_member_t *lm = (lcm_member_t *) g_ptr_array_index(ls->members, mind); emit_comment(f, 2, lm->comment); char* mapped_typename = map_type_name(lm->type->lctypename); int ndim = g_ptr_array_size(lm->dimensions); if (ndim == 0) { emit(2, "%-10s %s;", mapped_typename, lm->membername); } else { if (lcm_is_constant_size_array(lm)) { emit_start(2, "%-10s %s", mapped_typename, lm->membername); for (unsigned int d = 0; d < ndim; d++) { lcm_dimension_t *ld = (lcm_dimension_t *) g_ptr_array_index(lm->dimensions, d); emit_continue("[%s]", ld->size); } emit_end(";"); } else { emit_start(2, ""); for (unsigned int d = 0; d < ndim; d++) emit_continue("std::vector< "); emit_continue("%s", mapped_typename); for (unsigned int d = 0; d < ndim; d++) emit_continue(" >"); emit_end(" %s;", lm->membername); } } free(mapped_typename); if (mind < g_ptr_array_size(ls->members) - 1) { emit(0, ""); } } emit(0, ""); } // constants if (g_ptr_array_size(ls->constants) > 0) { emit(1, "public:"); for (unsigned int i = 0; i < g_ptr_array_size(ls->constants); i++) { lcm_constant_t *lc = (lcm_constant_t *) g_ptr_array_index(ls->constants, i); assert(lcm_is_legal_const_type(lc->lctypename)); emit_comment(f, 2, lc->comment); // For int32_t only, we emit enums instead of static const // values because the former can be passed by reference while // the latter cannot. if (!strcmp(lc->lctypename, "int32_t")) { emit(2, "enum { %s = %s };", lc->membername, lc->val_str); } else { const char *suffix = ""; if (!strcmp(lc->lctypename, "int64_t")) suffix = "LL"; char* mapped_typename = map_type_name(lc->lctypename); emit(2, "static const %-8s %s = %s%s;", mapped_typename, lc->membername, lc->val_str, suffix); free(mapped_typename); } } emit(0, ""); } emit(1, "public:"); emit(2, "/**"); emit(2, " * Encode a message into binary form."); emit(2, " *"); emit(2, " * @param buf The output buffer."); emit(2, " * @param offset Encoding starts at thie byte offset into @p buf."); emit(2, " * @param maxlen Maximum number of bytes to write. This should generally be"); emit(2, " * equal to getEncodedSize()."); emit(2, " * @return The number of bytes encoded, or <0 on error."); emit(2, " */"); emit(2, "inline int encode(void *buf, int offset, int maxlen) const;"); emit(0, ""); emit(2, "/**"); emit(2, " * Check how many bytes are required to encode this message."); emit(2, " */"); emit(2, "inline int getEncodedSize() const;"); emit(0, ""); emit(2, "/**"); emit(2, " * Decode a message from binary form into this instance."); emit(2, " *"); emit(2, " * @param buf The buffer containing the encoded message."); emit(2, " * @param offset The byte offset into @p buf where the encoded message starts."); emit(2, " * @param maxlen The maximum number of bytes to reqad while decoding."); emit(2, " * @return The number of bytes decoded, or <0 if an error occured."); emit(2, " */"); emit(2, "inline int decode(const void *buf, int offset, int maxlen);"); emit(0, ""); emit(2, "/**"); emit(2, " * Retrieve the 64-bit fingerprint identifying the structure of the message."); emit(2, " * Note that the fingerprint is the same for all instances of the same"); emit(2, " * message type, and is a fingerprint on the message type definition, not on"); emit(2, " * the message contents."); emit(2, " */"); emit(2, "inline static int64_t getHash();"); emit(0, ""); emit(2, "/**"); emit(2, " * Returns \"%s\"", ls->structname->shortname); emit(2, " */"); emit(2, "inline static const char* getTypeName();"); emit(0, ""); emit(2, "// LCM support functions. Users should not call these"); emit(2, "inline int _encodeNoHash(void *buf, int offset, int maxlen) const;"); emit(2, "inline int _getEncodedSizeNoHash() const;"); emit(2, "inline int _decodeNoHash(const void *buf, int offset, int maxlen);"); emit(2, "inline static int64_t _computeHash(const __lcm_hash_ptr *p);"); emit(0, "};"); emit(0, ""); free(tn_); }