X-Git-Url: http://git.marmaro.de/?a=blobdiff_plain;f=sbr%2Ffmt_compile.c;h=27f1a1ed3003088383daf741201a33a3c293bb20;hb=de3c9caebeaf5551e931f8875dd9cd222c63f020;hp=1e8964d8b7edeb65d621d1f6e55d79c51a82a937;hpb=0cd013babcc880cce0d0824dd0b6f6293be1f930;p=mmh diff --git a/sbr/fmt_compile.c b/sbr/fmt_compile.c index 1e8964d..27f1a1e 100644 --- a/sbr/fmt_compile.c +++ b/sbr/fmt_compile.c @@ -218,10 +218,27 @@ static struct ftable functable[] = { { NULL, 0, 0, 0, 0 } }; +/* + * Hash function for component name. The function should be + * case independent and probably shouldn't involve a routine + * call. This function is pretty good but will not work on + * single character component names. + */ +#define CHASH(nm) (((((nm)[0]) - ((nm)[1])) & 0x1f) + (((nm)[2]) & 0x5f)) + +/* + * Find a component in the hash table. + */ +#define FINDCOMP(comp,name) \ + for (comp = wantcomp[CHASH(name)]; \ + comp && strcmp(comp->c_name,name); \ + comp = comp->c_next) \ + ; + /* Add new component to the hash table */ #define NEWCOMP(cm,name) do { \ cm = ((struct comp *) calloc(1, sizeof (struct comp)));\ - cm->c_name = name;\ + cm->c_name = getcpy(name);\ ncomp++;\ i = CHASH(name);\ cm->c_next = wantcomp[i];\ @@ -240,10 +257,12 @@ static struct ftable functable[] = { NEWCOMP(cm,name);\ }\ fp->f_comp = cm; \ + fp->f_flags |= FF_COMPREF; \ + cm->c_refcount++; \ } while (0) #define LV(type, value) do { NEW(type,0,0); fp->f_value = (value); } while (0) -#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); } while (0) +#define LS(type, str) do { NEW(type,0,0); fp->f_text = (str); fp->f_flags |= FF_STRALLOC; } while (0) #define PUTCOMP(comp) do { NEW(FT_COMP,0,0); ADDC(comp); } while (0) #define PUTLIT(str) do { NEW(FT_LIT,0,0); fp->f_text = getcpy(str); } while (0) @@ -324,12 +343,15 @@ fmt_compile(char *fstring, struct format **fmt, int reset_comptable) { register char *cp; size_t i; + static int comptable_initialized = 0; format_string = getcpy (fstring); usr_fstring = fstring; - if (reset_comptable) + if (reset_comptable || !comptable_initialized) { free_comptable(); + comptable_initialized = 1; + } /* init the component hash table. */ for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) @@ -676,6 +698,37 @@ do_expr (char *sp, int preprocess) * There is no support for this in the format engine, so right now if * you try using it you will reach the FT_DONE and simply stop. I'm leaving * this here in case someone wants to continue the work. + * + * Okay, got some more information on this from John L. Romine! From an + * email he sent to the nmh-workers mailing list on December 2, 2010, he + * explains it thusly: + * + * In this case (scan, formatsbr) it has to do with an extension to + * the mh-format syntax to allow for looping. + * + * The scan format is processed once for each message. Those #ifdef + * JLR changes allowed for the top part of the format file to be + * processed once, then a second, looping part to be processed + * once per message. As I recall, there were new mh-format escape + * sequences to delimit the loop. This would have allowed for things + * like per-format column headings in the scan output. + * + * Since existing format files didn't include the scan listing + * header (it was hard-coded in scan.c) it would not have been + * backward-compatible. All existing format files (including any + * local ones) would have needed to be changed to include the format + * codes for a header. The practice at the time was not to introduce + * incompatible changes in a minor release, and I never managed to + * put out a newer major release. + * + * I can see how this would work, and I suspect part of the motivation was + * because the format compiler routines (at the time) couldn't really be + * called multiple times on the same message because the memory management + * was so lousy. That's been reworked and things are now a lot cleaner, + * so I suspect if we're going to allow a format string to be used for the + * scan header it might be simpler to have a separate format string just + * for the header. But I'll leave this code in for now just in case we + * decide that we want some kind of looping support. */ static char * do_loop(char *sp) @@ -775,6 +828,53 @@ do_if(char *sp) } /* + * Free a set of format instructions. + * + * What we do here is: + * + * - Iterate through the list of format instructions, freeing any references + * to allocated memory in each instruction. + * - Free component references. + * - If requested, reset the component hash table; that will also free any + * references to components stored there. + * + */ + +void +fmt_free(struct format *fmt, int reset_comptable) +{ + struct format *fp = fmt; + + if (fp) { + while (! (fp->f_type == FT_DONE && fp->f_value == 0)) { + if (fp->f_flags & FF_STRALLOC) + free(fp->f_text); + if (fp->f_flags & FF_COMPREF) + free_component(fp->f_comp); + } + free(fmt); + } + + if (reset_comptable) + free_comptable(); +} + +/* + * Find a component in our hash table. This is just a public interface to + * the FINDCOMP macro, so we don't have to expose our hash table. + */ + +struct comp * +fmt_findcomp(char *component) +{ + struct comp *cm; + + FINDCOMP(cm, component); + + return cm; +} + +/* * Free and reset our component hash table */ @@ -804,6 +904,15 @@ static void free_component(struct comp *cm) { if (--cm->c_refcount <= 0) { + /* Shouldn't ever be NULL, but just in case ... */ + if (cm->c_name) + free(cm->c_name); + if (cm->c_text) + free(cm->c_text); + if (cm->c_type & CT_DATE) + free(cm->c_tws); + if (cm->c_type & CT_ADDR && cm->c_mn && cm->c_mn != &fmt_mnull) + mnfree(cm->c_mn); free(cm); } }