+ snprintf(rebuf, sizeof(rebuf), fmt, pattern);
+
+ errcode = regcomp(*regex, rebuf, (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+ if (errcode)
+ {
+ size_t errlen = regerror(errcode, *regex, rebuf, sizeof(rebuf));
+ if (errlen > (sizeof(rebuf) - (size_t)1))
+ {
+ errlen = sizeof(rebuf) - (size_t)1;
+ }
+ rebuf[errlen] = '\0';
+ log_error(LOG_LEVEL_ERROR, "error compiling %s from %s: %s",
+ pattern, url->spec, rebuf);
+ free_pattern_spec(url);
+
+ return JB_ERR_PARSE;
+ }
+
+ return JB_ERR_OK;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : compile_url_pattern
+ *
+ * Description : Compiles the three parts of an URL pattern.
+ *
+ * Parameters :
+ * 1 : url = Target pattern_spec to be filled in.
+ * 2 : buf = The url pattern to compile. Will be messed up.
+ *
+ * Returns : JB_ERR_OK - Success
+ * JB_ERR_MEMORY - Out of memory
+ * JB_ERR_PARSE - Cannot parse regex
+ *
+ *********************************************************************/
+static jb_err compile_url_pattern(struct pattern_spec *url, char *buf)
+{
+ char *p;
+
+ p = strchr(buf, '/');
+ if (NULL != p)
+ {
+ /*
+ * Only compile the regex if it consists of more than
+ * a single slash, otherwise it wouldn't affect the result.
+ */
+ if (p[1] != '\0')
+ {
+ /*
+ * XXX: does it make sense to compile the slash at the beginning?
+ */
+ jb_err err = compile_pattern(p, LEFT_ANCHORED, url, &url->pattern.url_spec.preg);
+
+ if (JB_ERR_OK != err)
+ {
+ return err;
+ }
+ }
+ *p = '\0';
+ }
+
+ /*
+ * IPv6 numeric hostnames can contain colons, thus we need
+ * to delimit the hostname before the real port separator.
+ * As brackets are already used in the hostname pattern,
+ * we use angle brackets ('<', '>') instead.
+ */
+ if ((buf[0] == '<') && (NULL != (p = strchr(buf + 1, '>'))))
+ {
+ *p++ = '\0';
+ buf++;
+
+ if (*p == '\0')
+ {
+ /* IPv6 address without port number */
+ p = NULL;
+ }
+ else if (*p != ':')
+ {
+ /* Garbage after address delimiter */
+ return JB_ERR_PARSE;
+ }
+ }
+ else
+ {
+ p = strchr(buf, ':');
+ }
+
+ if (NULL != p)
+ {
+ *p++ = '\0';
+ url->pattern.url_spec.port_list = strdup_or_die(p);
+ }
+ else
+ {
+ url->pattern.url_spec.port_list = NULL;
+ }
+
+ if (buf[0] != '\0')
+ {
+ return compile_host_pattern(url, buf);
+ }
+
+ return JB_ERR_OK;
+
+}
+
+
+#ifdef FEATURE_EXTENDED_HOST_PATTERNS
+/*********************************************************************
+ *
+ * Function : compile_host_pattern
+ *
+ * Description : Parses and compiles a host pattern.
+ *
+ * Parameters :
+ * 1 : url = Target pattern_spec to be filled in.
+ * 2 : host_pattern = Host pattern to compile.
+ *
+ * Returns : JB_ERR_OK - Success
+ * JB_ERR_MEMORY - Out of memory
+ * JB_ERR_PARSE - Cannot parse regex
+ *
+ *********************************************************************/
+static jb_err compile_host_pattern(struct pattern_spec *url, const char *host_pattern)
+{
+ return compile_pattern(host_pattern, RIGHT_ANCHORED_HOST, url, &url->pattern.url_spec.host_regex);
+}
+
+#else
+
+/*********************************************************************
+ *
+ * Function : compile_host_pattern
+ *
+ * Description : Parses and "compiles" an old-school host pattern.
+ *
+ * Parameters :
+ * 1 : url = Target pattern_spec to be filled in.
+ * 2 : host_pattern = Host pattern to parse.
+ *
+ * Returns : JB_ERR_OK - Success
+ * JB_ERR_PARSE - Cannot parse regex
+ *
+ *********************************************************************/
+static jb_err compile_host_pattern(struct pattern_spec *url, const char *host_pattern)
+{
+ char *v[150];
+ size_t size;
+ char *p;
+
+ /*
+ * Parse domain part
+ */
+ if (host_pattern[strlen(host_pattern) - 1] == '.')
+ {
+ url->pattern.url_spec.unanchored |= ANCHOR_RIGHT;
+ }
+ if (host_pattern[0] == '.')
+ {
+ url->pattern.url_spec.unanchored |= ANCHOR_LEFT;
+ }
+
+ /*
+ * Split domain into components
+ */
+ url->pattern.url_spec.dbuffer = strdup_or_die(host_pattern);
+
+ /*
+ * Map to lower case
+ */
+ for (p = url->pattern.url_spec.dbuffer; *p ; p++)
+ {
+ *p = (char)privoxy_tolower(*p);
+ }
+
+ /*
+ * Split the domain name into components
+ */
+ url->pattern.url_spec.dcount = ssplit(url->pattern.url_spec.dbuffer, ".", v, SZ(v));
+
+ if (url->pattern.url_spec.dcount < 0)
+ {
+ free_pattern_spec(url);
+ return JB_ERR_PARSE;
+ }
+ else if (url->pattern.url_spec.dcount != 0)
+ {
+ /*
+ * Save a copy of the pointers in dvec
+ */
+ size = (size_t)url->pattern.url_spec.dcount * sizeof(*url->pattern.url_spec.dvec);
+
+ url->pattern.url_spec.dvec = malloc_or_die(size);
+
+ memcpy(url->pattern.url_spec.dvec, v, size);
+ }
+ /*
+ * else dcount == 0 in which case we needn't do anything,
+ * since dvec will never be accessed and the pattern will
+ * match all domains.
+ */