/*
* $Id: c.html,v 1.1.1.1 1999/09/28 16:43:44 sbooth Exp $
*
* Copyright (C) 1998, 1999 Stephen F. Booth
*
* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <stdio.h>
#include <string.h>

#include "markup.h"
#include "getopt.h"


/* Externs from flex */
extern int c_yylex();
extern int cpp_yylex();
extern int java_yylex();

extern FILE *cpp_yyout, *cpp_yyin;
extern FILE *c_yyout, *c_yyin;
extern FILE *java_yyout, *java_yyin;

/* Formatting modes */
#define DEFAULT_MODE 0
#define C_MODE 1
#define CPP_MODE 2
#define JAVA_MODE 3

/* Long options */
#define LONGOPT_VERSION 1
#define LONGOPT_HELP 2
#define LONGOPT_C_MODE 3
#define LONGOPT_CPP_MODE 4
#define LONGOPT_JAVA_MODE 5

/* Indicates which long option was selected */
static int gLongOption;

/* List of short options accepted */
static const char sShortOpts [] = "vhcCj";

/* List of long options accepted */
static const struct option sLongOpts [] = {
  { "version", no_argument, &gLongOption, LONGOPT_VERSION },
  { "help", no_argument, &gLongOption, LONGOPT_HELP },
  { "c-mode", no_argument, &gLongOption, LONGOPT_C_MODE },
  { "cpp-mode", no_argument, &gLongOption, LONGOPT_CPP_MODE },
  { "java-mode", no_argument, &gLongOption, LONGOPT_JAVA_MODE },
  {0, 0, 0, 0}
};

/* The program name */
static const char *gProgName;

/* A lex/flex lexer function */
typedef int (*lexer_func) (void);

/* A filename extension/mode mapping */
struct extension {
  char *name;
  int mode;
};

static const struct extension sExtensions [] = {
  { ".c", C_MODE },
  { ".h", C_MODE },
  { ".cc", CPP_MODE },
  { ".cpp", CPP_MODE },
  { ".cp", CPP_MODE },
  { ".C", CPP_MODE },
  { ".hh", CPP_MODE },
  { ".hpp", CPP_MODE },
  { ".hp", CPP_MODE },
  { ".H", CPP_MODE },
  { ".java", JAVA_MODE },
  { "", DEFAULT_MODE },
  { 0, 0 }
};


/* Print version of src2html */
static void printVersion()
{
  printf("src2html version %s, by Stephen F. Booth.\n", VERSION);
  puts("Copyright (C) 1998, 1999 Stephen F. Booth");
  puts("This is free software; see the source for copying conditions.");
  puts("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A");
  puts("PARTICULAR PURPOSE.");
  puts("");
  puts("Report bugs to <sbooth@saaba.lmi.net>");
}

/* Usage information */
static void usage()
{
  printf("Usage: %s [OPTIONS] [FILES]\n", gProgName);
  puts("Options:");
  puts("  -h, --help        Print this message and exit.");
  puts("  -v, --version     Print the version number of src2html and exit.");
  puts("  -c, --c-mode      Format source as C code.");
  puts("  -C, --cpp-mode    Format source as C++ code.");
  puts("  -j, --java-mode   Format source as Java code.");
}

/* Format a file */
static void formatFile(const char *filename,
    int mode,
    FILE *out)
{
  FILE *f;
  int use_stdin = 0;
  lexer_func lexer;

  /* open the file */
  if(strcmp(filename, "-") == 0) {
    use_stdin = 1;
    filename = "stdin";
    f = stdin;
  }
  else {
    f = fopen(filename, "r");
    if(f == 0) {
      printf("%s: Error opening file \"%s\"\n", gProgName, filename);
      exit(1);
    }
  }

  /* setup input/output and lexer */
  switch(mode) {
    case DEFAULT_MODE: cpp_yyin  = f; cpp_yyout  = out; lexer = cpp_yylex; break;
    case CPP_MODE:     cpp_yyin  = f; cpp_yyout  = out; lexer = cpp_yylex; break;
    case C_MODE:       c_yyin    = f; c_yyout    = out; lexer = c_yylex;   break;
    case JAVA_MODE:    java_yyin = f; java_yyout = out; lexer = java_yylex;break;
  }

  /* format the file */
  fprintf(out, "<!-- HTML generated by src2html from %s -->\n", filename);
  fputs(START_TEXT, out);
  (*lexer)();
  fputs(END_TEXT, out);

  if(use_stdin == 0)
    fclose(f);
}

/* Main Street, USA */
int main(int argc, 
    char **argv)
{
  int i = 0;
  int c = 0;
  char *ext = 0;
  int curlen = 0;
  int extlen = 0;
  int showVersion = 0;
  int showUsage = 0;
  int curarg = 0;
  int mode = DEFAULT_MODE;

  /* setup params */
  gLongOption = 0;
  gProgName = argv[0];

  /* parse the command-line arguments */
  while( (c = getopt_long(argc, argv, sShortOpts, sLongOpts, (int*)0)) != -1) {

    /* handle single-character switches */
    switch(c) {
      case '?': showUsage = 1;    break;
      case 'h': showUsage = 1;    break;
      case 'v': showVersion = 1;  break;
      case 'c': mode = C_MODE;    break;
      case 'C': mode = CPP_MODE;  break;
      case 'j': mode = JAVA_MODE; break;
    }

    /* handle long-style options */
    switch(gLongOption) {
      case LONGOPT_VERSION:   showVersion = 1;  break;
      case LONGOPT_HELP:      showUsage = 1;    break;
      case LONGOPT_C_MODE:    mode = C_MODE;    break;
      case LONGOPT_CPP_MODE:  mode = CPP_MODE;  break;
      case LONGOPT_JAVA_MODE: mode = JAVA_MODE; break;
    }

    /* reset params */
    gLongOption = 0;
  }

  /* show usage */
  if(showUsage) {
    usage();
    exit(0);
  }

  /* show version */
  if(showVersion) {
    printVersion();
    exit(0);
  }

  /* if no files specified, use stdin */
  if(optind == argc) {
    formatFile("-", mode, stdout);
  }
  else {
    /* format the files specified on command line */
    for(curarg = optind; curarg < argc; ++curarg) {
      
      /* determine the file type by extension */
      for(i = 0; sExtensions[i].name != 0; ++i) {
        curlen = strlen(argv[curarg]);
        extlen = strlen(sExtensions[i].name);
        ext = argv[curarg] + curlen - extlen;
        if(curlen > extlen && strcmp(ext, sExtensions[i].name) == 0) {
          formatFile(argv[curarg], 
              (mode == DEFAULT_MODE ? sExtensions[i].mode : mode),
              stdout);
          break;
        }
      }
    } 
  }
  
  exit(0);
}