+
+/*
+ * 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);
+ fp++;
+ }
+ 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;
+}
+
+/*
+ * Like fmt_findcomp, but case-insensitive.
+ */
+
+struct comp *
+fmt_findcasecomp(char *component)
+{
+ struct comp *cm;
+
+ for (cm = wantcomp[CHASH(component)]; cm; cm = cm->c_next)
+ if (mh_strcasecmp(component, cm->c_name) == 0)
+ break;
+
+ return cm;
+}
+
+/*
+ * Add an entry to the component hash table
+ *
+ * Returns true if the component was added, 0 if it already existed.
+ *
+ */
+
+int
+fmt_addcompentry(char *component)
+{
+ struct comp *cm;
+ int i;
+
+ FINDCOMP(cm, component);
+
+ if (cm)
+ return 0;
+
+ NEWCOMP(cm, component);
+
+ /*
+ * ncomp is really meant for fmt_compile() and this function is
+ * meant to be used outside of it. So decrement it just to be safe
+ * (internal callers should be using NEWCOMP()).
+ */
+
+ ncomp--;
+
+ return 1;
+}
+
+/*
+ * Add a string to a component hash table entry.
+ *
+ * Note the special handling for components marked with CT_ADDR. The comments
+ * in fmt_scan.h explain this in more detail.
+ */
+
+int
+fmt_addcomptext(char *component, char *text)
+{
+ int i, found = 0, bucket = CHASH(component);
+ struct comp *cptr = wantcomp[bucket];
+ char *cp;
+
+ while (cptr) {
+ if (mh_strcasecmp(component, cptr->c_name) == 0) {
+ found++;
+ if (! cptr->c_text) {
+ cptr->c_text = getcpy(text);
+ } else {
+ i = strlen(cp = cptr->c_text) - 1;
+ if (cp[i] == '\n') {
+ if (cptr->c_type & CT_ADDR) {
+ cp[i] = '\0';
+ cp = add(",\n\t", cp);
+ } else {
+ cp = add("\t", cp);
+ }
+ }
+ cptr->c_text = add(text, cp);
+ }
+ }
+ cptr = cptr->c_next;
+ }
+
+ return found ? bucket : -1;
+}
+
+/*
+ * Append text to a component we've already found. See notes in fmt_scan.h
+ * for more information.
+ */
+
+void
+fmt_appendcomp(int bucket, char *component, char *text)
+{
+ struct comp *cptr;
+
+ if (bucket != -1) {
+ for (cptr = wantcomp[bucket]; cptr; cptr = cptr->c_next)
+ if (mh_strcasecmp(component, cptr->c_name) == 0)
+ cptr->c_text = add(text, cptr->c_text);
+ }
+}
+
+/*
+ * Free and reset our component hash table
+ */
+
+static void
+free_comptable(void)
+{
+ unsigned int i;
+ struct comp *cm, *cm2;
+
+ for (i = 0; i < sizeof(wantcomp)/sizeof(wantcomp[0]); i++) {
+ cm = wantcomp[i];
+ while (cm != NULL) {
+ cm2 = cm->c_next;
+ free_component(cm);
+ cm = cm2;
+ }
+ wantcomp[i] = 0;
+ }
+
+ ncomp = 0;
+}
+
+/*
+ * Decrement the reference count of a component structure. If it reaches
+ * zero, free it
+ */
+
+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);
+ }
+}