[prev in list] [next in list] [prev in thread] [next in thread] 

List:       squid-dev
Subject:    Re: [PATCH] HttpHdrSc c++ refactoring
From:       Kinkie <gkinkie () gmail ! com>
Date:       2011-11-18 7:42:19
Message-ID: CA+Y8hcMOeFOw44HM5JNjOnNe1Wer+xmxArCrVZArW0aeWPK_Ug () mail ! gmail ! com
[Download RAW message or body]

>> +/**
>> + * look for the last occurrence of a character in a c-string with a set maximum length
>> + */
>> +SQUIDCEXTERN const char *strnrchr(const char *s, size_t slen, char c);
>
> Please fix the strnrchr() description. To match the implementation, the
> description should say that we scan from the beginning and stop at the
> end of the c-string or n-th character, whichever comes first (and
> s/slen/n/).

Done (although s/slen/count/ to match the

> I would also recommend checking whether your strnrchr() implementation
> matches that of GNU API. Their documentation is even worse:
>   http://gnugeneration.com/mirrors/kernel-api/r2320.html

Done.

>
>
>> -            if (!sctusable || sctusable->content.size() == 0)
>> +            if (!sctusable || sctusable->hasContent())
>
> Sorry if I asked you about this already, but is the reversal of the
> second condition above intentional?

No, it wasn't.
Thanks for spotting that, and sorry for missing it if you asked already :(

>>   class HttpHdrSc
>>   {
>>
>>   public:
>> +      bool parse(const String *str);
>> +      ~HttpHdrSc();
>> +      HttpHdrSc(const HttpHdrSc &);
>
> Please move the parse() declaration below constructors/destructors.

Done.

>> +      HttpHdrSc() {};
>
> Extra semicolon.

Removed.

>>>> >> +      String Content() const { return content; }
>>> >
>>> > I would s/content/content_/ instead, especially since content data
>>> > member is private. Capitalization should be used for static methods.
>>
>> Ok.
>
> If that "Ok" meant "will do later", then please note that you have not
> done that.

Gah! Sorry.. Now done.
New version attached.

-- 
      /kinkie

["playground-httphdrsc-v4.patch" (text/x-diff)]

=== modified file 'compat/Makefile.am'
--- compat/Makefile.am	2011-10-26 16:33:46 +0000
+++ compat/Makefile.am	2011-11-17 23:25:48 +0000
@@ -22,40 +22,42 @@
 	debug.h \
 	drand48.h \
 	eui64_aton.h \
 	fdsetsize.h \
 	getaddrinfo.h \
 	getnameinfo.h \
 	GnuRegex.c \
 	GnuRegex.h \
 	inet_ntop.h \
 	inet_pton.h \
 	initgroups.h \
 	osdetect.h \
 	psignal.h \
 	shm.cc \
 	shm.h \
 	stdio.h \
 	stdvarargs.h \
 	strnstr.cc \
 	strsep.h \
 	strtoll.h \
+	strnrchr.h \
+	strnrchr.c \
 	tempnam.h \
 	types.h \
 	unsafe.h \
 	valgrind.h \
 	xalloc.cc \
 	xalloc.h \
 	xis.h \
 	xstrerror.cc \
 	xstrerror.h \
 	xstring.cc \
 	xstring.h \
 	xstrto.cc \
 	xstrto.h \
 	\
 	os/aix.h \
 	os/dragonfly.h \
 	os/freebsd.h \
 	os/hpux.h \
 	os/linux.h \
 	os/macosx.h \

=== added file 'compat/strnrchr.c'
--- compat/strnrchr.c	1970-01-01 00:00:00 +0000
+++ compat/strnrchr.c	2011-11-18 06:09:15 +0000
@@ -0,0 +1,46 @@
+/*
+ * strnrchr.c
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#include "config.h"
+#include "strnrchr.h"
+
+const char *
+strnrchr(const char *s, size_t count, int c)
+{
+	const char *rv=NULL;
+	const char *l=s;
+	while (count > 0 && *l != 0) {
+		if (*l==c)
+			rv=l;
+		++l;
+		--count;
+	}
+	return rv;
+}

=== added file 'compat/strnrchr.h'
--- compat/strnrchr.h	1970-01-01 00:00:00 +0000
+++ compat/strnrchr.h	2011-11-18 06:09:00 +0000
@@ -0,0 +1,46 @@
+/*
+ * strnrchr.h
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; see the CREDITS file for full details.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ */
+
+#ifndef COMPAT_STRNRCHR_H_
+#define COMPAT_STRNRCHR_H_
+
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+/**
+ * look for the last occurrence of a character in a c-string.
+ *
+ * Scanning starts at the beginning of the c-string, and ends
+ * after count bytes or at the end of the c-string, whichever happens first
+ */
+SQUIDCEXTERN const char *strnrchr(const char *s, size_t count, int c);
+
+#endif /* COMPAT_STRNRCHR_H_ */

=== modified file 'src/HttpHdrSc.cc'
--- src/HttpHdrSc.cc	2010-11-02 00:49:51 +0000
+++ src/HttpHdrSc.cc	2011-11-18 06:25:02 +0000
@@ -1,407 +1,394 @@
 
 /*
  * $Id$
  *
  * DEBUG: section 90    HTTP Cache Control Header
  * AUTHOR: Alex Rousskov
  *         Robert Collins (Surrogate-Control is derived from
  *         		   Cache-Control).
+ *         Francesco Chemolli (c++ refactoring)
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
  *
  *  Squid is the result of efforts by numerous individuals from
  *  the Internet community; see the CONTRIBUTORS file for full
  *  details.   Many organizations have provided support for Squid's
  *  development; see the SPONSORS file for full details.  Squid is
  *  Copyrighted (C) 2001 by the Regents of the University of
  *  California; see the COPYRIGHT file for full details.  Squid
  *  incorporates software developed and/or copyrighted by other
  *  sources; see the CREDITS file for full details.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "Store.h"
 #include "HttpHeader.h"
 #include "HttpHdrSc.h"
 
+#if HAVE_MAP
+#include <map>
+#endif
+
+/* a row in the table used for parsing surrogate-control header and statistics */
+typedef struct {
+	const char *name;
+	http_hdr_sc_type id;
+	HttpHeaderFieldStat stat;
+} HttpHeaderScFields;
+
 /* this table is used for parsing surrogate control header */
+/* order must match that of enum http_hdr_sc_type. The constraint is verified at \
initialization time */ +//todo: implement constraint
 static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = {
     {"no-store", (http_hdr_type)SC_NO_STORE},
-
     {"no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE},
     {"max-age", (http_hdr_type)SC_MAX_AGE},
     {"content", (http_hdr_type)SC_CONTENT},
     {"Other,", (http_hdr_type)SC_OTHER}	/* ',' will protect from matches */
 };
 
 HttpHeaderFieldInfo *ScFieldsInfo = NULL;
 
 http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader)
 {
     int tmp = (int)aHeader;
     aHeader = (http_hdr_sc_type)(++tmp);
     return aHeader;
 }
 
 int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2)
 {
     return (int)anSc - (int)anSc2;
 }
 
 
-/* local prototypes */
-static int httpHdrScParseInit(HttpHdrSc * sc, const String * str);
-
 /* module initialization */
 
 void
 httpHdrScInitModule(void)
 {
     ScFieldsInfo = httpHeaderBuildFieldsInfo(ScAttrs, SC_ENUM_END);
 }
 
 void
 httpHdrScCleanModule(void)
 {
     httpHeaderDestroyFieldsInfo(ScFieldsInfo, SC_ENUM_END);
     ScFieldsInfo = NULL;
 }
 
 /* implementation */
 
-HttpHdrSc *
-httpHdrScCreate(void)
-{
-    return new HttpHdrSc();
-}
-
 /* creates an sc object from a 0-terminating string */
 HttpHdrSc *
-httpHdrScParseCreate(const String * str)
+httpHdrScParseCreate(const String & str)
 {
-    HttpHdrSc *sc = httpHdrScCreate();
+    HttpHdrSc *sc = new HttpHdrSc();
 
-    if (!httpHdrScParseInit(sc, str)) {
-        httpHdrScDestroy(sc);
+    if (!sc->parse(&str)) {
+        delete sc;
         sc = NULL;
     }
 
     return sc;
 }
 
 /* parses a 0-terminating string and inits sc */
-static int
-httpHdrScParseInit(HttpHdrSc * sc, const String * str)
+bool
+HttpHdrSc::parse(const String * str)
 {
+    HttpHdrSc * sc=this;
     const char *item;
     const char *p;		/* '=' parameter */
     const char *pos = NULL;
     const char *target = NULL; /* ;foo */
     const char *temp = NULL; /* temp buffer */
     int type;
     int ilen, vlen;
     int initiallen;
     HttpHdrScTarget *sct;
-    assert(sc && str);
+    assert(str);
 
     /* iterate through comma separated list */
 
     while (strListGetItem(str, ',', &item, &ilen, &pos)) {
         initiallen = ilen;
         vlen = 0;
         /* decrease ilen to still match the token for  '=' statements */
 
         if ((p = strchr(item, '=')) && (p - item < ilen)) {
             vlen = ilen - (p + 1 - item);
             ilen = p - item;
             p++;
         }
 
         /* decrease ilen to still match the token for ';' qualified non '=' \
statments */  else if ((p = strchr(item, ';')) && (p - item < ilen))
             ilen = p++ - item;
 
         /* find type */
+        /* TODO: use a type-safe map-based lookup */
         type = httpHeaderIdByName(item, ilen,
                                   ScFieldsInfo, SC_ENUM_END);
 
         if (type < 0) {
             debugs(90, 2, "hdr sc: unknown control-directive: near '" << item << "' \
in '" << str << "'");  type = SC_OTHER;
         }
 
         /* Is this a targeted directive? */
-        /* TODO sometime: implement a strnrchr that looks at a substring */
+        /* TODO: remove the temporary useage and use memrchr and the information we \
have instead */  temp = xstrndup (item, initiallen + 1);
 
         if (!((target = strrchr (temp, ';')) && !strchr (target, '"') && *(target + \
1) != '\0'))  target = NULL;
         else
             ++target;
 
-        sct = httpHdrScFindTarget (sc, target);
+        sct = sc->findTarget(target);
 
         if (!sct) {
-            sct = httpHdrScTargetCreate (target);
-            dlinkAdd(sct, &sct->node, &sc->targets);
+            sct = new HttpHdrScTarget(target);
+            addTarget(sct);
         }
 
         safe_free (temp);
 
-        if (EBIT_TEST(sct->mask, type)) {
+        if (sct->isSet(static_cast<http_hdr_sc_type>(type))) {
             if (type != SC_OTHER)
                 debugs(90, 2, "hdr sc: ignoring duplicate control-directive: near '" \
<< item << "' in '" << str << "'");  
             ScFieldsInfo[type].stat.repCount++;
 
             continue;
         }
 
-        /* update mask */
-        EBIT_SET(sct->mask, type);
-
-        /* post-processing special cases */
+        /* process directives */
         switch (type) {
+        case SC_NO_STORE:
+            sct->noStore(true);
+            break;
 
-        case SC_MAX_AGE:
-
-            if (!p || !httpHeaderParseInt(p, &sct->max_age)) {
-                debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
-                sct->max_age = -1;
-                EBIT_CLR(sct->mask, type);
-            }
-
-            if ((p = strchr (p, '+')))
-                if (!httpHeaderParseInt(++p, &sct->max_stale)) {
-                    debugs(90, 2, "sc: invalid max-stale specs near '" << item << \
                "'");
-                    sct->max_stale = 0;
-                    /* leave the max-age alone */
-                }
-
+        case SC_NO_STORE_REMOTE:
+            sct->noStoreRemote(true);
             break;
 
+        case SC_MAX_AGE:
+        	{
+        	    int ma;
+        	    if (p && httpHeaderParseInt(p, &ma)) {
+        	        sct->maxAge(ma);
+        	    } else {
+        	        debugs(90, 2, "sc: invalid max-age specs near '" << item << "'");
+        	        sct->clearMaxAge();
+        	    }
+
+        	    if ((p = strchr (p, '+'))) {
+        	        int ms;
+        	        ++p; //skip the + char
+        	        if (httpHeaderParseInt(p, &ms)) {
+        	            sct->maxStale(ms);
+        	        } else {
+        	            debugs(90, 2, "sc: invalid max-stale specs near '" << item << \
"'"); +        	            sct->clearMaxStale();
+        	            /* leave the max-age alone */
+        	        }
+        	    }
+        	    break;
+        	}
+
         case SC_CONTENT:
 
-            if (!p || !httpHeaderParseQuotedString(p, vlen, &sct->content)) {
+        	if ( p && httpHeaderParseQuotedString(p, vlen, &sct->content_)) {
+        		sct->setMask(SC_CONTENT,true); // ugly but saves a copy
+        	} else {
                 debugs(90, 2, "sc: invalid content= quoted string near '" << item << \
                "'");
-                sct->content.clean();
-                EBIT_CLR(sct->mask, type);
+                sct->clearContent();
             }
+        	break;
 
+        case SC_OTHER:
         default:
             break;
         }
     }
 
     return sc->targets.head != NULL;
 }
 
-void
-httpHdrScDestroy(HttpHdrSc * sc)
+HttpHdrSc::~HttpHdrSc()
 {
-    assert(sc);
-
-    if (sc->targets.head) {
-        dlink_node *sct = sc->targets.head;
+    if (targets.head) {
+        dlink_node *sct = targets.head;
 
         while (sct) {
-            HttpHdrScTarget *t = (HttpHdrScTarget *)sct->data;
+            HttpHdrScTarget *t = static_cast<HttpHdrScTarget *>(sct->data);
             sct = sct->next;
-            dlinkDelete (&t->node, &sc->targets);
-            httpHdrScTargetDestroy (t);
+            dlinkDelete (&t->node, &targets);
+            delete t;
         }
     }
-
-    delete sc;
 }
 
-HttpHdrSc *
-httpHdrScDup(const HttpHdrSc * sc)
+
+HttpHdrSc::HttpHdrSc(const HttpHdrSc &sc)
 {
-    HttpHdrSc *dup;
-    dlink_node *node;
-    assert(sc);
-    node = sc->targets.head;
-    dup = httpHdrScCreate();
+    dlink_node *node = sc.targets.head;
 
     while (node) {
-        HttpHdrScTarget *dupsct;
-        dupsct = httpHdrScTargetDup ((HttpHdrScTarget *)node->data);
-        dlinkAddTail (dupsct, &dupsct->node, &dup->targets);
+        HttpHdrScTarget *dupsct = new HttpHdrScTarget(*static_cast<HttpHdrScTarget \
*>(node->data)); +        addTargetAtTail(dupsct);
         node = node->next;
     }
-
-    return dup;
 }
 
 void
-httpHdrScTargetPackInto(const HttpHdrScTarget * sc, Packer * p)
+HttpHdrScTarget::packInto(Packer * p) const
 {
     http_hdr_sc_type flag;
     int pcount = 0;
-    assert(sc && p);
+    assert (p);
 
     for (flag = SC_NO_STORE; flag < SC_ENUM_END; ++flag) {
-        if (EBIT_TEST(sc->mask, flag) && flag != SC_OTHER) {
+        if (isSet(flag) && flag != SC_OTHER) {
 
             /* print option name */
             packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
                          SQUIDSTRINGPRINT(ScFieldsInfo[flag].name));
 
             /* handle options with values */
 
             if (flag == SC_MAX_AGE)
-                packerPrintf(p, "=%d", (int) sc->max_age);
+                packerPrintf(p, "=%d", (int) max_age);
 
             if (flag == SC_CONTENT)
-                packerPrintf(p, "=\"" SQUIDSTRINGPH "\"", \
SQUIDSTRINGPRINT(sc->content)); +                packerPrintf(p, "=\"" SQUIDSTRINGPH \
"\"", SQUIDSTRINGPRINT(content_));  
             pcount++;
         }
     }
 
-    if (sc->target.size())
-        packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(sc->target));
+    if (hasTarget())
+        packerPrintf (p, ";" SQUIDSTRINGPH, SQUIDSTRINGPRINT(target));
 }
 
 void
-httpHdrScPackInto(const HttpHdrSc * sc, Packer * p)
+HttpHdrSc::packInto(Packer * p) const
 {
     dlink_node *node;
-    assert(sc && p);
-    node = sc->targets.head;
+    assert(p);
+    node = targets.head;
 
     while (node) {
-        httpHdrScTargetPackInto((HttpHdrScTarget *)node->data, p);
+    	static_cast<HttpHdrScTarget *>(node->data)->packInto(p);
         node = node->next;
     }
 }
 
-void
-httpHdrScJoinWith(HttpHdrSc * sc, const HttpHdrSc * new_sc)
-{
-    assert(sc && new_sc);
-#if 0
-    /* RC TODO: check that both have the same target */
-
-    if (sc->max_age < 0)
-        sc->max_age = new_sc->max_age;
-
-    /* RC TODO: copy unique missing stringlist entries */
-    cc->mask |= new_cc->mask;
-
-#endif
-}
-
 /* negative max_age will clean old max_Age setting */
 void
-httpHdrScSetMaxAge(HttpHdrSc * sc, char const *target, int max_age)
+HttpHdrSc::setMaxAge(char const *target, int max_age)
 {
-    HttpHdrScTarget *sct;
-    assert(sc);
-    sct = httpHdrScFindTarget (sc, target);
+    HttpHdrScTarget *sct = findTarget(target);
 
     if (!sct) {
-        sct = httpHdrScTargetCreate (target);
-        dlinkAddTail (sct, &sct->node, &sc->targets);
+        sct = new HttpHdrScTarget(target);
+        dlinkAddTail (sct, &sct->node, &targets);
     }
 
-    httpHdrScTargetSetMaxAge(sct, max_age);
+    sct->maxAge(max_age);
 }
 
 void
-httpHdrScUpdateStats(const HttpHdrSc * sc, StatHist * hist)
+HttpHdrSc::updateStats(StatHist * hist) const
 {
-    dlink_node *sct;
-    assert(sc);
-    sct = sc->targets.head;
+    dlink_node *sct = targets.head;
 
     while (sct) {
-        httpHdrScTargetUpdateStats((HttpHdrScTarget *)sct->data, hist);
+    	static_cast<HttpHdrScTarget *>(sct->data)->updateStats(hist);
         sct = sct->next;
     }
 }
 
 void
 httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, double size, int \
count)  {
     extern const HttpHeaderStat *dump_stat;     /* argh! */
     const int id = (int) val;
     const int valid_id = id >= 0 && id < SC_ENUM_END;
     const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
                           id, name, count, xdiv(count, dump_stat->scParsedCount));
 }
 
 void
 httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double size, int \
count)  {
     extern const HttpHeaderStat *dump_stat;	/* argh! */
     const int id = (int) val;
     const int valid_id = id >= 0 && id < SC_ENUM_END;
     const char *name = valid_id ? ScFieldsInfo[id].name.termedBuf() : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
                           id, name, count, xdiv(count, dump_stat->scParsedCount));
 }
 
 HttpHdrScTarget *
-httpHdrScFindTarget (HttpHdrSc *sc, const char *target)
+HttpHdrSc::findTarget(const char *target)
 {
     dlink_node *node;
-    assert (sc);
-    node = sc->targets.head;
+    node = targets.head;
 
     while (node) {
         HttpHdrScTarget *sct = (HttpHdrScTarget *)node->data;
 
         if (target && sct->target.defined() && !strcmp (target, \
sct->target.termedBuf()))  return sct;
         else if (!target && sct->target.undefined())
             return sct;
 
         node = node->next;
     }
 
     return NULL;
 }
 
 HttpHdrScTarget *
-httpHdrScGetMergedTarget (HttpHdrSc *sc, const char *ourtarget)
+HttpHdrSc::getMergedTarget(const char *ourtarget)
 {
-    HttpHdrScTarget *sctus = httpHdrScFindTarget (sc, ourtarget);
-    HttpHdrScTarget *sctgeneric = httpHdrScFindTarget (sc, NULL);
+    HttpHdrScTarget *sctus = findTarget(ourtarget);
+    HttpHdrScTarget *sctgeneric = findTarget(NULL);
 
     if (sctgeneric || sctus) {
-        HttpHdrScTarget *sctusable = httpHdrScTargetCreate (NULL);
+        HttpHdrScTarget *sctusable = new HttpHdrScTarget(NULL);
 
         if (sctgeneric)
-            httpHdrScTargetMergeWith (sctusable, sctgeneric);
+            sctusable->mergeWith(sctgeneric);
 
         if (sctus)
-            httpHdrScTargetMergeWith (sctusable, sctus);
+            sctusable->mergeWith(sctus);
 
         return sctusable;
     }
 
     return NULL;
 }

=== modified file 'src/HttpHdrSc.h'
--- src/HttpHdrSc.h	2009-01-21 03:47:47 +0000
+++ src/HttpHdrSc.h	2011-11-18 06:20:50 +0000
@@ -26,45 +26,53 @@
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #ifndef SQUID_HTTPHDRSURROGATECONTROL_H
 #define SQUID_HTTPHDRSURROGATECONTROL_H
 
 #include "dlink.h"
 #include "HttpHdrScTarget.h"
 
 /* http surogate control header field */
 
 class HttpHdrSc
 {
 
 public:
+    HttpHdrSc(const HttpHdrSc &);
+    HttpHdrSc() {}
+    ~HttpHdrSc();
+
+    bool parse(const String *str);
+    void packInto(Packer * p) const;
+    void updateStats(StatHist *) const;
+    HttpHdrScTarget * getMergedTarget (const char *ourtarget); //todo: make const?
+    void setMaxAge(char const *target, int max_age);
+    void addTarget(HttpHdrScTarget *t) {
+        dlinkAdd(t, &t->node, &targets);
+    }
+    void addTargetAtTail(HttpHdrScTarget *t) {
+        dlinkAddTail (t, &t->node, &targets);
+    }
+
     MEMPROXY_CLASS(HttpHdrSc);
     dlink_list targets;
+private:
+    HttpHdrScTarget * findTarget (const char *target);
+
 };
 
 MEMPROXY_CLASS_INLINE(HttpHdrSc);
 
 /* Http Surrogate Control Header Field */
 extern void httpHdrScStatDumper(StoreEntry * sentry, int idx, double val, double \
size, int count);  extern void httpHdrScInitModule (void);
 extern void httpHdrScCleanModule (void);
-extern HttpHdrSc *httpHdrScCreate(void);
-extern HttpHdrSc *httpHdrScParseCreate(String const *);
-extern void httpHdrScDestroy(HttpHdrSc * sc);
-extern HttpHdrSc *httpHdrScDup(const HttpHdrSc * sc);
-extern void httpHdrScPackInto(const HttpHdrSc * sc, Packer * p);
-extern void httpHdrScJoinWith(HttpHdrSc *, const HttpHdrSc *);
+extern HttpHdrSc *httpHdrScParseCreate(String const &);
 extern void httpHdrScSetMaxAge(HttpHdrSc *, char const *, int);
-extern void httpHdrScUpdateStats(const HttpHdrSc *, StatHist *);
-extern HttpHdrScTarget * httpHdrScFindTarget (HttpHdrSc *sc, const char *target);
-extern HttpHdrScTarget * httpHdrScGetMergedTarget (HttpHdrSc *sc, const char \
                *ourtarget);
-
-extern void httpHeaderPutSc(HttpHeader *hdr, const HttpHdrSc *sc);
-extern HttpHdrSc *httpHeaderGetSc(const HttpHeader *hdr);
 
 #endif /* SQUID_HTTPHDRSURROGATECONTROL_H */

=== modified file 'src/HttpHdrScTarget.cc'
--- src/HttpHdrScTarget.cc	2009-01-31 18:23:44 +0000
+++ src/HttpHdrScTarget.cc	2011-11-18 06:25:35 +0000
@@ -21,131 +21,55 @@
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "HttpHdrSc.h"
 
-/* local prototypes */
-
-/* module initialization */
-
-/* implementation */
-
-HttpHdrScTarget *
-httpHdrScTargetCreate(char const *target)
-{
-    HttpHdrScTarget *sc = new HttpHdrScTarget();
-    sc->max_age = -1;
-    /* max_stale is specified as 0 if not specified in the header */
-    sc->target = target;
-    return sc;
-}
-
-void
-httpHdrScTargetDestroy(HttpHdrScTarget * sc)
-{
-    assert(sc);
-    sc->target.clean();
-    sc->content.clean();
-    delete sc;
-}
-
-HttpHdrScTarget *
-httpHdrScTargetDup(const HttpHdrScTarget * sc)
-{
-    HttpHdrScTarget *dup;
-    assert(sc);
-    dup = httpHdrScTargetCreate(sc->target.termedBuf());
-    dup->mask = sc->mask;
-    dup->max_age = sc->max_age;
-    dup->content = sc->content;
-    return dup;
-}
-
-/* union of two targets */
-void
-httpHdrScTargetJoinWith(HttpHdrScTarget * sc, const HttpHdrScTarget * new_sc)
-{
-    assert(sc && new_sc);
-    /* TODO: check both targets are the same */
-
-    if (sc->max_age < 0)
-        sc->max_age = new_sc->max_age;
-
-    if (sc->max_stale < new_sc->max_stale)
-        sc->max_stale = new_sc->max_stale;
-
-    /* RC TODO: copy unique missing content stringlist entries */
-    sc->mask |= new_sc->mask;
-}
-
 extern http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader);
-extern int operator - (http_hdr_sc_type const &anSc, http_hdr_sc_type const &anSc2);
 /* copies non-extant fields from new_sc to this sc */
 void
-httpHdrScTargetMergeWith(HttpHdrScTarget * sc, const HttpHdrScTarget * new_sc)
+HttpHdrScTarget::mergeWith(const HttpHdrScTarget * new_sc)
 {
-    http_hdr_sc_type c;
-    assert(sc && new_sc);
+    assert(new_sc);
     /* Don't touch the target - this is used to get the operations for a
      * single surrogate
      */
 
-    for (c = SC_NO_STORE; c < SC_ENUM_END; ++c)
-        if (!EBIT_TEST(sc->mask, c) && EBIT_TEST(new_sc->mask,c)) {
-            EBIT_SET(sc->mask, c);
+    if (new_sc->hasNoStore())
+        noStore(true);
 
-            switch (c) {
+    if (new_sc->hasNoStoreRemote())
+        noStoreRemote(true);
 
-            case SC_MAX_AGE:
-                sc->max_age = new_sc->max_age;
-                sc->max_stale = new_sc->max_stale;
-                break;
-
-            case SC_CONTENT:
-                assert (sc->content.size() == 0);
-                sc->content = new_sc->content;
-                break;
-
-            default:
-                break;
-            }
-        }
-}
+    if (new_sc->hasMaxAge() && !hasMaxAge()) {
+        maxAge(new_sc->maxAge());
+        maxStale(new_sc->maxStale());
+    }
 
-/* negative max_age will clean old max_Age setting */
-void
-httpHdrScTargetSetMaxAge(HttpHdrScTarget * sc, int max_age)
-{
-    assert(sc);
-    sc->max_age = max_age;
+    if (new_sc->hasContent() && !hasContent())
+        Content(new_sc->content());
 
-    if (max_age >= 0)
-        EBIT_SET(sc->mask, SC_MAX_AGE);
-    else
-        EBIT_CLR(sc->mask, SC_MAX_AGE);
 }
 
 void
-httpHdrScTargetUpdateStats(const HttpHdrScTarget * sc, StatHist * hist)
+HttpHdrScTarget::updateStats(StatHist * hist) const
 {
     http_hdr_sc_type c;
-    assert(sc);
 
     for (c = SC_NO_STORE; c < SC_ENUM_END; ++c)
-        if (EBIT_TEST(sc->mask, c))
+        if (isSet(c))
             statHistCount(hist, c);
 }

=== modified file 'src/HttpHdrScTarget.h'
--- src/HttpHdrScTarget.h	2009-01-21 03:47:47 +0000
+++ src/HttpHdrScTarget.h	2011-11-18 06:25:35 +0000
@@ -18,59 +18,116 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 #ifndef SQUID_HTTPHDRSURROGATECONTROLTARGET_H
 #define SQUID_HTTPHDRSURROGATECONTROLTARGET_H
 
 class Packer;
 class StoreEntry;
 
-/* for MEMPROXY_CLASS() macros */
 #include "MemPool.h"
-/* for dlink_node */
 #include "dlink.h"
-/* for String */
 #include "SquidString.h"
+#include "typedefs.h"
 
-/** HTTP Surogate-Control: header field */
+/** Representation of HTTP Surogate-Control header field targeted directive
+ *
+ * \see HttpHdrSc
+ */
 class HttpHdrScTarget
 {
+    // parsing is done in HttpHdrSc, need to grant them access.
+    friend class HttpHdrSc;
 public:
+	static const int MAX_AGE_UNSET=-1; //max-age is unset
+	static const int MAX_STALE_UNSET=0; //max-stale is unset
+
+    HttpHdrScTarget(const char *target_):
+        mask(0), max_age(MAX_AGE_UNSET), max_stale(MAX_STALE_UNSET),target(target_) \
{} +    HttpHdrScTarget(const String &target_):
+        mask(0), max_age(MAX_AGE_UNSET), max_stale(MAX_STALE_UNSET),target(target_) \
{} +    HttpHdrScTarget(const HttpHdrScTarget &t):
+        mask(t.mask), max_age(t.max_age), max_stale(t.max_stale),
+        content_(t.content_), target(t.target) {}
+
+    bool hasNoStore() const {return isSet(SC_NO_STORE); }
+    void noStore(bool v) { setMask(SC_NO_STORE,v); }
+    bool noStore() const { return isSet(SC_NO_STORE); }
+    void clearNoStore() { setMask(SC_NO_STORE, false); }
+
+    bool hasNoStoreRemote() const {return isSet(SC_NO_STORE_REMOTE); }
+    void noStoreRemote(bool v) { setMask(SC_NO_STORE_REMOTE,v); }
+    bool noStoreRemote() const { return isSet(SC_NO_STORE_REMOTE); }
+    void clearNoStoreRemote() { setMask(SC_NO_STORE_REMOTE, false); }
+
+    bool hasMaxAge() const { return isSet(SC_MAX_AGE); }
+    void maxAge(int v) {
+    	if (v >= 0) { //setting
+    		setMask(SC_MAX_AGE,true);
+    		max_age=v;
+    	} else {
+    		setMask(SC_MAX_AGE,false);
+    		max_age=MAX_AGE_UNSET;
+    	}
+    }
+    int maxAge() const { return max_age; }
+    void clearMaxAge() { setMask(SC_MAX_AGE,false); max_age=MAX_AGE_UNSET; }
+
+    //max_stale has no associated status-bit
+    bool hasMaxStale() const { return max_stale != MAX_STALE_UNSET; }
+    void maxStale(int v) { max_stale=v; }
+    int maxStale() const { return max_stale; }
+    void clearMaxStale() { max_stale=MAX_STALE_UNSET; }
+
+    bool hasContent() const { return isSet(SC_CONTENT); }
+    void Content(const String &v) {
+    	setMask(SC_CONTENT,true);
+    	content_=v;
+    }
+    String content() const { return content_; }
+    void clearContent() { setMask(SC_CONTENT,false); content_.clean(); }
+
+    bool hasTarget() const { return target.size() != 0; }
+    String Target() const { return target; }
+
+    void mergeWith(const HttpHdrScTarget * new_sc);
+    void packInto (Packer *p) const;
+    void updateStats(StatHist *) const;
+
     MEMPROXY_CLASS(HttpHdrScTarget);
-    dlink_node node;
+private:
+    bool isSet(http_hdr_sc_type id) const {
+        assert (id >= SC_NO_STORE && id < SC_ENUM_END);
+        return EBIT_TEST(mask,id);
+    }
+
+    void setMask(http_hdr_sc_type id, bool newval) {
+        if (newval) EBIT_SET(mask,id);
+        else EBIT_CLR(mask,id);
+    }
+
     int mask;
     int max_age;
     int max_stale;
-    String content;
+    String content_;
     String target;
+    dlink_node node;
 };
 
 MEMPROXY_CLASS_INLINE(HttpHdrScTarget);
 
-/* Http Surrogate control header field 'targets' */
-extern HttpHdrScTarget * httpHdrScTargetCreate (const char *);
-extern void httpHdrScTargetDestroy(HttpHdrScTarget *);
-extern HttpHdrScTarget *httpHdrScTargetDup(const HttpHdrScTarget *);
-extern void httpHdrScTargetPackInto(const HttpHdrScTarget *, Packer *);
-extern void httpHdrScTargetSetMaxAge(HttpHdrScTarget *, int);
-extern void httpHdrScTargetJoinWith(HttpHdrScTarget *, const HttpHdrScTarget *);
-extern void httpHdrScTargetMergeWith(HttpHdrScTarget *, const HttpHdrScTarget *);
 extern void httpHdrScTargetStatDumper(StoreEntry * sentry, int idx, double val, \
double size, int count);  
-/* for StatHist */
-#include "typedefs.h"
-
-extern void httpHdrScTargetUpdateStats(const HttpHdrScTarget *, StatHist *);
 
 
 #endif /* SQUID_HTTPHDRSURROGATECONTROLTARGET_H */

=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2011-09-28 12:13:22 +0000
+++ src/HttpHeader.cc	2011-11-17 23:55:24 +0000
@@ -1192,41 +1192,41 @@
     packerToMemInit(&p, &mb);
     range->packInto(&p);
     /* put */
     addEntry(new HttpHeaderEntry(HDR_RANGE, NULL, mb.buf));
     /* cleanup */
     packerClean(&p);
     mb.clean();
 }
 
 void
 HttpHeader::putSc(HttpHdrSc *sc)
 {
     MemBuf mb;
     Packer p;
     assert(sc);
     /* remove old directives if any */
     delById(HDR_SURROGATE_CONTROL);
     /* pack into mb */
     mb.init();
     packerToMemInit(&p, &mb);
-    httpHdrScPackInto(sc, &p);
+    sc->packInto(&p);
     /* put */
     addEntry(new HttpHeaderEntry(HDR_SURROGATE_CONTROL, NULL, mb.buf));
     /* cleanup */
     packerClean(&p);
     mb.clean();
 }
 
 void
 HttpHeader::putWarning(const int code, const char *const text)
 {
     char buf[512];
     snprintf(buf, sizeof(buf), "%i %s \"%s\"", code, visible_appname_string, text);
     putStr(HDR_WARNING, buf);
 }
 
 /* add extension header (these fields are not parsed/analyzed/joined, etc.) */
 void
 HttpHeader::putExt(const char *name, const char *value)
 {
     assert(name && value);
@@ -1349,46 +1349,46 @@
 
     if ((e = findEntry(HDR_RANGE)) ||
             (e = findEntry(HDR_REQUEST_RANGE))) {
         r = HttpHdrRange::ParseCreate(&e->value);
         httpHeaderNoteParsedEntry(e->id, e->value, !r);
     }
 
     return r;
 }
 
 HttpHdrSc *
 HttpHeader::getSc() const
 {
     if (!CBIT_TEST(mask, HDR_SURROGATE_CONTROL))
         return NULL;
 
     String s;
 
     (void) getList(HDR_SURROGATE_CONTROL, &s);
 
-    HttpHdrSc *sc = httpHdrScParseCreate(&s);
+    HttpHdrSc *sc = httpHdrScParseCreate(s);
 
-    HttpHeaderStats[owner].ccParsedCount++;
+    ++HttpHeaderStats[owner].ccParsedCount;
 
     if (sc)
-        httpHdrScUpdateStats(sc, &HttpHeaderStats[owner].scTypeDistr);
+        sc->updateStats(&HttpHeaderStats[owner].scTypeDistr);
 
     httpHeaderNoteParsedEntry(HDR_SURROGATE_CONTROL, s, !sc);
 
     return sc;
 }
 
 HttpHdrContRange *
 HttpHeader::getContRange() const
 {
     HttpHdrContRange *cr = NULL;
     HttpHeaderEntry *e;
 
     if ((e = findEntry(HDR_CONTENT_RANGE))) {
         cr = httpHdrContRangeParseCreate(e->value.termedBuf());
         httpHeaderNoteParsedEntry(e->id, e->value, !cr);
     }
 
     return cr;
 }
 

=== modified file 'src/HttpReply.cc'
--- src/HttpReply.cc	2011-09-28 22:42:19 +0000
+++ src/HttpReply.cc	2011-10-04 22:01:48 +0000
@@ -391,41 +391,41 @@
         content_type.limitInit(str, strcspn(str, ";\t "));
     else
         content_type = String();
 
     /* be sure to set expires after date and cache-control */
     expires = hdrExpirationTime();
 }
 
 /* sync this routine when you update HttpReply struct */
 void
 HttpReply::hdrCacheClean()
 {
     content_type.clean();
 
     if (cache_control) {
         delete cache_control;
         cache_control = NULL;
     }
 
     if (surrogate_control) {
-        httpHdrScDestroy(surrogate_control);
+        delete surrogate_control;
         surrogate_control = NULL;
     }
 
     if (content_range) {
         httpHdrContRangeDestroy(content_range);
         content_range = NULL;
     }
 }
 
 /*
  * Returns the body size of a HTTP response
  */
 int64_t
 HttpReply::bodySize(const HttpRequestMethod& method) const
 {
     if (sline.version.major < 1)
         return -1;
     else if (method.id() == METHOD_HEAD)
         return 0;
     else if (sline.status == HTTP_OK)

=== modified file 'src/esi/Esi.cc'
--- src/esi/Esi.cc	2011-05-13 08:13:01 +0000
+++ src/esi/Esi.cc	2011-11-18 06:25:35 +0000
@@ -2415,39 +2415,39 @@
     CBDATA_INIT_TYPE_FREECB(esiOtherwise, esiSequence::Free);
     rv = (void *)cbdataAlloc (esiOtherwise);
     return rv;
 }
 
 void
 esiOtherwise::operator delete (void *address)
 {
     cbdataFree (address);
 }
 
 #endif
 
 /* TODO: implement surrogate targeting and control processing */
 int
 esiEnableProcessing (HttpReply *rep)
 {
     int rv = 0;
 
     if (rep->surrogate_control) {
-        HttpHdrScTarget *sctusable = httpHdrScGetMergedTarget \
                (rep->surrogate_control,
-                                     Config.Accel.surrogate_id);
+        HttpHdrScTarget *sctusable =
+                rep->surrogate_control->getMergedTarget(Config.Accel.surrogate_id);
 
-        if (!sctusable || sctusable->content.size() == 0)
+        if (!sctusable || !sctusable->hasContent())
             /* Nothing generic or targeted at us, or no
              * content processing requested
              */
             return 0;
 
-        if (sctusable->content.pos("ESI/1.0") != NULL)
+        if (sctusable->content().pos("ESI/1.0") != NULL)
             rv = 1;
 
-        httpHdrScTargetDestroy (sctusable);
+        delete sctusable;
     }
 
     return rv;
 }
 
 #endif /* USE_SQUID_ESI == 1 */

=== modified file 'src/htcp.cc'
--- src/htcp.cc	2011-09-02 12:35:57 +0000
+++ src/htcp.cc	2011-11-17 18:16:28 +0000
@@ -32,40 +32,41 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "AccessLogEntry.h"
 #include "acl/FilledChecklist.h"
 #include "acl/Acl.h"
 #include "comm.h"
 #include "comm/Loops.h"
 #include "htcp.h"
 #include "http.h"
 #include "HttpRequest.h"
 #include "icmp/net_db.h"
 #include "ipc/StartListening.h"
 #include "ip/tools.h"
 #include "MemBuf.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "StoreClient.h"
+#include "compat/xalloc.h"
 
 /// dials htcpIncomingConnectionOpened call
 class HtcpListeningStartedDialer: public CallDialer,
         public Ipc::StartListeningCb
 {
 public:
     typedef void (*Handler)(int errNo);
     HtcpListeningStartedDialer(Handler aHandler): handler(aHandler) {}
 
     virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
     virtual bool canDial(AsyncCall &) const { return true; }
     virtual void dial(AsyncCall &) { (handler)(errNo); }
 
 public:
     Handler handler;
 };
 
 typedef struct _Countstr Countstr;
 
 typedef struct _htcpHeader htcpHeader;

=== modified file 'src/http.cc'
--- src/http.cc	2011-10-21 16:20:42 +0000
+++ src/http.cc	2011-11-17 23:25:48 +0000
@@ -268,68 +268,68 @@
      * changed.
      */
     if (e->mem_obj->request)
         pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
     else
         pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
 
     if (pe != NULL) {
         assert(e != pe);
 #if USE_HTCP
         neighborsHtcpClear(e, NULL, e->mem_obj->request, \
HttpRequestMethod(METHOD_HEAD), HTCP_CLR_INVALIDATION);  #endif
         pe->release();
     }
 }
 
 void
 HttpStateData::processSurrogateControl(HttpReply *reply)
 {
     if (request->flags.accelerated && reply->surrogate_control) {
-        HttpHdrScTarget *sctusable = \
httpHdrScGetMergedTarget(reply->surrogate_control, Config.Accel.surrogate_id); +      \
HttpHdrScTarget *sctusable = \
reply->surrogate_control->getMergedTarget(Config.Accel.surrogate_id);  
         if (sctusable) {
-            if (EBIT_TEST(sctusable->mask, SC_NO_STORE) ||
+            if (sctusable->noStore() ||
                     (Config.onoff.surrogate_is_remote
-                     && EBIT_TEST(sctusable->mask, SC_NO_STORE_REMOTE))) {
+                     && sctusable->noStoreRemote())) {
                 surrogateNoStore = true;
                 entry->makePrivate();
             }
 
             /* The HttpHeader logic cannot tell if the header it's parsing is a \
                reply to an
              * accelerated request or not...
              * Still, this is an abstraction breach. - RC
              */
-            if (sctusable->max_age != -1) {
-                if (sctusable->max_age < sctusable->max_stale)
-                    reply->expires = reply->date + sctusable->max_age;
+            if (sctusable->hasMaxAge()) {
+                if (sctusable->maxAge() < sctusable->maxStale())
+                    reply->expires = reply->date + sctusable->maxAge();
                 else
-                    reply->expires = reply->date + sctusable->max_stale;
+                    reply->expires = reply->date + sctusable->maxStale();
 
                 /* And update the timestamps */
                 entry->timestampsSet();
             }
 
             /* We ignore cache-control directives as per the Surrogate specification \
*/  ignoreCacheControl = true;
 
-            httpHdrScTargetDestroy(sctusable);
+            delete sctusable;
         }
     }
 }
 
 int
 HttpStateData::cacheableReply()
 {
     HttpReply const *rep = finalReply();
     HttpHeader const *hdr = &rep->header;
     const char *v;
 #if USE_HTTP_VIOLATIONS
 
     const refresh_t *R = NULL;
 
     /* This strange looking define first looks up the refresh pattern
      * and then checks if the specified flag is set. The main purpose
      * of this is to simplify the refresh pattern lookup and USE_HTTP_VIOLATIONS
      * condition
      */
 #define REFRESH_OVERRIDE(flag) \



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic