[Privoxy-commits] [privoxy] 03/19: Use separate linked lists for filters of different types

User Git git at git.privoxy.org
Mon Mar 16 07:54:51 CET 2026


This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch master
in repository privoxy.

commit 6d3d5befaa7e0a4fcbd9a5f1e33cdf0573f6fd43
Author: Fabian Keil <fk at fabiankeil.de>
AuthorDate: Fri Feb 27 14:48:58 2026 +0100

    Use separate linked lists for filters of different types
    
    ... to be able look up filters more efficiently.
    
    Implements TODO item #96.
---
 cgiedit.c   | 119 +++++++++++++++++++++++++++++++-----------------------------
 cgisimple.c |  32 +++++++---------
 filters.c   |   9 +----
 loaders.c   |  56 +++++++++++++++++-----------
 project.h   |  11 ++++--
 5 files changed, 121 insertions(+), 106 deletions(-)

diff --git a/cgiedit.c b/cgiedit.c
index b9244c8f..83989074 100644
--- a/cgiedit.c
+++ b/cgiedit.c
@@ -12,7 +12,7 @@
  *
  *                Stick to the short names in this file for consistency.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2023 the
+ * Copyright   :  Written by and Copyright (C) 2001-2026 the
  *                Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -2864,74 +2864,76 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
       {
          if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL))
          {
-            filter_group = csp->rlist[i]->f;
-            for (; (!err) && (filter_group != NULL); filter_group = filter_group->next)
+            int filter_type;
+            for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
             {
-               char current_mode = 'x';
-               char number[20];
-               struct list_entry *filter_name;
-               struct map *line_exports;
-               const enum filter_type type = filter_group->type;
-               const int multi_action_index = action_type_info[type].multi_action_index;
-
-               assert(type < MAX_FILTER_TYPES);
-               assert(multi_action_index < ACTION_MULTI_COUNT);
-
-               filter_name = cur_line->data.action->multi_add[multi_action_index]->first;
-               while ((filter_name != NULL)
-                   && (0 != strcmp(filter_group->name, filter_name->str)))
+               filter_group = ((struct re_filters *)(csp->rlist[i]->f))->filters[filter_type];
+               for (; (!err) && (filter_group != NULL); filter_group = filter_group->next)
                {
-                    filter_name = filter_name->next;
-               }
+                  char current_mode = 'x';
+                  char number[20];
+                  struct list_entry *filter_name;
+                  struct map *line_exports;
+                  const int multi_action_index = action_type_info[filter_type].multi_action_index;
 
-               if (filter_name != NULL)
-               {
-                  current_mode = 'y';
-               }
-               else
-               {
-                  filter_name = cur_line->data.action->multi_remove[multi_action_index]->first;
+                  assert(multi_action_index < ACTION_MULTI_COUNT);
+
+                  filter_name = cur_line->data.action->multi_add[multi_action_index]->first;
                   while ((filter_name != NULL)
                       && (0 != strcmp(filter_group->name, filter_name->str)))
                   {
                        filter_name = filter_name->next;
                   }
+
                   if (filter_name != NULL)
                   {
-                     current_mode = 'n';
+                     current_mode = 'y';
+                  }
+                  else
+                  {
+                     filter_name = cur_line->data.action->multi_remove[multi_action_index]->first;
+                     while ((filter_name != NULL)
+                         && (0 != strcmp(filter_group->name, filter_name->str)))
+                     {
+                          filter_name = filter_name->next;
+                     }
+                     if (filter_name != NULL)
+                     {
+                        current_mode = 'n';
+                     }
                   }
-               }
-
-               /* Generate a unique serial number */
-               snprintf(number, sizeof(number), "%x", filter_identifier++);
-               number[sizeof(number) - 1] = '\0';
-
-               line_exports = new_map();
-               if (line_exports == NULL)
-               {
-                  err = JB_ERR_MEMORY;
-               }
-               else
-               {
-                  char *filter_line;
 
-                  if (!err) err = map(line_exports, "index", 1, number, 1);
-                  if (!err) err = map(line_exports, "name",  1, filter_group->name, 1);
-                  if (!err) err = map(line_exports, "description",  1, filter_group->description, 1);
-                  if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode);
-                  if (!err) err = map(line_exports, "filter-type", 1, action_type_info[type].type, 1);
-                  if (!err) err = map(line_exports, "abbr-action-type", 1, action_type_info[type].abbr_type, 1);
-                  if (!err) err = map(line_exports, "anchor", 1, action_type_info[type].anchor, 1);
+                  /* Generate a unique serial number */
+                  snprintf(number, sizeof(number), "%x", filter_identifier++);
+                  number[sizeof(number) - 1] = '\0';
 
-                  if (!err)
+                  line_exports = new_map();
+                  if (line_exports == NULL)
                   {
-                     filter_line = strdup(filter_template);
-                     if (filter_line == NULL) err = JB_ERR_MEMORY;
+                     err = JB_ERR_MEMORY;
+                  }
+                  else
+                  {
+                     char *filter_line;
+
+                     if (!err) err = map(line_exports, "index", 1, number, 1);
+                     if (!err) err = map(line_exports, "name",  1, filter_group->name, 1);
+                     if (!err) err = map(line_exports, "description",  1, filter_group->description, 1);
+                     if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode);
+                     if (!err) err = map(line_exports, "filter-type", 1, action_type_info[filter_type].type, 1);
+                     if (!err) err = map(line_exports, "abbr-action-type", 1, action_type_info[filter_type].abbr_type, 1);
+                     if (!err) err = map(line_exports, "anchor", 1, action_type_info[filter_type].anchor, 1);
+
+                     if (!err)
+                     {
+                        filter_line = strdup(filter_template);
+                        if (filter_line == NULL) err = JB_ERR_MEMORY;
+                     }
+                     if (!err) err = template_fill(&filter_line, line_exports);
+                     if (!err) err = string_join(&prepared_templates[filter_type], filter_line);
+
+                     free_map(line_exports);
                   }
-                  if (!err) err = template_fill(&filter_line, line_exports);
-                  if (!err) err = string_join(&prepared_templates[type], filter_line);
-
-                  free_map(line_exports);
                }
             }
          }
@@ -2994,6 +2996,7 @@ static int get_number_of_filters(const struct client_state *csp)
    struct re_filterfile_spec *b;
    struct file_list *fl;
    int number_of_filters = 0;
+   int filter_type;
 
    for (i = 0; i < MAX_AF_FILES; i++)
    {
@@ -3009,10 +3012,12 @@ static int get_number_of_filters(const struct client_state *csp)
          */
         continue;
      }
-
-     for (b = fl->f; b != NULL; b = b->next)
+     for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
      {
-        number_of_filters++;
+        for (b = ((struct re_filters *)fl->f)->filters[filter_type]; b != NULL; b = b->next)
+        {
+           number_of_filters++;
+        }
      }
    }
 
diff --git a/cgisimple.c b/cgisimple.c
index a6a8fada..d2735ca9 100644
--- a/cgisimple.c
+++ b/cgisimple.c
@@ -5,7 +5,7 @@
  * Purpose     :  Simple CGIs to get information about Privoxy's
  *                status.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2022 the
+ * Copyright   :  Written by and Copyright (C) 2001-2026 the
  *                Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -1202,24 +1202,20 @@ static char *get_filter_statistics_table(const struct client_state *csp)
          */
         continue;
      }
-
-     for (b = fl->f; b != NULL; b = b->next)
+     for (b = ((struct re_filters *)(fl->f))->filters[FT_CONTENT_FILTER]; b != NULL; b = b->next)
      {
-        if (b->type == FT_CONTENT_FILTER)
-        {
-           unsigned long long executions;
-           unsigned long long response_bodies_modified;
-           unsigned long long hits;
-
-           get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
-           snprintf(buf, sizeof(buf),
-              "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
-              "<td style=\"text-align: right\">%llu</td>"
-              "<td style=\"text-align: right\">%llu</td><tr>\n",
-              b->name, executions, response_bodies_modified, hits);
-
-           if (!err) err = string_append(&statistics, buf);
-        }
+        unsigned long long executions;
+        unsigned long long response_bodies_modified;
+        unsigned long long hits;
+
+        get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
+        snprintf(buf, sizeof(buf),
+           "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
+           "<td style=\"text-align: right\">%llu</td>"
+           "<td style=\"text-align: right\">%llu</td><tr>\n",
+           b->name, executions, response_bodies_modified, hits);
+
+        if (!err) err = string_append(&statistics, buf);
      }
    }
 
diff --git a/filters.c b/filters.c
index 04fa77fa..8bda3caa 100644
--- a/filters.c
+++ b/filters.c
@@ -4,7 +4,7 @@
  *
  * Purpose     :  Declares functions to parse/crunch headers and pages.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2024 the
+ * Copyright   :  Written by and Copyright (C) 2001-2026 the
  *                Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -1560,13 +1560,8 @@ struct re_filterfile_spec *get_filter(const struct client_state *csp,
         continue;
      }
 
-     for (b = fl->f; b != NULL; b = b->next)
+     for (b = ((struct re_filters *)(fl->f))->filters[requested_type]; b != NULL; b = b->next)
      {
-        if (b->type != requested_type)
-        {
-           /* The callers isn't interested in this filter type. */
-           continue;
-        }
         if (strcmp(b->name, requested_name) == 0)
         {
            /* The requested filter has been found. Abort search. */
diff --git a/loaders.c b/loaders.c
index a9820df5..b973d40a 100644
--- a/loaders.c
+++ b/loaders.c
@@ -7,7 +7,7 @@
  *                the list of active loaders, and to automatically
  *                unload files that are no longer in use.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2014 the
+ * Copyright   :  Written by and Copyright (C) 2001-2026 the
  *                Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -967,20 +967,27 @@ load_trustfile_error:
  *********************************************************************/
 static void unload_re_filterfile(void *f)
 {
-   struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
+   int filter_type;
 
-   while (b != NULL)
+   for (filter_type = 0; filter_type < MAX_FILTER_TYPES; filter_type++)
    {
-      a = b->next;
+      struct re_filterfile_spec *a, *b;
 
-      destroy_list(b->patterns);
-      pcrs_free_joblist(b->joblist);
-      freez(b->name);
-      freez(b->description);
-      freez(b);
+      b = ((struct re_filters *)f)->filters[filter_type];
+      while (b != NULL)
+      {
+         a = b->next;
+
+         destroy_list(b->patterns);
+         pcrs_free_joblist(b->joblist);
+         freez(b->name);
+         freez(b->description);
+         freez(b);
 
-      b = a;
+         b = a;
+      }
    }
+   freez(f);
 
    return;
 }
@@ -1103,11 +1110,14 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
 
    struct re_filterfile_spec *new_bl, *bl = NULL;
    struct file_list *fs;
+   struct re_filters last_filters;
 
    char *buf = NULL;
    unsigned long linenum = 0;
    pcrs_job *dummy, *lastjob = NULL;
+   enum filter_type current_filter = FT_INVALID_FILTER;
 
+   memset(&last_filters, 0, sizeof(last_filters));
    /*
     * No need to reload if unchanged
     */
@@ -1179,6 +1189,7 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
        */
       if (new_filter != FT_INVALID_FILTER)
       {
+         current_filter = new_filter;
          new_bl = zalloc_or_die(sizeof(*bl));
          if (new_filter == FT_CONTENT_FILTER)
          {
@@ -1202,7 +1213,6 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
          {
             new_bl->name = chomp(buf + 21);
          }
-         new_bl->type = new_filter;
 
          /*
           * If a filter description is available,
@@ -1225,23 +1235,27 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
 
          new_bl->name = strdup_or_die(chomp(new_bl->name));
 
-         /*
-          * If this is the first filter block, chain it
-          * to the file_list rather than its (nonexistent)
-          * predecessor
-          */
          if (fs->f == NULL)
          {
-            fs->f = new_bl;
+            fs->f = zalloc_or_die(sizeof(struct re_filters));
+         }
+
+         if (((struct re_filters *)(fs->f))->filters[new_filter] == NULL)
+         {
+            ((struct re_filters *)(fs->f))->filters[new_filter] = new_bl;
          }
          else
          {
-            assert(NULL != bl);
-            bl->next = new_bl;
+            if (last_filters.filters[new_filter] != NULL)
+            {
+               last_filters.filters[new_filter]->next = new_bl;
+            }
          }
          bl = new_bl;
+         last_filters.filters[new_filter] = new_bl;
 
-         log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
+         log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\"). Type %d.",
+            bl->name, bl->description, new_filter);
 #ifdef FEATURE_EXTENDED_STATISTICS
          register_filter_for_statistics(bl->name);
 #endif
@@ -1250,7 +1264,7 @@ int load_one_re_filterfile(struct client_state *csp, int fileid)
       }
 
 #ifdef FEATURE_EXTERNAL_FILTERS
-      if ((bl != NULL) && (bl->type == FT_EXTERNAL_CONTENT_FILTER))
+      if ((bl != NULL) && (current_filter == FT_EXTERNAL_CONTENT_FILTER))
       {
          jb_err jb_error;
          /* Save the code as "pattern", but do not compile anything. */
diff --git a/project.h b/project.h
index 9f3c36ef..9075c9b7 100644
--- a/project.h
+++ b/project.h
@@ -8,7 +8,7 @@
  *                project.  Does not define any variables or functions
  *                (though it does declare some macros).
  *
- * Copyright   :  Written by and Copyright (C) 2001-2021 the
+ * Copyright   :  Written by and Copyright (C) 2001-2026 the
  *                Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
@@ -1338,7 +1338,8 @@ enum filter_type
  * This struct represents one filter (one block) from
  * the re_filterfile. If there is more than one filter
  * in the file, the file will be represented by a
- * chained list of re_filterfile specs.
+ * chained list of re_filterfile specs of the same filter
+ * type.
  */
 struct re_filterfile_spec
 {
@@ -1346,12 +1347,16 @@ struct re_filterfile_spec
    char *description;               /**< Description from FILTER: statement in re_filterfile. */
    struct list patterns[1];         /**< The patterns from the re_filterfile. */
    pcrs_job *joblist;               /**< The resulting compiled pcrs_jobs. */
-   enum filter_type type;           /**< Filter type (content, client-header, server-header). */
    int dynamic;                     /**< Set to one if the pattern might contain variables
                                          and has to be recompiled for every request. */
    struct re_filterfile_spec *next; /**< The pointer for chaining. */
 };
 
+struct re_filters
+{
+   struct re_filterfile_spec *filters[MAX_FILTER_TYPES];
+};
+
 
 #ifdef FEATURE_ACL
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Privoxy-commits mailing list