/*
 * $Header: /home/gene/library/website/docsrc/wel/src/RCS/print-log.c,v 395.1 2008/04/20 17:25:48 gene Exp $
 *
 * Copyright (c) 2005 Gene Michael Stover.  All rights reserved.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "this.h"

/*
 */
typedef enum {ACTION_RUN, ACTION_HELP } ActionEnum;
static ActionEnum S_action = ACTION_RUN;

/*
 */
static EVENTLOGRECORD *
S_Next (HANDLE hnd)
{
  EVENTLOGRECORD *x = NULL;
  static DWORD flags = EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ;
  static DWORD offset = 0;              /* ignored because we aren't SEEKing */
  DWORD read_count, needed_count, sz;

  x = (EVENTLOGRECORD *) xmalloc (1);
  if  (!ReadEventLog (hnd, flags, offset, x, 0, &read_count, &needed_count) &&
       GetLastError () == ERROR_INSUFFICIENT_BUFFER &&
       needed_count > 0) {
    sz = needed_count;
    x = (EVENTLOGRECORD *) xrealloc (x, sz);
    if (ReadEventLog (hnd, flags, offset, x, sz, &read_count, &needed_count)) {
      /* good */
    } else {
      LOG_LastError ("ReadEventLog", __FILE__, __LINE__);
      fprintf (stderr, "\n%s:%d: ReadEventLog failed", __FILE__, __LINE__);
      x = (EVENTLOGRECORD *) xfree (x);
    }
  } else if (GetLastError() == ERROR_HANDLE_EOF) {
    /* 
     * Normal end-of-file indication.  This is not an error.
     */
    x = (EVENTLOGRECORD *) xfree (x);
  } else {
    /*
     * ReadEventLog failed, & it was NOT because our buffer was too
     * small.  This is an error or an end-of-file situation.
     */
    LOG_LastError ("ReadEventLog", __FILE__, __LINE__);
    fprintf (stderr, "\n%s:%d: ReadEventLog failed", __FILE__, __LINE__);
    x = (EVENTLOGRECORD *) xfree (x);
  }
  return x;
}

/*
 */
static Boolean S_isSignal = FALSE;

/*
 */
static void
S_Signal (int sig)
{
  S_isSignal = TRUE;
}

/*
 */
static EVENTLOGRECORD *
S_NextMinusF (HANDLE hnd)
{
  EVENTLOGRECORD *x = NULL;

  signal (SIGINT, &S_Signal);
  do {
    x = S_Next (hnd);
    if (x == NULL) Sleep (1000);        /* wait a sec */
  } while (x == NULL && !S_isSignal);
  return x;
}

/*
 */
static void (*S_printFn) (EVENTLOGRECORD *) = &TAB_Print;

/*
 */
static EVENTLOGRECORD *(*S_read) (HANDLE) = &S_Next;

/*
 */
static int
S_CommandLine (int argc, char *argv[])
{
  int rc = 0, c;

  while (rc == 0 && (c = getopt (argc, argv, "c:fhlx")) != EOF) {
    switch (c) {
    case 'c':
      TAB_tab = *optarg;
      S_printFn = &TAB_Print;
      break;
    case 'f':
      S_read = &S_NextMinusF;
      break;
    case 'h':
      S_action = ACTION_HELP;
      break;
    case 'l':
      S_printFn = &LISP_Print;
      break;
    case 'x':
      S_printFn = &XML_Print;
      break;
    case ':':
      fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
      fprintf (stderr, " getopt returned '%c'.", c);
      fprintf (stderr, "  Missing argument to an option which requires");
      fprintf (stderr, " an argument?");
      rc = 101;
      break;
    case '?':
      fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
      fprintf (stderr, " getopt returned '%c'.", c);
      fprintf (stderr, "  Unrecognized command line option?");
      rc = -54;
      break;
    default:
      fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
      fprintf (stderr, " getopt returned '%c'.", c);
      fprintf (stderr, "  This is a really weird error.");
      rc = 22;
      break;
    }
  }
  if (rc == 0) {
    while (optind < argc) {
      fprintf (stderr, "\n%s:%d:", __FILE__, __LINE__);
      fprintf (stderr, " Ignoring argv[%d] \"%s\"", optind, argv[optind]);
      ++optind;
    }
  }
  return rc;
}

/*
 */
static void
S_Help (char progname[])
{
  printf ("\n   %s",
          "$Id: print-log.c,v 395.1 2008/04/20 17:25:48 gene Exp $");
  printf ("\n   Copyright (c) 2005 Gene Michael Stover.  All rights");
  printf (" reserved.");
  printf ("\n");
  printf ("\n%s : print entries from the Windows Event Log",
          progname == NULL ? "print-log" : progname);
  printf ("\n%s [-f] [-cTAB | -l | -x]",
          progname == NULL ? "print-log" : progname);
  printf ("\n-c TAB requests output in Delimeter Separated Values");
  printf ("\n       form with TAB (which must be a character) as the");
  printf ("\n       field separator.  If you use \"-c\", you must specify");
  printf ("\n       a character for TAB.  -c is incompatible with -l & -x.");
  printf ("\n-l     requests output as Lisp data.  -l is incompatible with");
  printf ("\n       -c & -x.");
  printf ("\n-x     requests output as XML.  It's not a full XML document");
  printf ("\n       because it does not have a single root element; it's a");
  printf ("\n       sequence of <EVENTLOGRECORD>...</EVENTLOGRECORD>");
  printf ("\n       elements.  There may be other ways in which it's not");
  printf ("\n       valid XML.  The idea is that you can easily wrap this");
  printf ("\n       pseudo-XML output to create valid XML.  -x is");
  printf ("\n       incompatible with -c & -l.");
  printf ("\nIf you omit -c, -l, & -x, it is as if you specified -c with a");
  printf ("\nTAB character of tab ('\\t').");
  printf ("\n-f     Tells PRINT-LOG that it should keep printing new event");
  printf ("\n       log messages as they arrive.  Use Ctrl-C to end");
  printf ("\n       PRINT-LOG when it is running in this mode.  The \"-f\"");
  printf ("\n       option can be used with the -c, -l, or -x options.  The");
  printf ("\n       -f option for PRINT-LOG resembles the -f option for the");
  printf ("\n       \"tail\" program from unix.");
  printf ("\n%s -h", progname == NULL ? "progname" : progname);
  printf ("\nGives you this message.  Complete instructions, executable");
  printf ("\nfiles, & source code are at");
  printf (" <http://cybertiggyr.com/gene/wel/>.");
  printf ("\n");
}

/*
 */
int
main (int argc, char *argv[])
{
  int rc = 0;

  if (S_CommandLine (argc, argv) == 0) {
    switch (S_action) {
    case ACTION_RUN:
      if (PL_Run (S_read, S_printFn) == 0) {
        /* good */
      } else {
        fprintf (stderr, "\n%s:%d: S_Run failed", __FILE__, __LINE__);
        rc = 234;
      }
      break;
    default: S_Help (argv[0]); break;
    }
  } else {
    fprintf (stderr, "\n%s:%d: S_CommandLine failed", __FILE__, __LINE__);
    rc = 23;
  }
  return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

/* --- end of file --- */
