From 7cbbba198913ff3403116d2364d8765cfdd7f162 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Thu, 9 Oct 2008 17:24:03 +0200
Subject: preparing for 3.18.5 release
---
ChangeLog | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index bbfbfd00..77d7be77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,5 @@
---------------------------------------------------------------------------
-Version 3.18.5 (rgerhards), 2008-10-??
+Version 3.18.5 (rgerhards), 2008-10-09
- bugfix: imudp input module could cause segfault on HUP
It did not properly de-init a variable acting as a linked list head.
That resulted in trying to access freed memory blocks after the HUP.
--
cgit
From 73d52a447cd91f95656274d46fc19d480312671b Mon Sep 17 00:00:00 2001
From: varmojfekoj
Date: Tue, 28 Oct 2008 14:55:27 +0100
Subject: bugfix: double-free in pctp netstream driver
Signed-off-by: Rainer Gerhards
---
ChangeLog | 5 +++++
runtime/nsd_ptcp.c | 13 +++++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 876c6d2b..a88febc1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,9 @@
---------------------------------------------------------------------------
+Version 3.20.0 [BETA] (rgerhards), 2008-10-??
+- this is the inital release of the 3.19.x branch as a stable release
+- bugfix: double-free in pctp netstream driver. Thank to varmojfeko
+ for the patch
+---------------------------------------------------------------------------
Version 3.19.12 [BETA] (rgerhards), 2008-10-16
- bugfix: subseconds where not correctly extracted from a timestamp
if that timestamp did not contain any subsecond information (the
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
index c3899f83..4cb46380 100644
--- a/runtime/nsd_ptcp.c
+++ b/runtime/nsd_ptcp.c
@@ -365,7 +365,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
netstrm_t *pNewStrm = NULL;
nsd_t *pNewNsd = NULL;
int error, maxs, on = 1;
- int sock;
+ int sock = -1;
int numSocks;
int sockflags;
struct addrinfo hints, *res = NULL, *r;
@@ -410,6 +410,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&iOn, sizeof (iOn)) < 0) {
close(sock);
+ sock = -1;
continue;
}
}
@@ -417,6 +418,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) {
dbgprintf("error %d setting tcp socket option\n", errno);
close(sock);
+ sock = -1;
continue;
}
@@ -431,6 +433,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
if(sockflags == -1) {
dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno);
close(sock);
+ sock = -1;
continue;
}
@@ -445,6 +448,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
(char *) &on, sizeof(on)) < 0) {
errmsg.LogError(errno, NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)");
close(sock);
+ sock = -1;
continue;
}
}
@@ -458,6 +462,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
/* TODO: check if *we* bound the socket - else we *have* an error! */
dbgprintf("error %d while binding tcp socket", errno);
close(sock);
+ sock = -1;
continue;
}
@@ -472,6 +477,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
if(listen(sock, 32) < 0) {
dbgprintf("tcp listen error %d, suspending\n", errno);
close(sock);
+ sock = -1;
continue;
}
}
@@ -482,13 +488,14 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
*/
CHKiRet(pNS->Drvr.Construct(&pNewNsd));
CHKiRet(pNS->Drvr.SetSock(pNewNsd, sock));
+ sock = -1;
CHKiRet(pNS->Drvr.SetMode(pNewNsd, netstrms.GetDrvrMode(pNS)));
CHKiRet(pNS->Drvr.SetAuthMode(pNewNsd, netstrms.GetDrvrAuthMode(pNS)));
CHKiRet(pNS->Drvr.SetPermPeers(pNewNsd, netstrms.GetDrvrPermPeers(pNS)));
CHKiRet(netstrms.CreateStrm(pNS, &pNewStrm));
pNewStrm->pDrvrData = (nsd_t*) pNewNsd;
- CHKiRet(fAddLstn(pUsr, pNewStrm));
pNewNsd = NULL;
+ CHKiRet(fAddLstn(pUsr, pNewStrm));
pNewStrm = NULL;
++numSocks;
}
@@ -507,6 +514,8 @@ finalize_it:
freeaddrinfo(res);
if(iRet != RS_RET_OK) {
+ if(sock != -1)
+ close(sock);
if(pNewStrm != NULL)
netstrm.Destruct(&pNewStrm);
if(pNewNsd != NULL)
--
cgit
From 99d63bef5fa6205d3da0f9aa74afa0551e9acd0b Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Tue, 28 Oct 2008 14:57:30 +0100
Subject: bumped version number, preparing to be new stable branch
---
configure.ac | 2 +-
doc/manual.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index d70e48b5..bacb9d1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
-AC_INIT([rsyslog],[3.19.12],[rsyslog@lists.adiscon.com])
+AC_INIT([rsyslog],[3.20.0],[rsyslog@lists.adiscon.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([ChangeLog])
AC_CONFIG_HEADERS([config.h])
diff --git a/doc/manual.html b/doc/manual.html
index f1e2640b..cbb3477d 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -16,7 +16,7 @@ relay chains while at the same time being very easy to setup for the
novice user. And as we know what enterprise users really need, there is
also professional
rsyslog support available directly from the source!
-This documentation is for version 3.19.12 (beta branch) of rsyslog.
+
This documentation is for version 3.20.0 (v3-stable branch) of rsyslog.
Visit the rsyslog status page to obtain current
version information and project status.
If you like rsyslog, you might
--
cgit
From 9048c16d90177a0dfa4131266ae73f029a5923c8 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Wed, 5 Nov 2008 12:50:18 +0100
Subject: updated release date for 3.20.0
---
ChangeLog | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 43acf562..0b01d9f7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,5 @@
---------------------------------------------------------------------------
-Version 3.20.0 [BETA] (rgerhards), 2008-10-??
+Version 3.20.0 [BETA] (rgerhards), 2008-11-05
- this is the inital release of the 3.19.x branch as a stable release
- bugfix: double-free in pctp netstream driver. Thank to varmojfeko
for the patch
--
cgit
From aaab9bb8a6d6249bff9642a67ef97cfb09e58b3b Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Wed, 5 Nov 2008 17:34:03 +0100
Subject: minor nit: fixed branch identification
---
ChangeLog | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 0b01d9f7..a0542b56 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,5 @@
---------------------------------------------------------------------------
-Version 3.20.0 [BETA] (rgerhards), 2008-11-05
+Version 3.20.0 [v3-stable] (rgerhards), 2008-11-05
- this is the inital release of the 3.19.x branch as a stable release
- bugfix: double-free in pctp netstream driver. Thank to varmojfeko
for the patch
--
cgit
From b4729996790c0f7a0b2758d9ee809b7cc10dec8f Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Mon, 10 Nov 2008 09:57:49 +0100
Subject: doc update: documented how to specify multiple property replacer
options
abd link to new online regex generator tool added
---
ChangeLog | 4 ++++
doc/manual.html | 1 +
doc/property_replacer.html | 11 +++++++++++
3 files changed, 16 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index a0542b56..688f2c99 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
---------------------------------------------------------------------------
+Version 3.20.1 [v3-stable] (rgerhards), 2008-11-??
+- doc update: documented how to specify multiple property replacer
+ options + link to new online regex generator tool added
+---------------------------------------------------------------------------
Version 3.20.0 [v3-stable] (rgerhards), 2008-11-05
- this is the inital release of the 3.19.x branch as a stable release
- bugfix: double-free in pctp netstream driver. Thank to varmojfeko
diff --git a/doc/manual.html b/doc/manual.html
index cbb3477d..61b16527 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -35,6 +35,7 @@ the links below for the
- configuration file syntax (rsyslog.conf)
- property
replacer, an important core component
+- a regular expression checker/generator tool for rsyslog
- a commented sample
rsyslog.conf
diff --git a/doc/property_replacer.html b/doc/property_replacer.html
index 367c8add..0b4f1a01 100644
--- a/doc/property_replacer.html
+++ b/doc/property_replacer.html
@@ -231,6 +231,13 @@ the full field if no match is found:
%msg:R,ERE,1,FIELD:for (vlan[0-9]*):--end%
and this takes the first submatch of the second match of said expression:
%msg:R,ERE,1,FIELD,1:for (vlan[0-9]*):--end%
+
Please note: there is also a
+rsyslog regular expression checker/generator
+online tool available. With that tool, you can check your regular expressions and
+also generate a valid property replacer sequence. Usage of this tool is recommended.
+Depending on the version offered, the tool may not cover all subleties that can
+be done with the property replacer. It concentrates on the most often used cases. So it
+is still useful to hand-craft expressions for demanding environments.
Also, extraction can be done based on so-called
"fields". To do so, place a "F" into FromChar. A field in its
current definition is anything that is delimited by a delimiter
@@ -347,6 +354,10 @@ Useful for secure pathname generation (with dynafiles).
+
To use multiple options, simply place them one after each other with a comma delmimiting
+them. For example "escape-cc,sp-if-no-1st-sp". If you use conflicting options together,
+the last one will override the previous one. For example, using "escape-cc,drop-cc" will
+use drop-cc and "drop-cc,escape-cc" will use escape-cc mode.
Further Links
- Article on "Recording
--
cgit
From c291d8baca323e26cd63e5d26b50f3b2247fac78 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Tue, 11 Nov 2008 10:07:52 +0100
Subject: improved debug output for regular expressions inside property
replacer
RE's seem to be a big trouble spot and I would like to have more
information inside the debug log. So I decided to add some additional
debug strings permanently.
---
ChangeLog | 4 ++++
runtime/msg.c | 8 +++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index 688f2c99..e6a2b899 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,10 @@
Version 3.20.1 [v3-stable] (rgerhards), 2008-11-??
- doc update: documented how to specify multiple property replacer
options + link to new online regex generator tool added
+- improved debug output for regular expressions inside property replacer
+ RE's seem to be a big trouble spot and I would like to have more
+ information inside the debug log. So I decided to add some additional
+ debug strings permanently.
---------------------------------------------------------------------------
Version 3.20.0 [v3-stable] (rgerhards), 2008-11-05
- this is the inital release of the 3.19.x branch as a stable release
diff --git a/runtime/msg.c b/runtime/msg.c
index fdeae077..fcd4a6d3 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -1906,7 +1906,10 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
* potential matches over the string.
*/
while(!bFound) {
- if(regexp.regexec(&pTpe->data.field.re, pRes + iOffs, nmatch, pmatch, 0) == 0) {
+ int iREstat;
+ iREstat = regexp.regexec(&pTpe->data.field.re, pRes + iOffs, nmatch, pmatch, 0);
+ dbgprintf("regexec return is %d\n", iREstat);
+ if(iREstat == 0) {
if(pmatch[0].rm_so == -1) {
dbgprintf("oops ... start offset of successful regexec is -1\n");
break;
@@ -1914,6 +1917,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
if(iTry == pTpe->data.field.iMatchToUse) {
bFound = 1;
} else {
+ dbgprintf("regex found at offset %d, new offset %d, tries %d\n",
+ iOffs, iOffs + pmatch[0].rm_eo, iTry);
iOffs += pmatch[0].rm_eo;
++iTry;
}
@@ -1921,6 +1926,7 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
break;
}
}
+ dbgprintf("regex: end search, found %d\n", bFound);
if(!bFound) {
/* we got no match! */
if(pTpe->data.field.nomatchAction != TPL_REGEX_NOMATCH_USE_WHOLE_FIELD) {
--
cgit
From b104759ad671a1ae92f2768de02f1dbbe5f4cb12 Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Tue, 11 Nov 2008 10:12:01 +0100
Subject: added small regex check tool to repository
This is intended for debugging and considered worth preserving.
However, it has not (yet) been added to the build diag tools
as it is not considered important enough.
---
tools/regexp.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 tools/regexp.c
diff --git a/tools/regexp.c b/tools/regexp.c
new file mode 100644
index 00000000..c8e4c681
--- /dev/null
+++ b/tools/regexp.c
@@ -0,0 +1,72 @@
+/* A simple regular expression checker for rsyslog test and debug.
+ * Regular expressions have shown to turn out to be a hot support topic.
+ * While I have done an online tool at http://www.rsyslog.com/tool-regex
+ * there are still some situations where one wants to check against the
+ * actual clib api calls. This is what this small test program does,
+ * it takes its command line arguments (re first, then sample data) and
+ * pushes them into the API and then shows the result. This should be
+ * considered the ultimate reference for any questions arising.
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 Rsyslog. If not, see .
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ regex_t preg;
+ size_t nmatch = 10;
+ regmatch_t pmatch[10];
+ char *pstr;
+ int i;
+
+ if(argc != 3) {
+ fprintf(stderr, "usage: regex regexp sample-data\n");
+ exit(1);
+ }
+
+ pstr = strdup(argv[2]); /* get working copy */
+
+ i = regcomp(&preg, argv[1], REG_EXTENDED);
+ printf("regcomp returns %d\n", i);
+ i = regexec(&preg, pstr, nmatch, pmatch, 0);
+ printf("regexec returns %d\n", i);
+ if(i == REG_NOMATCH) {
+ printf("found no match!\n");
+ return 1;
+ }
+
+ printf("returned substrings:\n");
+ for(i = 0 ; i < 10 ; i++) {
+ printf("%d: so %d, eo %d", i, pmatch[i].rm_so, pmatch[i].rm_eo);
+ if(pmatch[i].rm_so != -1) {
+ int j;
+ printf(", text: '");
+ for(j = pmatch[i].rm_so ; j < pmatch[i].rm_eo ; ++j)
+ putchar(pstr[j]);
+ putchar('\'');
+ }
+ putchar('\n');
+ }
+ return 0;
+}
--
cgit
From 4cfbf894fd0caebaf65e1b7ffcb5725a530cf67d Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Tue, 11 Nov 2008 12:00:11 +0100
Subject: enhance: regex nomatch option "ZERO" has been added
This allows to return the string 0 if a regular expression is
not found. This is probably useful for storing numerical values into
database columns.
---
ChangeLog | 4 ++++
doc/property_replacer.html | 5 +++--
runtime/msg.c | 2 ++
template.c | 8 ++++++--
template.h | 3 ++-
5 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index e6a2b899..84617825 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
---------------------------------------------------------------------------
Version 3.20.1 [v3-stable] (rgerhards), 2008-11-??
+- enhance: regex nomatch option "ZERO" has been added
+ This allows to return the string 0 if a regular expression is
+ not found. This is probably useful for storing numerical values into
+ database columns.
- doc update: documented how to specify multiple property replacer
options + link to new online regex generator tool added
- improved debug output for regular expressions inside property replacer
diff --git a/doc/property_replacer.html b/doc/property_replacer.html
index 0b4f1a01..2748dc89 100644
--- a/doc/property_replacer.html
+++ b/doc/property_replacer.html
@@ -219,10 +219,11 @@ that the first match is number 0, the second 1 and so on. Up to 10 matches
(up to number 9) are supported. Please note that it would be more
natural to have the match-number in front of submatch, but this would break
backward-compatibility. So the match-number must be specified after "nomatch".
-
nomatch is either "DFLT", "BLANK" or "FIELD" (all upper case!). It tells
+
nomatch is either "DFLT", "BLANK", ZERO or "FIELD" (all upper case!). It tells
what to use if no match is found. With "DFLT", the strig "**NO MATCH**" is
used. This was the only supported value up to rsyslog 3.19.5. With "BLANK"
-a blank text is used (""). Finally, "FIELD" uses the full property text
+a blank text is used (""). With "ZERO", "0" is used.
+Finally, "FIELD" uses the full property text
instead of the expression. Some folks have requested that, so it seems
to be useful.
The following is a sample of an ERE expression that takes the first
diff --git a/runtime/msg.c b/runtime/msg.c
index fcd4a6d3..c8dbf2c2 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -1936,6 +1936,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
if(pTpe->data.field.nomatchAction == TPL_REGEX_NOMATCH_USE_DFLTSTR)
return "**NO MATCH**";
+ else if(pTpe->data.field.nomatchAction == TPL_REGEX_NOMATCH_USE_ZERO)
+ return "0";
else
return "";
}
diff --git a/template.c b/template.c
index 2fe23710..936ccd07 100644
--- a/template.c
+++ b/template.c
@@ -558,13 +558,17 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl)
pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_DFLTSTR;
p += 4; /* eat indicator sequence */
} else if(p[0] == 'B' && p[1] == 'L' && p[2] == 'A' && p[3] == 'N' && p[4] == 'K'
- && (p[5] == ',' || p[5] == ':')) {
+ && (p[5] == ',' || p[5] == ':')) {
pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_BLANK;
p += 5; /* eat indicator sequence */
} else if(p[0] == 'F' && p[1] == 'I' && p[2] == 'E' && p[3] == 'L' && p[4] == 'D'
- && (p[5] == ',' || p[5] == ':')) {
+ && (p[5] == ',' || p[5] == ':')) {
pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_WHOLE_FIELD;
p += 5; /* eat indicator sequence */
+ } else if(p[0] == 'Z' && p[1] == 'E' && p[2] == 'R' && p[3] == 'O'
+ && (p[4] == ',' || p[4] == ':')) {
+ pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_ZERO;
+ p += 4; /* eat indicator sequence */
} else if(p[0] == ',') { /* empty, use default */
pTpe->data.field.nomatchAction = TPL_REGEX_NOMATCH_USE_DFLTSTR;
/* do NOT eat indicator sequence, as this was already eaten - the
diff --git a/template.h b/template.h
index 6e889c58..318f3f32 100644
--- a/template.h
+++ b/template.h
@@ -78,7 +78,8 @@ struct templateEntry {
enum {
TPL_REGEX_NOMATCH_USE_DFLTSTR = 0, /* use the (old style) default "**NO MATCH**" string */
TPL_REGEX_NOMATCH_USE_BLANK = 1, /* use a blank string */
- TPL_REGEX_NOMATCH_USE_WHOLE_FIELD = 2 /* use the full field contents that we were searching in*/
+ TPL_REGEX_NOMATCH_USE_WHOLE_FIELD = 2, /* use the full field contents that we were searching in*/
+ TPL_REGEX_NOMATCH_USE_ZERO = 3 /* use 0 (useful for numerical values) */
} nomatchAction; /**< what to do if we do not have a match? */
#endif
--
cgit
From 49dcad849e93551d90cd6298a576b67c4ad0c7ef Mon Sep 17 00:00:00 2001
From: Rainer Gerhards
Date: Tue, 11 Nov 2008 17:45:49 +0100
Subject: preparing for 3.12.7 release
---
ChangeLog | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/ChangeLog b/ChangeLog
index 8509ad2a..8303d495 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,8 @@
---------------------------------------------------------------------------
+Version 3.21.7 [BETA] (rgerhards), 2008-11-11
+- this is the new beta branch, based on the former 3.21.6 devel
+- new functionality: ZERO property replacer nomatch option (from v3-stable)
+---------------------------------------------------------------------------
Version 3.21.6 [DEVEL] (rgerhards), 2008-10-22
- consolidated time calls during msg object creation, improves performance
and consistency
--
cgit