Index: trunk/scconfig/Rev.h =================================================================== --- trunk/scconfig/Rev.h (revision 37990) +++ trunk/scconfig/Rev.h (revision 37991) @@ -1 +1 @@ -static const int myrev = 37808; +static const int myrev = 37991; Index: trunk/scconfig/Rev.tab =================================================================== --- trunk/scconfig/Rev.tab (revision 37990) +++ trunk/scconfig/Rev.tab (revision 37991) @@ -1,3 +1,4 @@ +37991 configure export_bom2: new bom plugin with templates 37808 configure gsch2pcb-rnd removal 36904 configure enable plugin the order and order_pcbway plugins 36851 configure order plugin: constraint language Index: trunk/scconfig/plugins.h =================================================================== --- trunk/scconfig/plugins.h (revision 37990) +++ trunk/scconfig/plugins.h (revision 37991) @@ -90,6 +90,7 @@ plugin_header("\nExport plugins:\n") plugin_def("cam", "cam/job based export", sbuildin, 1) plugin_def("ddraft", "2D drafting helper", sbuildin, 1) +plugin_def("export_bom2", "Bill of Materials export", sbuildin, 1) plugin_def("export_bom", "bom pcb_exporter", sbuildin, 1) plugin_def("export_c_draw", "export drawing in C code", sdisable, 0) plugin_def("export_debug", "export debug draw", sdisable, 0) Index: trunk/src/Makefile.dep =================================================================== --- trunk/src/Makefile.dep (revision 37990) +++ trunk/src/Makefile.dep (revision 37991) @@ -486,7 +486,7 @@ vtpadstack.h obj_pstk_shape.h polygon.h vtpadstack_t.h change.h board.h \ vtroutestyle.h rats_patch.h undo.h ../src_3rd/libuundo/uundo.h \ undo_old.h -../src_plugins/export_bom/bom.o: ../src_plugins/export_bom/bom.c \ +../src_plugins/export_bom2/bom2.o: ../src_plugins/export_bom2/bom2.c \ ../config.h conf_core.h globalconst.h build_run.h board.h vtroutestyle.h \ attrib.h global_typedefs.h layer.h obj_common.h flag.h data_parent.h \ obj_arc_list.h obj_arc.h obj_line_list.h obj_line.h obj_poly_list.h \ @@ -494,7 +494,12 @@ layer_grp.h rats_patch.h board.h data.h crosshair.h route.h buffer.h \ obj_rat_list.h obj_rat.h idpath.h obj_subc_list.h obj_subc.h \ ../src_3rd/libminuid/libminuid.h ht_subc.h obj_pstk_list.h obj_pstk.h \ - vtpadstack.h obj_pstk_shape.h polygon.h vtpadstack_t.h hid_cam.h + vtpadstack.h obj_pstk_shape.h polygon.h vtpadstack_t.h data_it.h data.h \ + obj_pstk_inlines.h thermal.h operation.h obj_subc_op.h layer.h netlist.h \ + operation.h ../src_plugins/export_bom2/bom2_conf.h hid_cam.h \ + ../src_plugins/lib_compat_help/elem_rot.h \ + ../src_plugins/export_bom2/conf_internal.c \ + ../src_plugins/export_bom2/bom2_conf_fields.h ../src_plugins/export_c_draw/export_c_draw.o: \ ../src_plugins/export_c_draw/export_c_draw.c ../config.h conf_core.h \ globalconst.h board.h vtroutestyle.h attrib.h global_typedefs.h layer.h \ Index: trunk/src_plugins/export_bom2/Makefile =================================================================== --- trunk/src_plugins/export_bom2/Makefile (nonexistent) +++ trunk/src_plugins/export_bom2/Makefile (revision 37991) @@ -0,0 +1,5 @@ +all: + cd ../../src && $(MAKE) mod_export_bom2 + +clean: + rm *.o *.so 2>/dev/null ; true Index: trunk/src_plugins/export_bom2/Plug.tmpasm =================================================================== --- trunk/src_plugins/export_bom2/Plug.tmpasm (nonexistent) +++ trunk/src_plugins/export_bom2/Plug.tmpasm (revision 37991) @@ -0,0 +1,11 @@ +put /local/rnd/mod {export_bom2} +put /local/rnd/mod/OBJS [@ $(PLUGDIR)/export_bom2/bom2.o @] +put /local/rnd/mod/CONF {$(PLUGDIR)/export_bom2/bom2_conf.h} +put /local/rnd/mod/CONFFILE {export_bom2.conf} +put /local/rnd/mod/CONFVAR {export_bom2_conf_internal} + +switch /local/module/export_bom2/controls + case {buildin} include /local/pcb/tmpasm/buildin; end; + case {plugin} include /local/pcb/tmpasm/plugin; end; + case {disable} include /local/pcb/tmpasm/disable; end; +end Index: trunk/src_plugins/export_bom2/bom2.c =================================================================== --- trunk/src_plugins/export_bom2/bom2.c (nonexistent) +++ trunk/src_plugins/export_bom2/bom2.c (revision 37991) @@ -0,0 +1,516 @@ +#include "config.h" +#include "conf_core.h" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "build_run.h" +#include "board.h" +#include "data.h" +#include "data_it.h" +#include +#include +#include +#include +#include +#include +#include "bom2_conf.h" + +#include +#include +#include +#include "hid_cam.h" +#include + +#include "../src_plugins/export_bom2/conf_internal.c" + +#define CONF_FN "export_bom2.conf" + +conf_bom2_t conf_bom2; + +const char *bom2_cookie = "BOM2 HID"; + +/* Maximum length of a template name (in the config file, in the enum) */ +#define MAX_TEMP_NAME_LEN 128 + + +/* This one can not be const because format enumeration is loaded run-time */ +static rnd_export_opt_t bom2_options[] = { + {"bom2file", "Name of the BoM output file", + RND_HATT_STRING, 0, 0, {0, 0, 0}, 0}, +#define HA_bom2file 0 + + {"format", "file format (template)", + RND_HATT_ENUM, 0, 0, {0, 0, 0}, NULL}, +#define HA_format 1 + + {"cam", "CAM instruction", + RND_HATT_STRING, 0, 0, {0, 0, 0}, 0}, +#define HA_cam 2 +}; + +#define NUM_OPTIONS (sizeof(bom2_options)/sizeof(bom2_options[0])) + +static rnd_hid_attr_val_t bom2_values[NUM_OPTIONS]; + +static const char *bom2_filename; +vts0_t fmt_names; /* array of const char * long name of each format, pointing into the conf database */ +vts0_t fmt_ids; /* array of strdup'd short name (ID) of each format */ + +static char *pcb_bom_clean_str(const char *in) +{ + char *out, *so; + const char *si; + long len = strlen(in); + + if ((out = malloc((len + 1) * sizeof(char))) == NULL) { + fprintf(stderr, "Error: pcb_bom_clean_str(): malloc() failed\n"); + exit(1); + } + + for(si = in, so = out; *si != '\0'; si++, so++) { + switch(*si) { + case '"': + *so = '\''; + break; + default: + *so = *si; + } + } + *so = '\0'; + + return out; +} + +static void free_fmts(void) +{ + int n; + for(n = 0; n < fmt_ids.used; n++) { + free(fmt_ids.array[n]); + fmt_ids.array[n] = NULL; + } +} + +static const rnd_export_opt_t *bom2_get_export_options(rnd_hid_t *hid, int *n, rnd_design_t *dsg, void *appspec) +{ + rnd_conf_listitem_t *li; + const char *val = bom2_values[HA_bom2file].str; + int idx; + + /* load all formats from the config */ + fmt_names.used = 0; + fmt_ids.used = 0; + + free_fmts(); + rnd_conf_loop_list(&conf_bom2.plugins.export_bom2.templates, li, idx) { + char id[MAX_TEMP_NAME_LEN]; + const char *sep = strchr(li->name, '.'); + int len; + + if (sep == NULL) { + rnd_message(RND_MSG_ERROR, "export_bom2: ignoring invalid template name (missing period): '%s'\n", li->name); + continue; + } + if (strcmp(sep+1, "name") != 0) + continue; + len = sep - li->name; + if (len > sizeof(id)-1) { + rnd_message(RND_MSG_ERROR, "export_bom2: ignoring invalid template name (too long): '%s'\n", li->name); + continue; + } + memcpy(id, li->name, len); + id[len] = '\0'; + vts0_append(&fmt_names, (char *)li->payload); + vts0_append(&fmt_ids, rnd_strdup(id)); + } + + if (fmt_names.used == 0) { + rnd_message(RND_MSG_ERROR, "export_bom2: can not set up export options: no template available\n"); + return NULL; + } + + bom2_options[HA_format].enumerations = (const char **)fmt_names.array; + + /* set default filename */ + if ((dsg != NULL) && ((val == NULL) || (*val == '\0'))) + pcb_derive_default_filename(dsg->loadname, &bom2_values[HA_bom2file], ".bom2"); + + if (n) + *n = NUM_OPTIONS; + return bom2_options; +} + + + +typedef struct { + char utcTime[64]; + char *name, *descr, *value; + pcb_subc_t *subc; + rnd_cardinal_t count; + int origin_score; + gds_t tmp; +} subst_ctx_t; + +static void append_clean(gds_t *dst, const char *text) +{ + const char *s; + for(s = text; *s != '\0'; s++) + if (isalnum(*s) || (*s == '.') || (*s == '-') || (*s == '+')) + gds_append(dst, *s); + else + gds_append(dst, '_'); +} + +static int is_val_true(const char *val) +{ + if (val == NULL) return 0; + if (strcmp(val, "yes") == 0) return 1; + if (strcmp(val, "on") == 0) return 1; + if (strcmp(val, "true") == 0) return 1; + if (strcmp(val, "1") == 0) return 1; + return 0; +} + +static int subst_cb(void *ctx_, gds_t *s, const char **input) +{ + subst_ctx_t *ctx = ctx_; + if (strncmp(*input, "UTC%", 4) == 0) { + *input += 4; + gds_append_str(s, ctx->utcTime); + return 0; + } + if (strncmp(*input, "author%", 7) == 0) { + *input += 7; + gds_append_str(s, pcb_author()); + return 0; + } + if (strncmp(*input, "title%", 6) == 0) { + *input += 6; + gds_append_str(s, RND_UNKNOWN(PCB->hidlib.name)); + return 0; + } + + if (strncmp(*input, "subc.", 5) == 0) { + *input += 5; + + /* elem attribute print: + subc.a.attribute - print the attribute if exists, "n/a" if not + subc.a.attribute|unk - print the attribute if exists, unk if not + subc.a.attribute?yes - print yes if attribute is true, "n/a" if not + subc.a.attribute?yes:nope - print yes if attribute is true, nope if not + */ + if (strncmp(*input, "a.", 2) == 0) { + char aname[256], unk_buf[256], *nope; + const char *val, *end, *unk = "n/a"; + long len; + + *input += 2; + end = strpbrk(*input, "?|%"); + len = end - *input; + if (len >= sizeof(aname) - 1) { + rnd_message(RND_MSG_ERROR, "bom2 tempalte error: attribute name '%s' too long\n", *input); + return 1; + } + memcpy(aname, *input, len); + aname[len] = '\0'; + if (*end == '|') { /* "or unknown" */ + *input = end+1; + end = strchr(*input, '%'); + len = end - *input; + if (len >= sizeof(unk_buf) - 1) { + rnd_message(RND_MSG_ERROR, "bom2 tempalte error: elem atribute '|unknown' field '%s' too long\n", *input); + return 1; + } + memcpy(unk_buf, *input, len); + unk_buf[len] = '\0'; + unk = unk_buf; + *input = end; + } + else if (*end == '?') { /* trenary */ + *input = end+1; + end = strchr(*input, '%'); + len = end - *input; + if (len >= sizeof(unk_buf) - 1) { + rnd_message(RND_MSG_ERROR, "bom2 tempalte error: elem atribute trenary field '%s' too long\n", *input); + return 1; + } + + memcpy(unk_buf, *input, len); + unk_buf[len] = '\0'; + *input = end+1; + + nope = strchr(unk_buf, ':'); + if (nope != NULL) { + *nope = '\0'; + nope++; + } + else /* only '?' is given, no ':' */ + nope = "n/a"; + + val = pcb_attribute_get(&ctx->subc->Attributes, aname); + if (is_val_true(val)) + gds_append_str(s, unk_buf); + else + gds_append_str(s, nope); + + return 0; + } + else + *input = end; + (*input)++; + + val = pcb_attribute_get(&ctx->subc->Attributes, aname); + if (val == NULL) + val = unk; + gds_append_str(s, val); + return 0; + } + if (strncmp(*input, "refdes%", 7) == 0) { + *input += 7; + gds_append_str(s, ctx->name); + return 0; + } + if (strncmp(*input, "refdes_%", 8) == 0) { + *input += 8; + append_clean(s, ctx->name); + return 0; + } + if (strncmp(*input, "footprint%", 10) == 0) { + *input += 10; + gds_append_str(s, ctx->descr); + return 0; + } + if (strncmp(*input, "footprint_%", 11) == 0) { + *input += 11; + append_clean(s, ctx->descr); + return 0; + } + if (strncmp(*input, "value%", 6) == 0) { + *input += 6; + gds_append_str(s, ctx->value); + return 0; + } + if (strncmp(*input, "value_%", 7) == 0) { + *input += 7; + append_clean(s, ctx->value); + return 0; + } + } + return -1; +} + +static void fprintf_templ(FILE *f, subst_ctx_t *ctx, const char *templ) +{ + if (templ != NULL) { + char *tmp = rnd_strdup_subst(templ, subst_cb, ctx, RND_SUBST_PERCENT); + fprintf(f, "%s", tmp); + free(tmp); + } +} + + +static const char *bom2_xform_get_attr(subst_ctx_t *ctx, pcb_subc_t *subc, const char *key) +{ + ctx->tmp.used = 0; + gds_append_str(&ctx->tmp, "bom2::"); + + gds_append_str(&ctx->tmp, key); + return pcb_attribute_get(&subc->Attributes, ctx->tmp.array); +} + +static void bom2_xform_by_subc_attrs(subst_ctx_t *ctx, pcb_subc_t *subc) +{ + const char *sval; + + sval = bom2_xform_get_attr(ctx, subc, "TODO"); + if (sval != NULL) { + } +} + +typedef struct { + const char *header, *item, *footer, *subc2id; +} template_t; + + +static int PrintBOM(const template_t *templ, const char *format_name) +{ + FILE *fp; + subst_ctx_t ctx; + + fp = rnd_fopen_askovr(&PCB->hidlib, bom2_filename, "w", NULL); + if (!fp) { + rnd_message(RND_MSG_ERROR, "Cannot open file %s for writing\n", bom2_filename); + return 1; + } + + ctx.count = 0; + gds_init(&ctx.tmp); + + rnd_print_utc(ctx.utcTime, sizeof(ctx.utcTime), 0); + + fprintf_templ(fp, &ctx, templ->header); + + /* For each subcircuit calculate an ID and count recurring IDs in a hash table */ + PCB_SUBC_LOOP(PCB->Data); + { +/*subc*/ + } + PCB_END_LOOP; + + fprintf_templ(fp, &ctx, templ->footer); + + fclose(fp); + gds_uninit(&ctx.tmp); + + return 0; +} + +static void gather_templates(void) +{ + rnd_conf_listitem_t *i; + int n; + + rnd_conf_loop_list(&conf_bom2.plugins.export_bom2.templates, i, n) { + char buff[256], *id, *sect; + int nl = strlen(i->name); + if (nl > sizeof(buff)-1) { + rnd_message(RND_MSG_ERROR, "export_bom2: ignoring template '%s': name too long\n", i->name); + continue; + } + memcpy(buff, i->name, nl+1); + id = buff; + sect = strchr(id, '.'); + if (sect == NULL) { + rnd_message(RND_MSG_ERROR, "export_bom2: ignoring template '%s': does not have a .section suffix\n", i->name); + continue; + } + *sect = '\0'; + sect++; + } +} + +static const char *get_templ(const char *tid, const char *type) +{ + char path[MAX_TEMP_NAME_LEN + 16]; + rnd_conf_listitem_t *li; + int idx; + + sprintf(path, "%s.%s", tid, type); /* safe: tid's length is checked before it was put in the vector, type is hardwired in code and is never longer than a few chars */ + rnd_conf_loop_list(&conf_bom2.plugins.export_bom2.templates, li, idx) + if (strcmp(li->name, path) == 0) + return li->payload; + return NULL; +} + +static void bom2_do_export(rnd_hid_t *hid, rnd_design_t *design, rnd_hid_attr_val_t *options, void *appspec) +{ + template_t templ; + char **tid; + pcb_cam_t cam; + + memset(&templ, 0, sizeof(templ)); + + + gather_templates(); + + if (!options) { + bom2_get_export_options(hid, 0, design, appspec); + options = bom2_values; + } + + bom2_filename = options[HA_bom2file].str; + if (!bom2_filename) + bom2_filename = "pcb-rnd-out.bom2"; + + pcb_cam_begin_nolayer(PCB, &cam, NULL, options[HA_cam].str, &bom2_filename); + + tid = vts0_get(&fmt_ids, options[HA_format].lng, 0); + if ((tid == NULL) || (*tid == NULL)) { + rnd_message(RND_MSG_ERROR, "export_bom2: invalid template selected\n"); + return; + } + templ.header = get_templ(*tid, "header"); + templ.item = get_templ(*tid, "item"); + templ.footer = get_templ(*tid, "footer"); + templ.subc2id = get_templ(*tid, "subc2id"); + + PrintBOM(&templ, options[HA_format].str); + pcb_cam_end(&cam); +} + +static int bom2_usage(rnd_hid_t *hid, const char *topic) +{ + int n; + fprintf(stderr, "\nBOM exporter command line arguments:\n\n"); + bom2_get_export_options(hid, &n, NULL, NULL); + rnd_hid_usage(bom2_options, sizeof(bom2_options) / sizeof(bom2_options[0])); + fprintf(stderr, "\nUsage: pcb-rnd [generic_options] -x bom2 [bom2_options] foo.pcb\n\n"); + return 0; +} + +static int bom2_parse_arguments(rnd_hid_t *hid, int *argc, char ***argv) +{ + rnd_export_register_opts2(hid, bom2_options, sizeof(bom2_options) / sizeof(bom2_options[0]), bom2_cookie, 0); + + /* when called from the export() command this field may be uninitialized yet */ + if (bom2_options[HA_format].enumerations == NULL) + bom2_get_export_options(hid, NULL, NULL, NULL); + + return rnd_hid_parse_command_line(argc, argv); +} + +rnd_hid_t bom2_hid; + +int pplg_check_ver_export_bom2(int ver_needed) { return 0; } + +void pplg_uninit_export_bom2(void) +{ + rnd_export_remove_opts_by_cookie(bom2_cookie); + rnd_conf_unreg_file(CONF_FN, export_bom2_conf_internal); + rnd_conf_unreg_fields("plugins/export_bom2/"); + free_fmts(); + vts0_uninit(&fmt_names); + vts0_uninit(&fmt_ids); + rnd_hid_remove_hid(&bom2_hid); +} + + +int pplg_init_export_bom2(void) +{ + RND_API_CHK_VER; + + rnd_conf_reg_file(CONF_FN, export_bom2_conf_internal); + + memset(&bom2_hid, 0, sizeof(rnd_hid_t)); + +#define conf_reg(field,isarray,type_name,cpath,cname,desc,flags) \ + rnd_conf_reg_field(conf_bom2, field,isarray,type_name,cpath,cname,desc,flags); +#include "bom2_conf_fields.h" + + rnd_hid_nogui_init(&bom2_hid); + + bom2_hid.struct_size = sizeof(rnd_hid_t); + bom2_hid.name = "bom2"; + bom2_hid.description = "Exports a BoM (Bill of Material) using templates"; + bom2_hid.exporter = 1; + + bom2_hid.get_export_options = bom2_get_export_options; + bom2_hid.do_export = bom2_do_export; + bom2_hid.parse_arguments = bom2_parse_arguments; + bom2_hid.argument_array = bom2_values; + + bom2_hid.usage = bom2_usage; + + rnd_hid_register_hid(&bom2_hid); + rnd_hid_load_defaults(&bom2_hid, bom2_options, NUM_OPTIONS); + + vts0_init(&fmt_names); + vts0_init(&fmt_ids); + return 0; +} Index: trunk/src_plugins/export_bom2/bom2_conf.h =================================================================== --- trunk/src_plugins/export_bom2/bom2_conf.h (nonexistent) +++ trunk/src_plugins/export_bom2/bom2_conf.h (revision 37991) @@ -0,0 +1,14 @@ +#ifndef PCB_BOM2_CONF_H +#define PCB_BOM2_CONF_H + +#include + +typedef struct { + const struct { + const struct { + RND_CFT_LIST templates; + } export_bom2; + } plugins; +} conf_bom2_t; + +#endif Index: trunk/src_plugins/export_bom2/export_bom2.conf =================================================================== --- trunk/src_plugins/export_bom2/export_bom2.conf (nonexistent) +++ trunk/src_plugins/export_bom2/export_bom2.conf (revision 37991) @@ -0,0 +1,21 @@ +### conf file header (compacted) +li:pcb-rnd-conf-v1 { ha:overwrite { ha:plugins { ha:export_bom2 { li:templates { + +### tempalates + +# classis gEDA/PCB BoM ######################################################### +geda.name = pcb BoM +geda.header = {# $Id$ +# PcbBOM Version 1.0 +# Date: %UTC% +# Author: %author% +# Title: %title% - PCB BOM +# Quantity, Description, Value, RefDes +# -------------------------------------------- +} +geda.subc2id = {%subc.refdes%__%subc.footprint%__%subc.value%} +geda.footer = {} + + +### conf file footer (compacted) +} } } } } Index: trunk/src_plugins/export_bom2/export_bom2.pup =================================================================== --- trunk/src_plugins/export_bom2/export_bom2.pup (nonexistent) +++ trunk/src_plugins/export_bom2/export_bom2.pup (revision 37991) @@ -0,0 +1,9 @@ +$class export +$short Bill of Materials export +$long Export BoM (Bill of Materials) with configurable templates +$state works +$fmt-native no +$fmt-feature-w bom (Bill of Materials, text, templated) +$package export +default buildin +autoload 1 Index: trunk/src_plugins/plugins_ALL.tmpasm =================================================================== --- trunk/src_plugins/plugins_ALL.tmpasm (revision 37990) +++ trunk/src_plugins/plugins_ALL.tmpasm (revision 37991) @@ -22,6 +22,7 @@ include {../src_plugins/drc_query/Plug.tmpasm} include {../src_plugins/expfeat/Plug.tmpasm} include {../src_plugins/export_bom/Plug.tmpasm} +include {../src_plugins/export_bom2/Plug.tmpasm} include {../src_plugins/export_c_draw/Plug.tmpasm} include {../src_plugins/export_debug/Plug.tmpasm} include {../src_plugins/export_dxf/Plug.tmpasm}