/* ========================================================================== **
 *                                debug2html.c
 *
 * Copyright (C) 1998 by Christopher R. Hertel
 *
 * Email: crh@ubiqx.mn.org
 *
 * -------------------------------------------------------------------------- **
 * Parse Samba debug logs (2.0 & greater) and output the results as HTML.
 * -------------------------------------------------------------------------- **
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * -------------------------------------------------------------------------- **
 * This program provides an example of the use of debugparse.c, and also
 * does a decent job of converting Samba logs into HTML.
 * -------------------------------------------------------------------------- **
 *
 * $Revision: 1.9 $
 *
 * ========================================================================== **
 */

#include "includes.h"

/* -------------------------------------------------------------------------- **
 * Global values.
 */

FILE *infile;
FILE *outfile;

/* -------------------------------------------------------------------------- **
 * The size of the read buffer.
 */

#define DBG_BSIZE 1024

/* -------------------------------------------------------------------------- **
 * Functions...
 */

static dbg_Token modechange( dbg_Token new, dbg_Token mode )
  /* ------------------------------------------------------------------------ **
   * Handle a switch between header and message printing.
   *
   *  Input:  new   - The token value of the current token.  This indicates
   *                  the lexical item currently being recognized.
   *          mode  - The current mode.  This is either dbg_null or
   *                  dbg_message.  It could really be any toggle
   *                  (true/false, etc.)
   *
   *  Output: The new mode.  This will be the same as the input mode unless
   *          there was a transition in or out of message processing.
   *
   *  Notes:  The purpose of the mode value is to mark the beginning and end
   *          of the message text block.  In order to show the text in its
   *          correct format, it must be included within a <PRE></PRE> block.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  switch( new )
    {
    case dbg_null:
    case dbg_ignore:
      return( mode );
    case dbg_message:
      if( dbg_message != mode )
        {
        /* Switching to message mode. */
        (void)fprintf( outfile, "<PRE>\n" );
        return( dbg_message );
        }
      break;
    default:
      if( dbg_message == mode )
        {
        /* Switching out of message mode. */
        (void)fprintf( outfile, "</PRE>\n\n" );
        return( dbg_null );
        }
    }

  return( mode );
  } /* modechange */

static void newblock( dbg_Token old, dbg_Token new )
  /* ------------------------------------------------------------------------ **
   * Handle the transition between tokens.
   *
   *  Input:  old - The previous token.
   *          new - The current token.
   *
   *  Output: none.
   *
   *  Notes:  This is called whenever there is a transition from one token
   *          type to another.  It first prints the markup tags that close
   *          the previous token, and then the markup tags for the new
   *          token.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  switch( old )
    {
    case dbg_timestamp:
      (void)fprintf( outfile, ",</B>" );
      break;
    case dbg_level:
      (void)fprintf( outfile, "</FONT>]</B>\n   " );
      break;
    case dbg_sourcefile:
      (void)fprintf( outfile, ":" );
      break;
    case dbg_lineno:
      (void)fprintf( outfile, ")" );
      break;
    default:
      break;
    }

  switch( new )
    {
    case dbg_timestamp:
      (void)fprintf( outfile, "<B>[" );
      break;
    case dbg_level:
      (void)fprintf( outfile, " <B><FONT COLOR=MAROON>" );
      break;
    case dbg_lineno:
      (void)fprintf( outfile, "(" );
      break;
    default:
      break;
    }
  } /* newblock */

static void charprint( dbg_Token tok, int c )
  /* ------------------------------------------------------------------------ **
   * Filter the input characters to determine what goes to output.
   *
   *  Input:  tok - The token value of the current character.
   *          c   - The current character.
   *
   *  Output: none.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  switch( tok )
    {
    case dbg_ignore:
    case dbg_header:
      break;
    case dbg_null:
    case dbg_eof:
      (void)putc( '\n', outfile );
      break;
    default:
      switch( c )
        {
        case '<':
          (void)fprintf( outfile, "&lt;" );
          break;
        case '>':
          (void)fprintf( outfile, "&gt;" );
          break;
        case '&':
          (void)fprintf( outfile, "&amp;" );
          break;
        case '\"':
          (void)fprintf( outfile, "&#34;" );
          break;
        default:
          (void)putc( c, outfile );
          break;
        }
    }
  } /* charprint */

static void convert( void )
  /* ------------------------------------------------------------------------ **
   * Read the input logfile, converting the entries to HTML.
   *
   *  Input:  none.
   *  output: none.
   *  Notes:  Reads from the global infile, writes to the global outfile.
   *          These default to stdin and stdout, respectively.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  int       i;
  int       len;
  char      bufr[DBG_BSIZE];
  dbg_Token old   = dbg_null,
            new   = dbg_null,
            state = dbg_null,
            mode  = dbg_null;

  while( (!feof( infile ))
      && ((len = fread( bufr, 1, DBG_BSIZE, infile )) > 0) )
    {
    for( i = 0; i < len; i++ )
      {
      old = new;
      new = dbg_char2token( &state, bufr[i] );
      if( new != old )
        {
        mode = modechange( new, mode );
        newblock( old, new );
        }
      charprint( new, bufr[i] );
      }
    }
  (void)modechange( dbg_eof, mode );

  } /* convert */

static void usage( void )
  /* ------------------------------------------------------------------------ **
   * Prints a usage message on stderr, then gently exits.
   *
   *  Input:  none.
   *  Output: none.  Exits with return code of 0.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  fprintf( stderr, "This utility converts Samba log files " );
  fprintf( stderr, "into HTML documents.\n" );
  fprintf( stderr, "Usage:\n" );
  fprintf( stderr, "  debug2html <infile> <outfile>\n" );
  exit( 0 );
  } /* usage */

static FILE *carefull_fopen( const char *path, const char *type )
  /* ------------------------------------------------------------------------ **
   * Checks for leading '-' characters, which are generically regarded as
   * flags.  Also exits the program gracefully should the file fail to open.
   *
   *  Input:  path  - pathname of the file to open.
   *          type  - open mode.  See fopen(3S).
   *
   *  Output: Pointer to open file.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  FILE *tmp;

  if( '-' == path[0] || '\0' == path[0] )
    usage();

  tmp = sys_fopen( path, type );
  if( NULL == tmp )
    {
    fprintf( stderr, "Error opening file %s: %s\n", path, strerror(errno) );
    exit( 1 );
    }
  return( tmp );
  } /* carefull_fopen */

int main( int argc, char *argv[] )
  /* ------------------------------------------------------------------------ **
   * This simple program scans and parses Samba debug logs, and produces HTML
   * output.
   *
   *  Input:  argc    - Argument count.
   *          argv[1] - Input file name.
   *          argv[2] - Output file name.
   *                    A '-' character by itself means use defaults (i.e.,
   *                    <stdin> or <stdout> depending upon the argument.
   *                    A string beginning with '-' and containing more than
   *                    that one character will generate a usage message.
   *
   *  Output: An exit value of 1 is returned if an error was encountered
   *          while opening a file, else 0.
   *
   *  Notes:  The HTML output is sent to stdout.
   *
   * ------------------------------------------------------------------------ **
   */
  {
  if( argc > 3 )
    usage();

  infile = stdin;
  outfile = stdout;

  if( argc > 1 && 0 != strcmp( argv[1], "-" ) )
    infile = carefull_fopen( argv[1], "r" );

  if( argc > 2 && 0 != strcmp( argv[2], "-" ) )
    infile = carefull_fopen( argv[2], "w" );

  (void)fprintf( outfile,
                 "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n" );
  (void)fprintf( outfile, "<HTML>\n<HEAD>\n" );
  (void)fprintf( outfile,
                 "  <TITLE>Samba Log</TITLE>\n</HEAD>\n\n<BODY>\n" );

  convert();

  (void)fprintf( outfile, "</BODY>\n</HTML>\n" );

  return( 0 );
  } /* main */