/*
 * output.c - log output function for various formats
 * $Id: output.c,v 1.3 2004/06/05 15:15:17 rdenisc Exp $
 */

/***********************************************************************
 *  Copyright (C) 2002-2003 Remi Denis-Courmont.                       *
 *  This program is free software; you can redistribute and/or modify  *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation; version 2 of the license.         *
 *                                                                     *
 *  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, you can get it from:              *
 *  http://www.gnu.org/copyleft/gpl.html                               *
 ***********************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "secstdio.h"
#include <ctype.h> /* isprint() */

#include "gettext.h"

#include "output.h"

int fwrite_count (const void *buf, int len, FILE *stream)
{
	fprintf (stream, _("%d byte(s)\n"), len);
	return len;
}


/*
 * Displays non-readable and extended characters in C string-like form.
 */
static int
fputc_C (int c, FILE *stream)
{
	unsigned char b;
	int errflag;
	b = (unsigned char)c;

	if (b > 127)
		errflag = fprintf (stream, "\\0x%02X", (unsigned int)b) != 5;
	else if (b == '\\')
		errflag = fputs ("\\\\", stream) < 0;
	else if (b >= 32)
		errflag = fputc(c, stream) != b;
	else switch (b) {
		case 0:
			errflag = fputs ("\\0", stream) < 0;
			break;
			
		case '\r':
			errflag = fputs ("\\r", stream) < 0;
			break;
			
		case '\n':
			errflag = fputs ("\\n", stream) < 0;
			break;
			
		case 27:
			errflag = fputs ("\\E", stream) < 0;
			break;
			
		default:
			errflag = fprintf (stream, "\\0x%02X", (unsigned int)b) != 5;
	}
	return errflag ? EOF : b;

}


int fwrite_C (const void *buf, int len, FILE *stream)
{
	int i;
	for (i = 0; i < len; i++)
		if (fputc_C (((const unsigned char *)buf)[i], stream) == EOF)
			return i;
	fputs ("\n", stream);
	return len;
}


/*
 * Displays only printable ASCII characters.
 */
static int
fputc_strip (int c, FILE *stream)
{
	return (fputc (isprint (c) ? c : '.', stream) != EOF)
		? (unsigned char)c : EOF;
}


int fwrite_strip (const void *buf, int len, FILE *stream)
{
	int i;
	unsigned char c;

	for (i = 0; i < len; i++)
	{
		c = ((const unsigned char *)buf)[i];
		if (c != '\r')
		{
			if (((c != '\n') ? fputc_strip (c, stream)
					: fputc ('\n', stream)) == EOF)
				return i;
		}
	}
	return len;
}


/*
 * Displays any characters in hexadecimal form
 * (for binary protocols).
 */
#define HEX_DIGIT( n ) ((n) < 10) ? ('0' + (n)) : ('A' + (n) - 10)
static int
fputc_hex (int c, FILE *stream)
{
	unsigned char b;
	b = (unsigned char)c;

	if ((fputc (HEX_DIGIT(b >> 4), stream) == EOF)
	 || (fputc (HEX_DIGIT(b & 0x0f), stream) == EOF))
		return EOF;
	return b;
}
#undef HEX_DIGIT


int fwrite_hex (const void *buf, int len, FILE *stream)
{
	int i = 0, j = 0;

	if (fputs ("   |  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F |\n"
		   "-------+-------------------------------------------------+"
		   "----------------\n", stream) == EOF)
		return 0;

	while (i < len)
	{
		if (fprintf (stream, "0x%04x | ", i) != 9)
			return 0;
		do
		{
			if ((fputc_hex (((const unsigned char *)buf)[j],
				stream) == EOF)
			 || (fputc (' ', stream) == EOF))
				return i;
			j++;
		}
		while ((j & 0xf) && (j < len));

		/* fills extra space at end of packet */
		while (j & 0xf)
		{
			if (fwrite("   ", 3, 1, stream) != 1)
				return i;
			j++;
		}

		if (fwrite ("| ", 2, 1, stream) != 1)
			return i;
		do
		{
			if (fputc_strip (((const unsigned char *)buf)[i],
					stream) == EOF)
				return i;
			i++;
		}
		while ((i & 0xf) && (i < len));

		if (fputc ('\n', stream) == EOF)
			return i;
	}
	fprintf (stream, _("Packet length: 0x%04x (%5d) byte(s)\n\n"), len, len);
	return len;
}

/*
 * Displays any characters without encoding
 * (for pure 7-bit clean protocols mainly).
 * USE IS DISCOURAGED.
 */
int fwrite_raw (const void *buf, int len, FILE *stream)
{
	return fwrite (buf, 1, len, stream);
}



syntax highlighted by Code2HTML, v. 0.9.1