Index: trunk/src/plug_footprint.h =================================================================== --- trunk/src/plug_footprint.h (revision 30790) +++ trunk/src/plug_footprint.h (revision 30791) @@ -70,12 +70,6 @@ */ FILE *(*fp_fopen)(pcb_plug_fp_t *ctx, const char *path, const char *name, pcb_fp_fopen_ctx_t *fctx, pcb_data_t *dst); - /* Scan as little as possible from the file to decide what the file is and extract tags; - For a single file, load head and return it. For a library-type file, load - head with the first footprint then allocate further footprints in a singly - linked list. If need_tags is 0, do not parse for tags */ - pcb_plug_fp_map_t *(*fp_map)(pcb_plug_fp_t *ctx, FILE *f, const char *fn, pcb_plug_fp_map_t *head, int need_tags); - /* Close the footprint file opened by pcb_pcb_fp_fopen(). */ void (*fp_fclose)(pcb_plug_fp_t *ctx, FILE * f, pcb_fp_fopen_ctx_t *fctx); }; Index: trunk/src/plug_io.c =================================================================== --- trunk/src/plug_io.c (revision 30790) +++ trunk/src/plug_io.c (revision 30791) @@ -1003,7 +1003,38 @@ return 0; } +pcb_plug_fp_map_t *pcb_io_map_footprint_file(pcb_hidlib_t *hl, const char *fn, pcb_plug_fp_map_t *head, int need_tags) +{ + FILE *f = pcb_fopen(hl, fn, "r"); + pcb_plug_fp_map_t *res = NULL; + pcb_plug_io_t *plug; + if (f == NULL) { + head->type = PCB_FP_INVALID; + return head; + } + + for(plug = pcb_plug_io_chain; plug != NULL; plug = plug->next) { + if (plug->map_footprint == NULL) continue; + + rewind(f); + res = plug->map_footprint(NULL, f, fn, head, need_tags); + if (res == NULL) continue; + if (res->type != PCB_FP_INVALID) + break; /* success */ + vts0_uninit(&res->tags); + } + + + fclose(f); + if (res == NULL) { + res = head; + head->type = PCB_FP_INVALID; + } + return res; +} + + void pcb_io_uninit(void) { pcb_view_list_free_fields(&pcb_io_incompat_lst); Index: trunk/src/plug_io.h =================================================================== --- trunk/src/plug_io.h (revision 30790) +++ trunk/src/plug_io.h (revision 30791) @@ -31,6 +31,7 @@ #define PCB_PLUG_IO_H #include "global_typedefs.h" +#include "plug_footprint.h" #include typedef enum { /* I/O type bitmask; each bit is one thing to save or load, not all formats support all things */ @@ -73,6 +74,13 @@ /* Attempt to load an element from Filename to Ptr. Return 0 on success. */ int (*parse_footprint)(pcb_plug_io_t *ctx, pcb_data_t *Ptr, const char *name); + /* Scan as little as possible from the file to decide what the file is and extract tags; + For a single file, load head and return it. For a library-type file, load + head with the first footprint then allocate further footprints in a singly + linked list. If need_tags is 0, do not parse for tags */ + pcb_plug_fp_map_t *(*map_footprint)(pcb_plug_io_t *ctx, FILE *f, const char *fn, pcb_plug_fp_map_t *head, int need_tags); + + /* Attempt to load fonts from a file. Return 0 on success. */ int (*parse_font)(pcb_plug_io_t *ctx, pcb_font_t *Ptr, const char *Filename); @@ -130,6 +138,9 @@ int pcb_write_footprint_data(FILE *f, pcb_data_t *e, const char *fmt, long subc_idx); int pcb_write_font(pcb_font_t *Ptr, const char *Filename, const char *fmt); +/* map a footprint file: always returns head with 0 or 1 or more mapping results */ +pcb_plug_fp_map_t *pcb_io_map_footprint_file(pcb_hidlib_t *hl, const char *fn, pcb_plug_fp_map_t *head, int need_tags); + /********** common function used to be part of file.[ch] and friends **********/ int pcb_save_pcb(const char *, const char *fmt); #define PCB_INHIBIT_BOARD_CHANGED 0x20 @@ -204,4 +215,6 @@ void pcb_plug_io_err(pcb_hidlib_t *hidlib, int res, const char *what, const char *filename); + + #endif Index: trunk/src_plugins/fp_fs/fp_fs.c =================================================================== --- trunk/src_plugins/fp_fs/fp_fs.c (revision 30790) +++ trunk/src_plugins/fp_fs/fp_fs.c (revision 30791) @@ -39,6 +39,7 @@ #include #include #include "plug_footprint.h" +#include "plug_io.h" #include #include #include @@ -103,29 +104,6 @@ return 0; } -pcb_plug_fp_map_t *pcb_fp_map_fp_file(pcb_hidlib_t *hl, const char *fn, pcb_plug_fp_map_t *head, int need_tags) -{ - FILE *f = pcb_fopen(hl, fn, "r"); - pcb_plug_fp_map_t *res; - - if (f == NULL) { - head->type = PCB_FP_INVALID; - return head; - } - - { /* run this for all plugins */ - rewind(f); - res = pcb_fp_file_type(NULL, f, fn, head, need_tags); - } - - fclose(f); - if (res == NULL) { - res = head; - head->type = PCB_FP_INVALID; - } - return res; -} - static int fp_fs_list(pcb_fplibrary_t *pl, const char *subdir, int recurse, int (*cb) (void *cookie, const char *subdir, const char *name, pcb_fptype_t type, void *tags[]), void *cookie, int subdir_may_not_exist, int need_tags) @@ -209,7 +187,7 @@ if ((S_ISREG(buffer.st_mode)) || (WRAP_S_ISLNK(buffer.st_mode))) { pcb_plug_fp_map_t head = {0}, *res; - res = pcb_fp_map_fp_file(&PCB->hidlib, subdirentry->d_name, &head, need_tags); + res = pcb_io_map_footprint_file(&PCB->hidlib, subdirentry->d_name, &head, need_tags); if ((res->type == PCB_FP_FILE) || (res->type == PCB_FP_PARAMETRIC)) { n_footprints++; if (cb(cookie, new_subdir, subdirentry->d_name, res->type, (void **)res->tags.array)) @@ -371,119 +349,6 @@ return NULL; } -TODO("subc: should be handled in io_*") -/* Decide about the type of a footprint file: - - it is a file element if the first non-comment is "Element(" or "Element[" - - else it is a parametric element (footprint generator) if it contains - "@@" "purpose" - - else it's not an element. - - if a line of a file element starts with ## and doesn't contain @, it's a tag - - if tags is not NULL, it's a pointer to a void *tags[] - an array of tag IDs -*/ -pcb_plug_fp_map_t *pcb_fp_file_type(pcb_plug_fp_t *ctx, FILE *f, const char *fn, pcb_plug_fp_map_t *head, int need_tags) -{ - int c, comment_len; - int first_element = 1; - enum { - ST_WS, - ST_COMMENT, - ST_ELEMENT, - ST_TAG - } state = ST_WS; - gds_t tag; - - gds_init(&tag); - head->type = PCB_FP_INVALID; - while ((c = fgetc(f)) != EOF) { - switch (state) { - case ST_ELEMENT: - if (isspace(c)) - break; - if ((c == '(') || (c == '[')) { - head->type = PCB_FP_FILE; - goto out; - } - case ST_WS: - if (isspace(c)) - break; - if (c == '#') { - comment_len = 0; - state = ST_COMMENT; - break; - } - else if ((first_element) && (c == 'l')) { -TODO("fp: rather call plug_io if it is not parametric") - char s[23]; - /* li:pcb-rnd-subcircuit */ - fgets(s, 21, f); - s[20] = '\0'; - if (strcmp(s, "i:pcb-rnd-subcircuit") == 0) { - head->type = PCB_FP_FILE; - goto out; - } - } - else if ((first_element) && (c == 'E')) { - char s[8]; - /* Element */ - fgets(s, 7, f); - s[6] = '\0'; - if (strcmp(s, "lement") == 0) { - state = ST_ELEMENT; - break; - } - } - else if ((first_element) && (c == '(')) { - char s[8]; - /* module */ - fgets(s, 7, f); - s[6] = '\0'; - if (strcmp(s, "module") == 0) { - state = ST_ELEMENT; - break; - } - } - first_element = 0; - /* fall-thru for detecting @ */ - case ST_COMMENT: - comment_len++; - if ((c == '#') && (comment_len == 1)) { - state = ST_TAG; - break; - } - if ((c == '\r') || (c == '\n')) - state = ST_WS; - if (c == '@') { - char s[10]; - maybe_purpose:; - /* "@@" "purpose" */ - fgets(s, 9, f); - s[8] = '\0'; - if (strcmp(s, "@purpose") == 0) { - head->type = PCB_FP_PARAMETRIC; - goto out; - } - } - break; - case ST_TAG: - if ((c == '\r') || (c == '\n')) { /* end of a tag */ - if (need_tags && (tag.used != 0)) - vts0_append(&head->tags, (char *)pcb_fp_tag(tag.array, 1)); - - tag.used = 0; - state = ST_WS; - break; - } - if (c == '@') - goto maybe_purpose; - gds_append(&tag, c); - } - } - -out:; - gds_uninit(&tag); - return head; -} - #define F_IS_PARAMETRIC 0 #define F_TMPNAME 1 static FILE *fp_fs_fopen(pcb_plug_fp_t *ctx, const char *path, const char *name, pcb_fp_fopen_ctx_t *fctx, pcb_data_t *dst) Index: trunk/src_plugins/io_pcb/file.c =================================================================== --- trunk/src_plugins/io_pcb/file.c (revision 30790) +++ trunk/src_plugins/io_pcb/file.c (revision 30791) @@ -1205,3 +1205,116 @@ } #endif + +TODO("subc: should be split up to multiple plugins") +/* Decide about the type of a footprint file: + - it is a file element if the first non-comment is "Element(" or "Element[" + - else it is a parametric element (footprint generator) if it contains + "@@" "purpose" + - else it's not an element. + - if a line of a file element starts with ## and doesn't contain @, it's a tag + - if tags is not NULL, it's a pointer to a void *tags[] - an array of tag IDs +*/ +pcb_plug_fp_map_t *io_pcb_map_footprint(pcb_plug_io_t *ctx, FILE *f, const char *fn, pcb_plug_fp_map_t *head, int need_tags) +{ + int c, comment_len; + int first_element = 1; + enum { + ST_WS, + ST_COMMENT, + ST_ELEMENT, + ST_TAG + } state = ST_WS; + gds_t tag; + + gds_init(&tag); + head->type = PCB_FP_INVALID; + while ((c = fgetc(f)) != EOF) { + switch (state) { + case ST_ELEMENT: + if (isspace(c)) + break; + if ((c == '(') || (c == '[')) { + head->type = PCB_FP_FILE; + goto out; + } + case ST_WS: + if (isspace(c)) + break; + if (c == '#') { + comment_len = 0; + state = ST_COMMENT; + break; + } + else if ((first_element) && (c == 'l')) { +TODO("fp: rather call plug_io if it is not parametric") + char s[23]; + /* li:pcb-rnd-subcircuit */ + fgets(s, 21, f); + s[20] = '\0'; + if (strcmp(s, "i:pcb-rnd-subcircuit") == 0) { + head->type = PCB_FP_FILE; + goto out; + } + } + else if ((first_element) && (c == 'E')) { + char s[8]; + /* Element */ + fgets(s, 7, f); + s[6] = '\0'; + if (strcmp(s, "lement") == 0) { + state = ST_ELEMENT; + break; + } + } + else if ((first_element) && (c == '(')) { + char s[8]; + /* module */ + fgets(s, 7, f); + s[6] = '\0'; + if (strcmp(s, "module") == 0) { + state = ST_ELEMENT; + break; + } + } + first_element = 0; + /* fall-thru for detecting @ */ + case ST_COMMENT: + comment_len++; + if ((c == '#') && (comment_len == 1)) { + state = ST_TAG; + break; + } + if ((c == '\r') || (c == '\n')) + state = ST_WS; + if (c == '@') { + char s[10]; + maybe_purpose:; + /* "@@" "purpose" */ + fgets(s, 9, f); + s[8] = '\0'; + if (strcmp(s, "@purpose") == 0) { + head->type = PCB_FP_PARAMETRIC; + goto out; + } + } + break; + case ST_TAG: + if ((c == '\r') || (c == '\n')) { /* end of a tag */ + if (need_tags && (tag.used != 0)) + vts0_append(&head->tags, (char *)pcb_fp_tag(tag.array, 1)); + + tag.used = 0; + state = ST_WS; + break; + } + if (c == '@') + goto maybe_purpose; + gds_append(&tag, c); + } + } + +out:; + gds_uninit(&tag); + return head; +} Index: trunk/src_plugins/io_pcb/file.h =================================================================== --- trunk/src_plugins/io_pcb/file.h (revision 30790) +++ trunk/src_plugins/io_pcb/file.h (revision 30791) @@ -98,4 +98,6 @@ /* This is the version we support. */ #define PCB_FILE_VERSION 20110603 +pcb_plug_fp_map_t *io_pcb_map_footprint(pcb_plug_io_t *ctx, FILE *f, const char *fn, pcb_plug_fp_map_t *head, int need_tags); + #endif Index: trunk/src_plugins/io_pcb/io_pcb.c =================================================================== --- trunk/src_plugins/io_pcb/io_pcb.c (revision 30790) +++ trunk/src_plugins/io_pcb/io_pcb.c (revision 30791) @@ -73,6 +73,7 @@ io_pcb[0].test_parse = io_pcb_test_parse; io_pcb[0].parse_pcb = io_pcb_ParsePCB; io_pcb[0].parse_footprint = io_pcb_ParseElement; + io_pcb[0].map_footprint = io_pcb_map_footprint; /* it is enough to have this in [0] so the same checks are not done multiple times, per version */ io_pcb[0].parse_font = io_pcb_ParseFont; io_pcb[0].write_buffer = NULL; io_pcb[0].write_subcs_head = io_pcb_write_subcs_head;