Re: [PATCHES] Repleacement for src/port/snprintf.c

Bruce Momjian <[email protected]>
Newsgroups gmane.comp.db.postgresql.devel.win32,gmane.comp.db.postgresql.devel.general,gmane.comp.db.postgresql.devel.patches
Message-ID <[email protected]>
Applied.

---------------------------------------------------------------------------

Bruce Momjian wrote:
> Nicolai Tufar wrote:
> > Hello all,
> > 
> > I would like to submit my changes to src/port/snprintf.c to
> > enable %n$ format placeholder replacement in snprintf() and
> > vsnprintf(). Additionally I implemented a trivial printf().
> > 
> > I also attach a diff for configure.in to include snprintf.o
> > in pgport but I am sure it is not the right thing to do.
> > Could someone give a hint on where I need to place such a
> > definition.
> > 
> > Please review my patch. as Tom Lane pointed out there
> > are 150 messages in the following files that do not print
> > properly:
> 
> It took me a while to understand this but I get it now.  This is the
> best explanation I have seen, from Linux 2.6:
> 
> 	One can also specify explicitly which argument is taken, at each place
> 	where an argument is required, by writing '%m$' instead of '%' and '*m$'
> 	instead of '*', where the decimal integer m denotes the position in the
> 	argument list of the desired argument, indexed starting from 1. Thus,
> 	
> 		printf("%*d", width, num);
> 	
> 	and
> 	
> 		printf("%2$*1$d", width, num);
> 	
> 	are  equivalent.  The  second style allows repeated references to the
> 	same argument. The C99 standard does not include the style using '$',
> 	which comes from the Single Unix Specification.  If the style using '$'
> 	is used, it must be  used throughout for all conversions taking an
> 	argument and all width and precision arguments, but it may be mixed with
> 	'%%' formats which do not consume an argument.  There may be no gaps in
> 	the numbers of arguments specified using  '$';  for example, if
> 	arguments 1 and 3 are specified, argument 2 must also be specified
> 	somewhere in the format string.
> 
> I can see why this would be useful for translations because it uncouples
> the order of the printf arguments from the printf string.  However, I
> have learned that Win32, HP-UX, NetBSD 2.0, and BSD/OS do not support
> this.  This is probably because it is not in C99 but in SUS (see above).
> 
> Anyway, this is too large to put into 8.0, but I am attaching a patch
> for 8.1 that has the proper configure tests to check if the C library
> supports this behavior.  If it does not, the build will use our
> port/snprintf.c.
> 
> One problem with that is that our snprintf.c is not thread-safe.  Seems
> the increases use of it will require us to fix this soon.  I have added
> to TODO:
> 
> 	* Make src/port/snprintf.c thread-safe
> 
> One change to the original port is that there was a define of a union
> with no name:
> 
> +               union{
> +                       void*   value;
> +                       long_long       numvalue;
> +                       double          fvalue;
> +                       int             charvalue;
> +               };
> 
> As far as I know a union with no name is illegal.  I just removed the
> "union {" and the closing brace.
> 
> -- 
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   [email protected]               |  (610) 359-1001
>   +  If your life is a hard drive,     |  13 Roberts Road
>   +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

> Index: configure
> ===================================================================
> RCS file: /cvsroot/pgsql/configure,v
> retrieving revision 1.425
> diff -c -c -r1.425 configure
> *** configure	18 Jan 2005 05:23:35 -0000	1.425
> --- configure	13 Feb 2005 23:50:46 -0000
> ***************
> *** 12162,12167 ****
> --- 12162,12224 ----
>   done
>   
>   
> + echo "$as_me:$LINENO: checking printf supports argument control" >&5
> + echo $ECHO_N "checking printf supports argument control... $ECHO_C" >&6
> + if test "${pgac_cv_printf_arg_control+set}" = set; then
> +   echo $ECHO_N "(cached) $ECHO_C" >&6
> + else
> +   if test "$cross_compiling" = yes; then
> +   pgac_cv_printf_arg_control=cross
> + else
> +   cat >conftest.$ac_ext <<_ACEOF
> + #line $LINENO "configure"
> + #include "confdefs.h"
> + #include <stdio.h>
> + 
> + int does_printf_have_arg_control()
> + {
> +   char buf[100];
> + 
> +   /* can it swap arguments? */
> +   snprintf(buf, 100, "%2$d|%1$d", 3, 4);
> +   if (strcmp(buf, "4|3") != 0)
> +     return 0;
> +   return 1;
> + }
> + main() {
> +   exit(! does_printf_have_arg_control());
> + }
> + _ACEOF
> + rm -f conftest$ac_exeext
> + if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
> +   (eval $ac_link) 2>&5
> +   ac_status=$?
> +   echo "$as_me:$LINENO: \$? = $ac_status" >&5
> +   (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
> +   { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
> +   (eval $ac_try) 2>&5
> +   ac_status=$?
> +   echo "$as_me:$LINENO: \$? = $ac_status" >&5
> +   (exit $ac_status); }; }; then
> +   pgac_cv_printf_arg_control=yes
> + else
> +   echo "$as_me: program exited with status $ac_status" >&5
> + echo "$as_me: failed program was:" >&5
> + cat conftest.$ac_ext >&5
> + ( exit $ac_status )
> + pgac_cv_printf_arg_control=no
> + fi
> + rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
> + fi
> + 
> + fi
> + echo "$as_me:$LINENO: result: $pgac_cv_printf_arg_control" >&5
> + echo "${ECHO_T}$pgac_cv_printf_arg_control" >&6
> + 
> + # cross compiler should use our snprintf too
> + if test $pgac_cv_printf_arg_control != yes ; then
> +   pgac_need_repl_snprintf=yes
> + fi
>   
>   # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
>   # include/c.h will provide declarations.  Note this is a separate test
> Index: configure.in
> ===================================================================
> RCS file: /cvsroot/pgsql/configure.in,v
> retrieving revision 1.399
> diff -c -c -r1.399 configure.in
> *** configure.in	18 Jan 2005 05:23:36 -0000	1.399
> --- configure.in	13 Feb 2005 23:50:47 -0000
> ***************
> *** 881,886 ****
> --- 881,891 ----
>   AC_CHECK_FUNCS(snprintf, [], pgac_need_repl_snprintf=yes)
>   AC_CHECK_FUNCS(vsnprintf, [], pgac_need_repl_snprintf=yes)
>   
> + PGAC_FUNC_PRINTF_ARG_CONTROL
> + # cross compiler should use our snprintf too
> + if test $pgac_cv_printf_arg_control != yes ; then
> +   pgac_need_repl_snprintf=yes
> + fi
>   
>   # Check whether <stdio.h> declares snprintf() and vsnprintf(); if not,
>   # include/c.h will provide declarations.  Note this is a separate test
> ***************
> *** 1069,1074 ****
> --- 1074,1081 ----
>   [AC_MSG_RESULT([cross-compiling])])
>   
>   
> + dnl  64-bit section
> + dnl
>   dnl Check to see if we have a working 64-bit integer type.
>   dnl This breaks down into two steps:
>   dnl (1) figure out if the compiler has a 64-bit int type with working
> Index: config/c-library.m4
> ===================================================================
> RCS file: /cvsroot/pgsql/config/c-library.m4,v
> retrieving revision 1.29
> diff -c -c -r1.29 c-library.m4
> *** config/c-library.m4	16 Dec 2004 17:48:26 -0000	1.29
> --- config/c-library.m4	13 Feb 2005 23:50:48 -0000
> ***************
> *** 266,268 ****
> --- 266,301 ----
>            LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
>     *)     AC_MSG_RESULT(none);;
>   esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
> + 
> + 
> + # PGAC_FUNC_PRINTF_ARG_CONTROL
> + # ---------------------------------------
> + # Determine if printf supports %1$ argument selection, e.g. %5$ selects
> + # the fifth argument after the printf print string.
> + # This is not in the C99 standard, but in the Single Unix Specification (SUS).
> + # It is used in our langauge translation strings.
> + #
> + AC_DEFUN([PGAC_FUNC_PRINTF_ARG_CONTROL],
> + [AC_MSG_CHECKING([printf supports argument control])
> + AC_CACHE_VAL(pgac_cv_printf_arg_control,
> + [AC_TRY_RUN([#include <stdio.h>
> + 
> + int does_printf_have_arg_control()
> + {
> +   char buf[100];
> + 
> +   /* can it swap arguments? */
> +   snprintf(buf, 100, "%2$d|%1$d", 3, 4);
> +   if (strcmp(buf, "4|3") != 0)
> +     return 0;
> +   return 1;
> + }
> + main() {
> +   exit(! does_printf_have_arg_control());
> + }],
> + [pgac_cv_printf_arg_control=yes],
> + [pgac_cv_printf_arg_control=no],
> + [pgac_cv_printf_arg_control=cross])
> + ])dnl AC_CACHE_VAL
> + AC_MSG_RESULT([$pgac_cv_printf_arg_control])
> + ])# PGAC_FUNC_PRINTF_ARG_CONTROL
> Index: src/port/snprintf.c
> ===================================================================
> RCS file: /cvsroot/pgsql/src/port/snprintf.c,v
> retrieving revision 1.4
> diff -c -c -r1.4 snprintf.c
> *** src/port/snprintf.c	29 Aug 2004 05:07:02 -0000	1.4
> --- src/port/snprintf.c	13 Feb 2005 23:50:56 -0000
> ***************
> *** 57,62 ****
> --- 57,66 ----
>   typedef unsigned long ulong_long;
>   #endif
>   
> + #ifndef NL_ARGMAX
> + #define NL_ARGMAX 4096
> + #endif
> + 
>   /*
>   **	SNPRINTF, VSNPRINT -- counted versions of printf
>   **
> ***************
> *** 85,93 ****
> --- 89,115 ----
>   
>   int			snprintf(char *str, size_t count, const char *fmt,...);
>   int			vsnprintf(char *str, size_t count, const char *fmt, va_list args);
> + int			printf(const char *format, ...);
>   static void dopr(char *buffer, const char *format, va_list args);
>   
>   int
> + printf(const char *fmt,...)
> + {
> + 	int			len;
> + 	va_list			args;
> + 	static char*		buffer[4096];
> + 	char*			p;
> + 
> + 	va_start(args, fmt);
> + 	len = vsnprintf((char*)buffer, (size_t)4096, fmt, args);
> + 	va_end(args);
> + 	p = (char*)buffer;
> + 	for(;*p;p++)
> + 		putchar(*p);
> + 	return len;
> + }
> + 
> + int
>   snprintf(char *str, size_t count, const char *fmt,...)
>   {
>   	int			len;
> ***************
> *** 124,129 ****
> --- 146,155 ----
>   
>   static char *output;
>   
> + #define	FMTSTR		1
> + #define	FMTNUM		2
> + #define	FMTFLOAT	3
> + #define	FMTCHAR		4
>   
>   static void
>   dopr(char *buffer, const char *format, va_list args)
> ***************
> *** 139,145 ****
> --- 165,198 ----
>   	int			ljust;
>   	int			len;
>   	int			zpad;
> + 	int			i;
> + 	const char*		format_save;
> + 	const char*		fmtbegin;
> + 	int			fmtpos = 1;
> + 	int			realpos = 0;
> + 	int			position;
> + 	static struct{
> + 		const char*	fmtbegin;
> + 		const char*	fmtend;
> + 		void*	value;
> + 		long_long	numvalue;
> + 		double	fvalue;
> + 		int	charvalue;
> + 		int	ljust;
> + 		int	len;
> + 		int	zpad;
> + 		int	maxwidth;
> + 		int	base;
> + 		int	dosign;
> + 		char	type;
> + 		int	precision;
> + 		int	pointflag;
> + 		char	func;
> + 		int	realpos;
> + 	} fmtpar[NL_ARGMAX+1], *fmtparptr[NL_ARGMAX+1];
> + 
>   
> + 	format_save = format;
>   	output = buffer;
>   	while ((ch = *format++))
>   	{
> ***************
> *** 148,161 ****
>   			case '%':
>   				ljust = len = zpad = maxwidth = 0;
>   				longflag = longlongflag = pointflag = 0;
>   		nextch:
>   				ch = *format++;
>   				switch (ch)
>   				{
>   					case 0:
> ! 						dostr("**end of format**", 0);
> ! 						*output = '\0';
> ! 						return;
>   					case '-':
>   						ljust = 1;
>   						goto nextch;
> --- 201,215 ----
>   			case '%':
>   				ljust = len = zpad = maxwidth = 0;
>   				longflag = longlongflag = pointflag = 0;
> + 				fmtbegin = format - 1;
> + 				realpos = 0;
> + 				position = 0;
>   		nextch:
>   				ch = *format++;
>   				switch (ch)
>   				{
>   					case 0:
> ! 						goto performpr;
>   					case '-':
>   						ljust = 1;
>   						goto nextch;
> ***************
> *** 174,180 ****
> --- 228,241 ----
>   						if (pointflag)
>   							maxwidth = maxwidth * 10 + ch - '0';
>   						else
> + 						{ 
>   							len = len * 10 + ch - '0';
> + 							position = position * 10 + ch - '0';
> + 						}
> + 						goto nextch;
> + 					case '$':
> + 						realpos = position;
> + 						len = 0;
>   						goto nextch;
>   					case '*':
>   						if (pointflag)
> ***************
> *** 203,209 ****
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtnum(value, 10, 0, ljust, len, zpad);
>   						break;
>   					case 'o':
>   					case 'O':
> --- 264,280 ----
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].numvalue = value;
> ! 						fmtpar[fmtpos].base = 10;
> ! 						fmtpar[fmtpos].dosign = 0;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].zpad = zpad;
> ! 						fmtpar[fmtpos].func = FMTNUM;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 'o':
>   					case 'O':
> ***************
> *** 217,223 ****
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtnum(value, 8, 0, ljust, len, zpad);
>   						break;
>   					case 'd':
>   					case 'D':
> --- 288,304 ----
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].numvalue = value;
> ! 						fmtpar[fmtpos].base = 8;
> ! 						fmtpar[fmtpos].dosign = 0;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].zpad = zpad;
> ! 						fmtpar[fmtpos].func = FMTNUM;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 'd':
>   					case 'D':
> ***************
> *** 230,236 ****
>   						}
>   						else
>   							value = va_arg(args, int);
> ! 						fmtnum(value, 10, 1, ljust, len, zpad);
>   						break;
>   					case 'x':
>   						if (longflag)
> --- 311,327 ----
>   						}
>   						else
>   							value = va_arg(args, int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].numvalue = value;
> ! 						fmtpar[fmtpos].base = 10;
> ! 						fmtpar[fmtpos].dosign = 1;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].zpad = zpad;
> ! 						fmtpar[fmtpos].func = FMTNUM;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 'x':
>   						if (longflag)
> ***************
> *** 242,248 ****
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtnum(value, 16, 0, ljust, len, zpad);
>   						break;
>   					case 'X':
>   						if (longflag)
> --- 333,349 ----
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].numvalue = value;
> ! 						fmtpar[fmtpos].base = 16;
> ! 						fmtpar[fmtpos].dosign = 0;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].zpad = zpad;
> ! 						fmtpar[fmtpos].func = FMTNUM;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 'X':
>   						if (longflag)
> ***************
> *** 254,260 ****
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtnum(value, -16, 0, ljust, len, zpad);
>   						break;
>   					case 's':
>   						strvalue = va_arg(args, char *);
> --- 355,371 ----
>   						}
>   						else
>   							value = va_arg(args, unsigned int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].numvalue = value;
> ! 						fmtpar[fmtpos].base = -16;
> ! 						fmtpar[fmtpos].dosign = 1;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].zpad = zpad;
> ! 						fmtpar[fmtpos].func = FMTNUM;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 's':
>   						strvalue = va_arg(args, char *);
> ***************
> *** 262,273 ****
>   						{
>   							if (pointflag && len > maxwidth)
>   								len = maxwidth; /* Adjust padding */
> ! 							fmtstr(strvalue, ljust, len, zpad, maxwidth);
>   						}
>   						break;
>   					case 'c':
>   						ch = va_arg(args, int);
> ! 						dopr_outch(ch);
>   						break;
>   					case 'e':
>   					case 'E':
> --- 373,398 ----
>   						{
>   							if (pointflag && len > maxwidth)
>   								len = maxwidth; /* Adjust padding */
> ! 							fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 							fmtpar[fmtpos].fmtend = format;
> ! 							fmtpar[fmtpos].value = strvalue;
> ! 							fmtpar[fmtpos].ljust = ljust;
> ! 							fmtpar[fmtpos].len = len;
> ! 							fmtpar[fmtpos].zpad = zpad;
> ! 							fmtpar[fmtpos].maxwidth = maxwidth;
> ! 							fmtpar[fmtpos].func = FMTSTR;
> ! 							fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 							fmtpos++;
>   						}
>   						break;
>   					case 'c':
>   						ch = va_arg(args, int);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].charvalue = ch;
> ! 						fmtpar[fmtpos].func = FMTCHAR;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case 'e':
>   					case 'E':
> ***************
> *** 275,285 ****
>   					case 'g':
>   					case 'G':
>   						fvalue = va_arg(args, double);
> ! 						fmtfloat(fvalue, ch, ljust, len, maxwidth, pointflag);
>   						break;
>   					case '%':
> ! 						dopr_outch(ch);
> ! 						continue;
>   					default:
>   						dostr("???????", 0);
>   				}
> --- 400,419 ----
>   					case 'g':
>   					case 'G':
>   						fvalue = va_arg(args, double);
> ! 						fmtpar[fmtpos].fmtbegin = fmtbegin;
> ! 						fmtpar[fmtpos].fmtend = format;
> ! 						fmtpar[fmtpos].fvalue = fvalue;
> ! 						fmtpar[fmtpos].type = ch;
> ! 						fmtpar[fmtpos].ljust = ljust;
> ! 						fmtpar[fmtpos].len = len;
> ! 						fmtpar[fmtpos].maxwidth = maxwidth;
> ! 						fmtpar[fmtpos].pointflag = pointflag;
> ! 						fmtpar[fmtpos].func = FMTFLOAT;
> ! 						fmtpar[fmtpos].realpos = realpos?realpos:fmtpos;
> ! 						fmtpos++;
>   						break;
>   					case '%':
> ! 						break;
>   					default:
>   						dostr("???????", 0);
>   				}
> ***************
> *** 289,294 ****
> --- 423,475 ----
>   				break;
>   		}
>   	}
> + performpr:
> + 	/* shuffle pointers */
> + 	for(i = 1; i < fmtpos; i++)
> + 	{
> + 		fmtparptr[i] = &fmtpar[fmtpar[i].realpos];
> + 	}
> + 	output = buffer;
> + 	format = format_save;
> + 	while ((ch = *format++))
> + 	{
> + 		for(i = 1; i < fmtpos; i++)
> + 		{
> + 			if(ch == '%' && *format == '%')
> + 			{
> + 				format++;
> + 				continue;
> + 			}
> + 			if(fmtpar[i].fmtbegin == format - 1)
> + 			{
> + 				switch(fmtparptr[i]->func){
> + 				case FMTSTR:
> + 					fmtstr(fmtparptr[i]->value, fmtparptr[i]->ljust,
> + 						fmtparptr[i]->len, fmtparptr[i]->zpad,
> + 						fmtparptr[i]->maxwidth);
> + 					break;
> + 				case FMTNUM:
> + 					fmtnum(fmtparptr[i]->numvalue, fmtparptr[i]->base,
> + 						fmtparptr[i]->dosign, fmtparptr[i]->ljust,
> + 						fmtparptr[i]->len, fmtparptr[i]->zpad);
> + 					break;
> + 				case FMTFLOAT:
> + 					fmtfloat(fmtparptr[i]->fvalue, fmtparptr[i]->type,
> + 						fmtparptr[i]->ljust, fmtparptr[i]->len,
> + 						fmtparptr[i]->precision, fmtparptr[i]->pointflag);
> + 					break;
> + 				case FMTCHAR:
> + 					dopr_outch(fmtparptr[i]->charvalue);
> + 					break;
> + 				}
> + 				format = fmtpar[i].fmtend;
> + 				goto nochar;
> + 			}
> + 		}
> + 		dopr_outch(ch);
> + nochar:
> + 	/* nothing */
> + 	}
>   	*output = '\0';
>   }
>   

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 2: you can get off all lists at once with the unregister command
>     (send "unregister YourEmailAddressHere" to [email protected])

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [email protected]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

---------------------------(end of broadcast)---------------------------
TIP 5: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.