// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- // 
// C++ Source Code File Name: txfilter.cpp
// Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
// Produced By: Doug Gaer 
// File Creation Date: 09/17/1997
// Date Last Modified: 10/16/1998
// ----------------------------------------------------------- // 
// ------------- Program Description and Details ------------- // 
// ----------------------------------------------------------- // 
/*
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
CORRECTION.

Text file filter program used to filter out unwanted characters
from ASCII text files. This program can also be used to convert
DOS text files to a UNIX format of UNIX text files to a DOS
format.
*/
// ----------------------------------------------------------- // 
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdlib.h> 
#include <stdio.h>
#include <ctype.h>

// Define this macro for DOS file opens (the default is UNIX)
// #ifndef __MSDOS__
// #define __MSDOS__
// #endif

// Txfilter version number and program name
const double TXFilterVersionNumber = 1027.101;
const char *ProgramName = "txfilter";

// Program functions
void ProcessArgs(int argc, char *argv[]);
void HelpMessage(const char *program_name, const double version_number);
int ConvertTextFile(ifstream &infile, ostream &stream);

// Program globals
const int MAX_LINE = 1024; // Maximum characters per line
int VerboseMode;           // Echo results
char in_file[MAX_LINE];    // Input file to clean
char out_file[MAX_LINE];   // Optional output file name
int UNIX_TEXT_FORMAT = 1;  // Output text file in UNIX format
int DOS_TEXT_FORMAT = 0;   // Output text file in DOS CR/LF format
int filter_text = 1;       // Filter the text
int printable_chars = 1;   // Output all printable characters only
int alpha_chars = 0;       // Output alphabetic characters only
int alpha_num_chars = 0;   // Output alphanumeric characters only
int numeric_chars = 0;     // Output numeric characters only

void HelpMessage(const char *program_name, const double version_number)
{
  char vbuffer[255];
  sprintf(vbuffer, "%.3f", version_number);
  cout << endl;
  cout << "ASCII Text file filter program version "
       << vbuffer  << endl;
  cout << "Usage: " << program_name << " [switches] infile.txt "
       << "outfile.txt (optional)" << endl;
  cout << "Switches:  -?      = Display this help message." << endl;
  cout << "           -d      = Output text file in DOS CR/LF format."
       << endl;
  cout << "           -n      = No text filtering (defaults to filtered)."
       << endl;
  cout << "           -u      = Output text file in UNIX format (default)."
       << endl;
  cout << "           -P      = Output printable characters only (default)."
       << endl;
  cout << "           -A      = Output alphabetic characters only."
       << endl;
  cout << "           -M      = Output alphanumeric characters only."
       << endl;
  cout << "           -N      = Output numeric characters only."
       << endl;
  cout << endl;
  exit(0);
}

void ProcessArgs(int argc, char *argv[])
// Process the program's argument list
{
  int i;
  for(i = 1; i < argc; i++ ) {
    if(*argv[i] == '-') {
      char sw = *(argv[i] +1);
      switch(sw) {
	case '?' :
	  HelpMessage(ProgramName, TXFilterVersionNumber);
	  break;

	case 'd' :
	  DOS_TEXT_FORMAT = 1;   
	  UNIX_TEXT_FORMAT = 0;  
	  break;

	case 'n' :
	  filter_text = 0;
	  break;

	case 'u' :
	  DOS_TEXT_FORMAT = 0;   
	  UNIX_TEXT_FORMAT = 1;  
	  break;

	case 'v' :
	  VerboseMode = 1;
	  break;

	case 'P' :
	  printable_chars = 1;   // Output all printable characters only
	  alpha_chars = 0;       // Output alphabetic characters only
	  alpha_num_chars = 0;   // Output alphanumeric characters only
	  numeric_chars = 0;     // Output numeric characters only
	  break;

	case 'A' :
	  printable_chars = 0;   // Output all printable characters only
	  alpha_chars = 1;       // Output alphabetic characters only
	  alpha_num_chars = 0;   // Output alphanumeric characters only
	  numeric_chars = 0;     // Output numeric characters only
	  break;

	case 'M' :
	  printable_chars = 0;   // Output all printable characters only
	  alpha_chars = 0;       // Output alphabetic characters only
	  alpha_num_chars = 1;   // Output alphanumeric characters only
	  numeric_chars = 0;     // Output numeric characters only
	  break;

	case 'N' :
	  printable_chars = 0;   // Output all printable characters only
	  alpha_chars = 0;       // Output alphabetic characters only
	  alpha_num_chars = 0;   // Output alphanumeric characters only
	  numeric_chars = 1;     // Output numeric characters only
	  break;

	default:
	  cerr << endl;
	  cerr << "Unknown switch " << argv[i] << endl;
	  cerr << "Exiting..." << endl;
	  cerr << endl;
	  exit(0);
	  break;
      }
    }
    else { 
      strcpy(in_file, argv[i]);      // Input file name
      if(argv[i+1]) {
	strcpy(out_file, argv[i+1]); // Output file name
	break;
      }
      else
	break;
    }
  }
}

int ConvertTextFile(ifstream &infile, ostream &stream)
// Filter all unwanted control characters from the text file
{
  char LineBuffer[MAX_LINE];
  char OutputBuffer[MAX_LINE];
  int i, j;

  // Clear the buffers
  for(i = 0; i < MAX_LINE; i++) LineBuffer[i] = '\0';
  for(i = 0; i < MAX_LINE; i++) OutputBuffer[i] = '\0';
  
  while(!infile.eof()) {
    // Read in the file line by line
    for(i = 0, j = 0; i < MAX_LINE && !infile.eof(); i++) {
      infile.get(LineBuffer[i]);
      if(!filter_text) stream << LineBuffer[i];
      
      // Look for the end of line sequence CR/LF
      if(LineBuffer[i] == '\r' || LineBuffer[i] == '\n') break;

      if(filter_text) { // Output specified character sets only
	if(printable_chars)
	  if(isgraph(LineBuffer[i]) || LineBuffer[i] == ' ')
	    OutputBuffer[j++] = LineBuffer[i];

	if(alpha_chars)
	  if(isalpha(LineBuffer[i]) || LineBuffer[i] == ' ')
	    OutputBuffer[j++] = LineBuffer[i];
	
	if(alpha_num_chars)
	  if(isalnum(LineBuffer[i]) || LineBuffer[i] == ' ')
	    OutputBuffer[j++] = LineBuffer[i];
	
	if(numeric_chars)
	  if(isdigit(LineBuffer[i]) || LineBuffer[i] == ' ')
	    OutputBuffer[j++] = LineBuffer[i];
      }
    }

    if(OutputBuffer[0] != 0 && filter_text == 1) {
      if(DOS_TEXT_FORMAT)
	stream << OutputBuffer << "\r\n";
      else if(UNIX_TEXT_FORMAT)
	stream << OutputBuffer << "\n";
      else
	stream << OutputBuffer;
    }
    
    // Clear the buffer
    for(i = 0; i < MAX_LINE; i++) LineBuffer[i] = '\0';
    for(i = 0; i < MAX_LINE; i++) OutputBuffer[i] = '\0';
  }
  return 1;
}

int main(int argc, char *argv[])
// Program's main thread of execution
{
  // If no argument is given print usage message to the screen 1
  if(argc < 2) {
    HelpMessage(ProgramName, TXFilterVersionNumber);
    return(0);
  }

  // Process the programs command line arguments
  ProcessArgs(argc, argv);
  
  if(in_file[0] == 0 ) {
    cout << endl;
    cout << "You must specify a valid input file name." << endl;
    cout << endl;
    exit(0);
  }
    
#ifndef __MSDOS__
  // In UNIX there is only one file type
  ifstream infile(in_file, ios::in | ios::nocreate);
#else 
  // In MS-DOS/Windows there are two file types, text and binary
  ifstream infile(in_file, ios::in | ios::binary | ios::nocreate);
#endif

  if(!infile) {
      cerr << endl;
      cerr << "Cannot open file: " << in_file << endl;
      cerr << "Exiting..." << endl;
      cerr << endl;
    return 1;
  }

  if(out_file[0] == 0 ) {
    ConvertTextFile(infile, cout);
  }
  else { // Open specified file and truncate it
#ifndef __MSDOS__
  // In UNIX there is only one file type
  ofstream stream(out_file, ios::out); 
#else 
  // In MS-DOS/Windows there are two file types, text and binary
  ofstream stream(out_file, ios::out|ios::binary); 
#endif

    if(!stream) {
      cerr << endl;
      cerr << "Cannot open " << out_file << endl;
      cerr << endl;
      return 1;
    }
    ConvertTextFile(infile, stream);
    stream.close();
  }

  infile.close();
  return 0;
}
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //
