]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Update cf_gen objects to use STL containers and extend syntax for DEFAULT*
authorAmos Jeffries <squid3@treenet.co.nz>
Sun, 21 Aug 2011 06:34:26 +0000 (18:34 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Sun, 21 Aug 2011 06:34:26 +0000 (18:34 +1200)
Removes all need for explicit memory management of the parsed tree.

Alters DEFAULT: tag to allow multiple line values to be pre-defined.

Adds DEFAULT_DOC: tag to allow text description of a default in the documented
versions of config file instead of explicit code-level values.

Also updates the output slightly so cf_parser.cci conforms to the current
coding style gidelines.

src/cf_gen.cc

index 3b38486958e17fdf28f0a55c81774d4363a19835..adbafa64144c8715cd3c65b34ae522edf15838cc 100644 (file)
@@ -1,6 +1,8 @@
 /*
  * DEBUG: none          Generate squid.conf.default and cf_parser.cci
  * AUTHOR: Max Okumoto
+ * AUTHOR: Francesco Chemolli
+ * AUTHOR: Amos Jeffries
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
@@ -60,6 +62,7 @@ _FILE_OFFSET_BITS==64
 #include <cstring>
 #include <fstream>
 #include <iostream>
+#include <list>
 
 #include "cf_gen_defines.cci"
 
@@ -77,111 +80,91 @@ enum State {
     sEXIT
 };
 
-// TODO: inherit all these from link lists.
+typedef std::list<std::string> LineList;
+typedef std::list<std::string> TypeDepList;
+typedef std::list<std::string> EntryAliasList;
 
-class Line
+class DefaultValues
 {
 public:
-    Line(const char *str) : data(str), next(NULL) {}
-    ~Line() {}
+    DefaultValues() : preset(), if_none(), docs() {}
+    ~DefaultValues() {}
 
-    std::string data;
-    Line *next;
-};
+    /// Default config lines to be defined before parsing the config files.
+    LineList preset;
 
-class EntryAlias
-{
-public:
-    EntryAlias(const char *str) : name(str), next(NULL) {}
-    ~EntryAlias() {}
+    /// Default config lines to parse if the directive has no prior settings.
+    /// This is mutually exclusive with preset values.
+    /// An error will be printed during build if they clash.
+    LineList if_none;
 
-    std::string name;
-    EntryAlias *next;
+    /// Text description to use in documentation for the default.
+    /// If unset the preset or if-none values will be displayed.
+    LineList docs;
 };
 
 class Entry
 {
 public:
     Entry(const char *str) :
-            name(str), alias(), type(), loc(),
-            default_value(), default_if_none(),
-            comment(), ifdef(), doc(), nocomment(),
-            next(NULL) {}
+            name(str), alias(),type(), loc(),
+            defaults(), comment(), ifdef(), doc(), nocomment(),
+            array_flag(0) {}
     ~Entry() {}
 
     std::string name;
-    EntryAlias *alias;
+    EntryAliasList alias;
     std::string type;
     std::string loc;
-    std::string default_value;
-    Line *default_if_none;
+    DefaultValues defaults;
     std::string comment;
     std::string ifdef;
-    Line *doc;
-    Line *nocomment;
+    LineList doc;
+    LineList nocomment;
     int array_flag;
 
-    Entry *next;
-};
+    void genParse(std::ostream &fout) const;
 
-class TypeDep
-{
-public:
-    TypeDep(const char *str) : name(str), next(NULL) {}
-    ~TypeDep() {}
-
-    std::string name;
-    TypeDep *next;
+private:
+    void genParseAlias(const std::string &, std::ostream &) const;
 };
 
+typedef std::list<class Entry> EntryList;
+
 class Type
 {
 public:
-    Type(const char *str) : name(str), next(NULL) {}
+    Type(const char *str) : name(str) {}
     ~Type() {}
 
     std::string name;
-    TypeDep *depend;
-    Type *next;
+    TypeDepList depend;
 };
 
-static const char WS[] = " \t\n";
-static int gen_default(Entry *, std::ostream &);
-static void gen_parse(Entry *, std::ostream &);
-static void gen_parse_entry(Entry *entry, std::ostream&);
-static void gen_parse_alias(const std::string &, EntryAlias *, Entry *, std::ostream &);
-static void gen_dump(Entry *, std::ostream&);
-static void gen_free(Entry *, std::ostream&);
-static void gen_conf(Entry *, std::ostream&, bool verbose_output);
-static void gen_default_if_none(Entry *, std::ostream&);
-
-static void
-lineAdd(Line ** L, const char *str)
-{
-    assert(str);
+typedef std::list<class Type> TypeList;
 
-    while (*L)
-        L = &(*L)->next;
-
-    *L = new Line(str);
-}
+static const char WS[] = " \t\n";
+static int gen_default(const EntryList &, std::ostream &);
+static void gen_parse(const EntryList &, std::ostream &);
+static void gen_dump(const EntryList &, std::ostream&);
+static void gen_free(const EntryList &, std::ostream&);
+static void gen_conf(const EntryList &, std::ostream&, bool verbose_output);
+static void gen_default_if_none(const EntryList &, std::ostream&);
 
 static void
-checkDepend(const std::string &directive, const char *name, const Type *types, const Entry *entries)
+checkDepend(const std::string &directive, const char *name, const TypeList &types, const EntryList &entries)
 {
-    const Type *type;
-    for (type = types; type; type = type->next) {
-        const TypeDep *dep;
-        if (type->name.compare(name) != 0)
+    for (TypeList::const_iterator t = types.begin(); t != types.end(); ++t) {
+        if (t->name.compare(name) != 0)
             continue;
-        for (dep = type->depend; dep; dep = dep->next) {
-            const Entry *entry;
-            for (entry = entries; entry; entry = entry->next) {
-                if (entry->name.compare(dep->name) == 0)
+        for (TypeDepList::const_iterator dep = t->depend.begin(); dep != t->depend.end(); ++dep) {
+            EntryList::const_iterator entry = entries.begin();
+            for (; entry != entries.end(); ++entry) {
+                if (entry->name.compare(*dep) == 0)
                     break;
             }
-            if (!entry) {
-                std::cerr << "ERROR: '" << directive << "' (" << name << ") depends on '" << dep->name << "'\n";
+            if (entry == entries.end()) {
+                std::cerr << "ERROR: '" << directive << "' (" << name << ") depends on '" << *dep << "'\n";
                 exit(1);
             }
         }
@@ -207,9 +190,8 @@ main(int argc, char *argv[])
     const char *conf_filename_short = _PATH_SQUID_CONF_SHORT;
     const char *type_depend;
     int linenum = 0;
-    Entry *entries = NULL;
-    Entry *curr = NULL;
-    Type *types = NULL;
+    EntryList entries;
+    TypeList types;
     enum State state;
     int rc = 0;
     char *ptr = NULL;
@@ -238,14 +220,11 @@ main(int argc, char *argv[])
         const char *dep;
         if (!type || type[0] == '#')
             continue;
-        Type *t = new Type(type);
+        Type t(type);
         while ((dep = strtok(NULL, WS)) != NULL) {
-            TypeDep *d = new TypeDep(dep);
-            d->next = t->depend;
-            t->depend = d;
+            t.depend.push_front(dep);
         }
-        t->next = types;
-        types = t;
+        types.push_front(t);
     }
     fp.close();
     fp.clear(); // BSD does not reset flags in close().
@@ -287,20 +266,17 @@ main(int argc, char *argv[])
                     exit(1);
                 }
 
-                curr = new Entry(name);
+                entries.push_back(name);
 
-                while ((aliasname = strtok(NULL, WS)) != NULL) {
-                    EntryAlias *alias = new EntryAlias(aliasname);
-                    alias->next = curr->alias;
-                    curr->alias = alias;
-                }
+                while ((aliasname = strtok(NULL, WS)) != NULL)
+                    entries.back().alias.push_front(aliasname);
 
                 state = s1;
             } else if (!strcmp(buff, "EOF")) {
                 state = sEXIT;
             } else if (!strcmp(buff, "COMMENT_START")) {
-                curr = new Entry("comment");
-                curr->loc = "none";
+                entries.push_back("comment");
+                entries.back().loc = "none";
                 state = sDOC;
             } else {
                 std::cerr << "Error on line " << linenum << std::endl <<
@@ -310,7 +286,8 @@ main(int argc, char *argv[])
 
             break;
 
-        case s1:
+        case s1: {
+            Entry &curr = entries.back();
 
             if ((strlen(buff) == 0) || (!strncmp(buff, "#", 1))) {
                 /* ignore empty and comment lines */
@@ -321,28 +298,35 @@ main(int argc, char *argv[])
                 while (isspace((unsigned char)*ptr))
                     ptr++;
 
-                curr->comment = ptr;
+                curr.comment = ptr;
             } else if (!strncmp(buff, "DEFAULT:", 8)) {
                 ptr = buff + 8;
 
                 while (isspace((unsigned char)*ptr))
                     ptr++;
 
-                curr->default_value = ptr;
+                curr.defaults.preset.push_back(ptr);
             } else if (!strncmp(buff, "DEFAULT_IF_NONE:", 16)) {
                 ptr = buff + 16;
 
                 while (isspace((unsigned char)*ptr))
                     ptr++;
 
-                lineAdd(&curr->default_if_none, ptr);
+                curr.defaults.if_none.push_back(ptr);
+            } else if (!strncmp(buff, "DEFAULT_DOC:", 12)) {
+                ptr = buff + 12;
+
+                while (isspace((unsigned char)*ptr))
+                    ptr++;
+
+                curr.defaults.docs.push_back(ptr);
             } else if (!strncmp(buff, "LOC:", 4)) {
                 if ((ptr = strtok(buff + 4, WS)) == NULL) {
                     std::cerr << "Error on line " << linenum << std::endl;
                     exit(1);
                 }
 
-                curr->loc = ptr;
+                curr.loc = ptr;
             } else if (!strncmp(buff, "TYPE:", 5)) {
                 if ((ptr = strtok(buff + 5, WS)) == NULL) {
                     std::cerr << "Error on line " << linenum << std::endl;
@@ -351,88 +335,48 @@ main(int argc, char *argv[])
 
                 /* hack to support arrays, rather than pointers */
                 if (0 == strcmp(ptr + strlen(ptr) - 2, "[]")) {
-                    curr->array_flag = 1;
+                    curr.array_flag = 1;
                     *(ptr + strlen(ptr) - 2) = '\0';
                 }
 
-                checkDepend(curr->name, ptr, types, entries);
-                curr->type = ptr;
+                checkDepend(curr.name, ptr, types, entries);
+                curr.type = ptr;
             } else if (!strncmp(buff, "IFDEF:", 6)) {
                 if ((ptr = strtok(buff + 6, WS)) == NULL) {
                     std::cerr << "Error on line " << linenum << std::endl;
                     exit(1);
                 }
 
-                curr->ifdef = ptr;
+                curr.ifdef = ptr;
             } else if (!strcmp(buff, "DOC_START")) {
                 state = sDOC;
             } else if (!strcmp(buff, "DOC_NONE")) {
-                /* add to list of entries */
-                curr->next = entries;
-                entries = curr;
                 state = sSTART;
             } else {
                 std::cerr << "Error on line " << linenum << std::endl;
                 exit(1);
             }
-
-            break;
+        }
+        break;
 
         case sDOC:
-
             if (!strcmp(buff, "DOC_END") || !strcmp(buff, "COMMENT_END")) {
-                Line *head = NULL;
-                Line *line = curr->doc;
-                /* reverse order of doc lines */
-
-                while (line != NULL) {
-                    Line *tmp;
-                    tmp = line->next;
-                    line->next = head;
-                    head = line;
-                    line = tmp;
-                }
-
-                curr->doc = head;
-                /* add to list of entries */
-                curr->next = entries;
-                entries = curr;
                 state = sSTART;
             } else if (!strcmp(buff, "NOCOMMENT_START")) {
                 state = sNOCOMMENT;
             } else { // if (buff != NULL) {
                 assert(buff != NULL);
-                Line *line = new Line(buff);
-                line->next = curr->doc;
-                curr->doc = line;
+                entries.back().doc.push_back(buff);
             }
-
             break;
 
         case sNOCOMMENT:
-
             if (!strcmp(buff, "NOCOMMENT_END")) {
-                Line *head = NULL;
-                Line *line = curr->nocomment;
-                /* reverse order of lines */
-
-                while (line != NULL) {
-                    Line *tmp;
-                    tmp = line->next;
-                    line->next = head;
-                    head = line;
-                    line = tmp;
-                }
-
-                curr->nocomment = head;
                 state = sDOC;
             } else { // if (buff != NULL) {
                 assert(buff != NULL);
-                Line *line = new Line(buff);
-                line->next = curr->nocomment;
-                curr->nocomment = line;
+                entries.back().nocomment.push_back(buff);
             }
-
             break;
 
         case sEXIT:
@@ -445,20 +389,6 @@ main(int argc, char *argv[])
     if (state != sEXIT) {
         std::cerr << "Error: unexpected EOF\n";
         exit(1);
-    } else {
-        /* reverse order of entries */
-        Entry *head = NULL;
-
-        while (entries != NULL) {
-            Entry *tmp;
-
-            tmp = entries->next;
-            entries->next = head;
-            head = entries;
-            entries = tmp;
-        }
-
-        entries = head;
     }
 
     fp.close();
@@ -487,8 +417,6 @@ main(int argc, char *argv[])
     " * Abstract: This file contains routines used to configure the\n"
     " *           variables in the squid server.\n"
     " */\n"
-    "\n"
-    "#include \"config.h\"\n"
     "\n";
 
     rc = gen_default(entries, fout);
@@ -528,28 +456,26 @@ main(int argc, char *argv[])
 }
 
 static int
-gen_default(Entry * head, std::ostream &fout)
+gen_default(const EntryList &head, std::ostream &fout)
 {
-    Entry *entry;
     int rc = 0;
-    fout << "static void\n"
-    "default_line(const char *s)\n"
-    "{\n"
-    "\tLOCAL_ARRAY(char, tmp_line, BUFSIZ);\n"
-    "\txstrncpy(tmp_line, s, BUFSIZ);\n"
-    "\txstrncpy(config_input_line, s, BUFSIZ);\n"
-    "\tconfig_lineno++;\n"
-    "\tparse_line(tmp_line);\n"
-    "}\n";
-    fout << "static void\n"
-    "default_all(void)\n"
-    "{\n"
-    "\tcfg_filename = \"Default Configuration\";\n"
-    "\tconfig_lineno = 0;\n";
-
-    for (entry = head; entry != NULL; entry = entry->next) {
+    fout << "static void" << std::endl <<
+    "default_line(const char *s)" << std::endl << 
+    "{" << std::endl <<
+    "    LOCAL_ARRAY(char, tmp_line, BUFSIZ);" << std::endl <<
+    "    xstrncpy(tmp_line, s, BUFSIZ);" << std::endl <<
+    "    xstrncpy(config_input_line, s, BUFSIZ);" << std::endl <<
+    "    config_lineno++;" << std::endl <<
+    "    parse_line(tmp_line);" << std::endl <<
+    "}" << std::endl << std::endl;
+    fout << "static void" << std::endl <<
+    "default_all(void)" << std::endl <<
+    "{" << std::endl <<
+    "    cfg_filename = \"Default Configuration\";" << std::endl <<
+    "    config_lineno = 0;" << std::endl;
+
+    for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) {
         assert(entry->name.size());
-        assert(entry != entry->next);
 
         if (!entry->name.compare("comment"))
             continue;
@@ -563,125 +489,113 @@ gen_default(Entry * head, std::ostream &fout)
             continue;
         }
 
-        if (!entry->default_value.size() && entry->default_if_none == NULL) {
+        if (!entry->defaults.preset.size() && entry->defaults.if_none.empty()) {
             std::cerr << "NO DEFAULT FOR " << entry->name << std::endl;
             rc |= 1;
             continue;
         }
 
-        if (!entry->default_value.size() || entry->default_value.compare("none") == 0) {
-            fout << "\t/* No default for " << entry->name << " */\n";
+        if (!entry->defaults.preset.size() || entry->defaults.preset.front().compare("none") == 0) {
+            fout << "    // No default for " << entry->name << std::endl;
         } else {
             if (entry->ifdef.size())
                 fout << "#if " << entry->ifdef << std::endl;
 
-            fout << "\tdefault_line(\"" << entry->name << " " <<
-            entry->default_value << "\");\n";
+            for (LineList::const_iterator l = entry->defaults.preset.begin(); l != entry->defaults.preset.end(); ++l) {
+                fout << "    default_line(\"" << entry->name << " " << *l << "\");" << std::endl;
+            }
 
             if (entry->ifdef.size())
-                fout << "#endif\n";
+                fout << "#endif" << std::endl;
         }
     }
 
-    fout << "\tcfg_filename = NULL;\n"
-    "}\n\n";
+    fout << "    cfg_filename = NULL;" << std::endl <<
+    "}" << std::endl << std::endl;
     return rc;
 }
 
 static void
-gen_default_if_none(Entry * head, std::ostream &fout)
+gen_default_if_none(const EntryList &head, std::ostream &fout)
 {
-    Entry *entry;
-    Line *line;
-    fout << "static void\n"
-    "defaults_if_none(void)\n"
-    "{\n";
+    fout << "static void" << std::endl <<
+    "defaults_if_none(void)" << std::endl <<
+    "{" << std::endl;
 
-    for (entry = head; entry != NULL; entry = entry->next) {
+    for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) {
         assert(entry->name.size());
 
         if (!entry->loc.size())
             continue;
 
-        if (entry->default_if_none == NULL)
+        if (entry->defaults.if_none.empty())
             continue;
 
+        if (!entry->defaults.preset.empty()) {
+            std::cerr << "ERROR: " << entry->name << " has preset defaults. DEFAULT_IF_NONE cannot be true." << std::endl;
+            exit(1);
+        }
+
         if (entry->ifdef.size())
             fout << "#if " << entry->ifdef << std::endl;
 
-        if (entry->default_if_none) {
-            fout << "\tif (check_null_" << entry->type << "(" <<
-            entry->loc << ")) {\n";
-
-            for (line = entry->default_if_none; line; line = line->next)
-                fout << "\t\tdefault_line(\"" << entry->name << " " <<
-                line->data <<"\");\n";
-
-            fout << "\t}\n";
-        }
+        fout << "    if (check_null_" << entry->type << "(" << entry->loc << ")) {" << std::endl;
+        for (LineList::const_iterator l = entry->defaults.if_none.begin(); l != entry->defaults.if_none.end(); ++l)
+            fout << "        default_line(\"" << entry->name << " " << *l <<"\");" << std::endl;
+        fout << "    }" << std::endl;
 
         if (entry->ifdef.size())
-            fout << "#endif\n";
+            fout << "#endif" << std::endl;
     }
 
-    fout << "}\n\n";
+    fout << "}" << std::endl << std::endl;
 }
 
 void
-gen_parse_alias(const std::string &name, EntryAlias *alias, Entry *entry, std::ostream &fout)
+Entry::genParseAlias(const std::string &aName, std::ostream &fout) const
 {
-    fout << "\tif (!strcmp(token, \"" << name << "\")) {\n";
-
-    if (entry->type.compare("obsolete") == 0) {
-        fout << "\t\tdebugs(0, DBG_CRITICAL, \"ERROR: Directive '" << name << "' is obsolete.\");\n";
-        for (Line *line = entry->doc; line != NULL; line = line->next) {
+    fout << "    if (!strcmp(token, \"" << aName << "\")) {" << std::endl;
+    fout << "        ";
+    if (type.compare("obsolete") == 0) {
+        fout << "debugs(0, DBG_CRITICAL, \"ERROR: Directive '" << aName << "' is obsolete.\");\n";
+        for (LineList::const_iterator l = doc.begin(); l != doc.end(); ++l) {
             // offset line to strip initial whitespace tab byte
-            fout << "\t\tdebugs(0, opt_parse_cfg_only?0:1, \"" << name << " : " << &line->data[1] << "\");\n";
+            fout << "        debugs(0, opt_parse_cfg_only?0:1, \"" << aName << " : " << &(*l)[1] << "\");" << std::endl;
         }
-        fout << "\t\tparse_obsolete(token);\n";
-    } else if (!entry->loc.size() || entry->loc.compare("none") == 0) {
-        fout << "\t\tparse_" << entry->type << "();\n";
+        fout << "        parse_obsolete(token);";
+    } else if (!loc.size() || loc.compare("none") == 0) {
+        fout << "parse_" << type << "();";
     } else {
-        fout << "\t\tparse_" << entry->type << "(&" << entry->loc <<
-        (entry->array_flag ? "[0]" : "") << ");\n";
+        fout << "parse_" << type << "(&" << loc << (array_flag ? "[0]" : "") << ");";
     }
-
-    fout << "\t\treturn 1;\n";
-    fout << "\t};\n";
+    fout << std::endl;
+    fout << "        return 1;" << std::endl;
+    fout << "    };" << std::endl;
 }
 
 void
-gen_parse_entry(Entry *entry, std::ostream &fout)
+Entry::genParse(std::ostream &fout) const
 {
-    if (entry->name.compare("comment") == 0)
+    if (name.compare("comment") == 0)
         return;
 
-    if (entry->ifdef.size())
-        fout << "#if " << entry->ifdef << std::endl;
+    if (ifdef.size())
+        fout << "#if " << ifdef << std::endl;
 
-    std::string &name = entry->name;
+    // Once for the current directive name
+    genParseAlias(name, fout);
 
-    EntryAlias *alias = entry->alias;
-
-    bool more;
-
-    do {
-        gen_parse_alias(name, alias, entry, fout);
-        more = false;
-
-        if (alias) {
-            name = alias->name;
-            alias = alias->next;
-            more = true;
-        }
-    } while (more);
+    // All accepted aliases
+    for (EntryAliasList::const_iterator a = alias.begin(); a != alias.end(); ++a) {
+        genParseAlias(*a, fout);
+    }
 
-    if (entry->ifdef.size())
+    if (ifdef.size())
         fout << "#endif\n";
 }
 
 static void
-gen_parse(Entry * head, std::ostream &fout)
+gen_parse(const EntryList &head, std::ostream &fout)
 {
     fout <<
     "static int\n"
@@ -691,8 +605,8 @@ gen_parse(Entry * head, std::ostream &fout)
     "\tif ((token = strtok(buff, w_space)) == NULL) \n"
     "\t\treturn 1;\t/* ignore empty lines */\n";
 
-    for (Entry *entry = head; entry != NULL; entry = entry->next)
-        gen_parse_entry (entry, fout);
+    for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e)
+        e->genParse(fout);
 
     fout << "\treturn 0; /* failure */\n"
     "}\n\n";
@@ -700,68 +614,64 @@ gen_parse(Entry * head, std::ostream &fout)
 }
 
 static void
-gen_dump(Entry * head, std::ostream &fout)
+gen_dump(const EntryList &head, std::ostream &fout)
 {
-    Entry *entry;
     fout <<
-    "static void\n"
-    "dump_config(StoreEntry *entry)\n"
-    "{\n"
-    "    debugs(5, 4, HERE);\n";
+    "static void" << std::endl <<
+    "dump_config(StoreEntry *entry)" << std::endl <<
+    "{" << std::endl <<
+    "    debugs(5, 4, HERE);" << std::endl;
 
-    for (entry = head; entry != NULL; entry = entry->next) {
+    for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) {
 
-        if (!entry->loc.size() || entry->loc.compare("none") == 0)
+        if (!e->loc.size() || e->loc.compare("none") == 0)
             continue;
 
-        if (entry->name.compare("comment") == 0)
+        if (e->name.compare("comment") == 0)
             continue;
 
-        if (entry->ifdef.size())
-            fout << "#if " << entry->ifdef << std::endl;
+        if (e->ifdef.size())
+            fout << "#if " << e->ifdef << std::endl;
 
-        fout << "\tdump_" << entry->type << "(entry, \"" << entry->name <<
-        "\", " << entry->loc << ");\n";
+        fout << "    dump_" << e->type << "(entry, \"" << e->name << "\", " << e->loc << ");" << std::endl;
 
-        if (entry->ifdef.size())
-            fout << "#endif\n";
+        if (e->ifdef.size())
+            fout << "#endif" << std::endl;
     }
 
-    fout << "}\n\n";
+    fout << "}" << std::endl << std::endl;
 }
 
 static void
-gen_free(Entry * head, std::ostream &fout)
+gen_free(const EntryList &head, std::ostream &fout)
 {
-    Entry *entry;
     fout <<
-    "static void\n"
-    "free_all(void)\n"
-    "{\n"
-    "    debugs(5, 4, HERE);\n";
+    "static void" << std::endl <<
+    "free_all(void)" << std::endl <<
+    "{" << std::endl <<
+    "    debugs(5, 4, HERE);" << std::endl;
 
-    for (entry = head; entry != NULL; entry = entry->next) {
-        if (!entry->loc.size() || entry->loc.compare("none") == 0)
+    for (EntryList::const_iterator e = head.begin(); e != head.end(); ++e) {
+        if (!e->loc.size() || e->loc.compare("none") == 0)
             continue;
 
-        if (entry->name.compare("comment") == 0)
+        if (e->name.compare("comment") == 0)
             continue;
 
-        if (entry->ifdef.size())
-            fout << "#if " << entry->ifdef << std::endl;
+        if (e->ifdef.size())
+            fout << "#if " << e->ifdef << std::endl;
 
-        fout << "\tfree_" << entry->type << "(&" << entry->loc <<
-        (entry->array_flag ? "[0]" : "") << ");\n";
+        fout << "    free_" << e->type << "(&" << e->loc << (e->array_flag ? "[0]" : "") << ");" << std::endl;
 
-        if (entry->ifdef.size())
-            fout << "#endif\n";
+        if (e->ifdef.size())
+            fout << "#endif" << std::endl;
     }
 
-    fout << "}\n\n";
+    fout << "}" << std::endl << std::endl;
 }
 
 static bool
-defined(const std::string &name)
+isDefined(const std::string &name)
 {
     if (!name.size())
         return true;
@@ -780,7 +690,7 @@ available_if(const std::string &name)
     assert(name.size());
 
     for (int i = 0; defines[i].name; i++) {
-        if (name.compare(defines[i].name) != 0)
+        if (name.compare(defines[i].name) == 0)
             return defines[i].enable;
     }
 
@@ -788,16 +698,14 @@ available_if(const std::string &name)
 }
 
 static void
-gen_conf(Entry * head, std::ostream &fout, bool verbose_output)
+gen_conf(const EntryList &head, std::ostream &fout, bool verbose_output)
 {
-    Entry *entry;
-    char buf[8192];
-    Line *def = NULL;
-
-    for (entry = head; entry != NULL; entry = entry->next) {
-        Line *line;
+    for (EntryList::const_iterator entry = head.begin(); entry != head.end(); ++entry) {
+        char buf[8192];
+        LineList def;
         int enabled = 1;
 
+        // Display TAG: line
         if (!entry->name.compare("comment"))
             (void) 0;
         else if (!entry->name.compare("obsolete"))
@@ -811,64 +719,68 @@ gen_conf(Entry * head, std::ostream &fout, bool verbose_output)
             fout << std::endl;
         }
 
-        if (!defined(entry->ifdef)) {
+        // Display --enable/--disable disclaimer
+        if (!isDefined(entry->ifdef)) {
             if (verbose_output) {
-
-                fout << "# Note: This option is only available if "
-                "Squid is rebuilt with the\n" <<
-                "#       " << available_if(entry->ifdef) << "\n#\n";
+                fout << "# Note: This option is only available if Squid is rebuilt with the" << std::endl <<
+                "#       " << available_if(entry->ifdef) << std::endl <<
+                "#" << std::endl;
             }
             enabled = 0;
         }
 
-        if (verbose_output) {
-            for (line = entry->doc; line != NULL; line = line->next) {
-                fout << "#" << line->data << std::endl;
+        // Display DOC_START section
+        if (verbose_output && entry->doc.size()) {
+            for (LineList::const_iterator line = entry->doc.begin(); line != entry->doc.end(); ++line) {
+                fout << "#" << *line << std::endl;
             }
         }
 
-        if (entry->default_value.size() && entry->default_value.compare("none") != 0) {
-            snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), entry->default_value.c_str());
-            lineAdd(&def, buf);
-        }
-
-        if (entry->default_if_none) {
-            for (line = entry->default_if_none; line != NULL; line = line->next) {
-                snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), line->data.c_str());
-                lineAdd(&def, buf);
+        if (entry->defaults.docs.size()) {
+            // Display the DEFAULT_DOC line(s)
+            def = entry->defaults.docs;
+        } else {
+            if (entry->defaults.preset.size() && entry->defaults.preset.front().compare("none") != 0) {
+                // Display DEFAULT: line(s)
+                for (LineList::const_iterator l = entry->defaults.preset.begin(); l != entry->defaults.preset.end(); ++l) {
+                    snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str());
+                    def.push_back(buf);
+                }
+            } else if (entry->defaults.if_none.size()) {
+                // Display DEFAULT_IF_NONE: line(s)
+                for (LineList::const_iterator l = entry->defaults.if_none.begin(); l != entry->defaults.if_none.end(); ++l) {
+                    snprintf(buf, sizeof(buf), "%s %s", entry->name.c_str(), l->c_str());
+                    def.push_back(buf);
+                }
             }
         }
 
-        if (!def && entry->doc && !entry->nocomment &&
-                entry->name.compare("comment") != 0)
-            lineAdd(&def, "none");
+        // Display "none" if no default is set or comments to display
+        if (def.empty() && entry->nocomment.empty() && entry->name.compare("comment") != 0)
+            def.push_back("none");
 
-        if (verbose_output && def && (entry->doc || entry->nocomment)) {
+        if (verbose_output && def.size()) {
             fout << "#Default:\n";
-            while (def != NULL) {
-                line = def;
-                def = line->next;
-                line->next = NULL; // unlink to simplify delete
-                fout << "# " << line->data << std::endl;
-                delete line;
+            while (def.size()) {
+                fout << "# " << def.front() << std::endl;
+                def.pop_front();
             }
+            if (entry->doc.empty() && entry->nocomment.empty())
+                fout << std::endl;
         }
 
-        if (verbose_output && entry->nocomment)
+        if (verbose_output && entry->nocomment.size())
             fout << "#" << std::endl;
 
         if (enabled || verbose_output) {
-            for (line = entry->nocomment; line != NULL; line = line->next) {
-                if (!line->data.size())
-                    continue;
-                if (!enabled && line->data[0] != '#')
-                    fout << "#" << line->data << std::endl;
-                else
-                    fout << line->data << std::endl;
+            for (LineList::const_iterator line = entry->nocomment.begin(); line != entry->nocomment.end(); ++line) {
+                if (!enabled && line->at(0) != '#')
+                    fout << "#";
+                fout << *line << std::endl;
             }
         }
 
-        if (verbose_output && entry->doc != NULL) {
+        if (verbose_output && entry->doc.size()) {
             fout << std::endl;
         }
     }