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

/*

  Program to walk a directory and convert each file it finds from
  DOS format to Unix format, Unix format to DOS format, Mac format
  to Unix format, or Unix format to Mac format.

  The various line-ending styles are:

  Mac: \r
  Unix: \n
  DOS:  \r\n

  Author: Nick Gammon <nick@gammon.com.au>
  Date:   18th February 1998

  Copyright 1998 Gammon Software Solutions. 

  This program and source may be redistributed provided no charge is made
  for it, and credit given to the original author.

  Usage:  unix2dos <wildcard1> [<wildcard2>, ... ]
          dos2unix <wildcard1> [<wildcard2>, ... ]
          mac2unix <wildcard1> [<wildcard2>, ... ]

  eg.     unix2dos c:\source\mush\*.c
          dos2unix *.h *.c *.cpp
          mac2unix *.c

  All versions are in the same source file.


  Define:
  
    UNIX2DOS in "project settings" to make a unix2dos program
    DOS2UNIX in "project settings" to make a dos2unix program
    MAC2UNIX in "project settings" to make a mac2unix program
    UNIX2MAC in "project settings" to make a unix2mac program


*/

#ifdef UNIX2DOS

#define PROGRAMNAME "unix2dos"
#define RENAMESUFFIX ".unix"
#define INPUTMODE "rb"
#define OUTPUTMODE "w"

#elif DOS2UNIX

#define PROGRAMNAME "dos2unix"
#define RENAMESUFFIX ".dos"
#define INPUTMODE "r"
#define OUTPUTMODE "wb"

#elif MAC2UNIX

#define PROGRAMNAME "mac2unix"
#define RENAMESUFFIX ".mac"
#define INPUTMODE "rb"
#define OUTPUTMODE "wb"
#define SEARCHFOR '\r'
#define REPLACEWITH '\n'

#elif UNIX2MAC

#define PROGRAMNAME "unix2mac"
#define RENAMESUFFIX ".unix"
#define INPUTMODE "rb"
#define OUTPUTMODE "wb"
#define SEARCHFOR '\n'
#define REPLACEWITH '\r'

#else

#error Please include a define for: UNIX2DOS, DOS2UNIX, MAC2UNIX, or UNIX2MAC

#endif

// helper define for appending an "s" to plural amounts
#define PLURAL(arg) arg, arg == 1 ? "" : "s"

#define BOOL int
#define FALSE 0
#define TRUE 1


long nFiles = 0;
long nErrors = 0;
long nWarnings = 0;
long nTotalLines = 0;

void ProcessWildcard (char * sWildcard)
  {
  struct _finddata_t fileinfo;
  long nFindFileHandle;

  char sInputFileName [_MAX_PATH];
  char sOutputFileName [_MAX_PATH];

  char sBuff [5000];

  FILE * fi;
  FILE * fo;

  char * p;

  BOOL bWriteError = FALSE;
  long nLines;
  int iRenameResult,
      iDeleteResult;

  printf ("Processing wildcard \"%s\"\n", sWildcard);

  nFindFileHandle = _findfirst (sWildcard, &fileinfo);

  if (nFindFileHandle == -1)
    {
    printf ("*** Unable to find any files matching sWildcard: %s\n", sWildcard);    
    nWarnings++;
    return;
    }

  do
    {
  
    if ((fileinfo.attrib & _A_SUBDIR) == 0)
      {

      // display name of file we are processing
      printf ("%s \n",fileinfo.name);

      // calculate full pathnames
      strcpy (sOutputFileName, sWildcard);

      // strip off trailing filename sWildcard
      p = strrchr (sOutputFileName, '\\');
      if (p)
        {
        *p = 0;   // remove everything past the slash
        strcat (sOutputFileName, "\\");
        }
      else
        strcpy (sOutputFileName, "");    // no directory, must be in current directory

      strcat (sOutputFileName, fileinfo.name);
      strcpy (sInputFileName, sOutputFileName);
      strcat (sInputFileName, RENAMESUFFIX);

      // rename input file with a different suffix
      iRenameResult = rename (sOutputFileName, sInputFileName);
      if (iRenameResult != 0)
        {
        perror( "Rename of input file failed" );
        printf ("Could not rename \"%s\" to \"%s\".\n", sOutputFileName, sInputFileName);
        nErrors++;
        continue;   // don't convert this one
        }

      // open input file
      fi = fopen (sInputFileName, INPUTMODE);
      if (fi == NULL)
        {
        perror( "Open of input file failed" );
        printf ("File name: \"%s\".\n", sInputFileName);
        nErrors++;
        continue;
        }

      // open output file
      fo = fopen (sOutputFileName, OUTPUTMODE);
      if (fo == NULL)
        {
        fclose (fi);    // close input file already opened
        perror( "Open of output file failed" );
        printf ("File name: \"%s\".\n", sOutputFileName);
        nErrors++;
        continue;
        }

      nLines = 0;

      while (!feof (fi))
        {

// In the case of Mac input/output we simply want to change \n to \r or vice versa.
// We may as well do this in chunks.

#if  defined (MAC2UNIX) || defined (UNIX2MAC)
        {
        size_t iNumRead;

        iNumRead = fread(sBuff, sizeof(char), sizeof (sBuff), fi);
        if (iNumRead == 0)
          break;

        // convert each carriage-return into a linefeed, thus going from Mac to Unix
        // or vice-versa

        while (p = strrchr (sBuff, SEARCHFOR))
          {
          *p = REPLACEWITH;
          nLines++;
          nTotalLines++;
          }

        if (fwrite(sBuff, sizeof(char), iNumRead, fo) != iNumRead)
          {
          perror( "Error writing to output file" );
          printf ("File name: \"%s\".\n", sOutputFileName);
          bWriteError = TRUE;
          nErrors++;
          break;
          }

        
        }

#else   // read line-by-line

        if  (fgets(sBuff, sizeof (sBuff), fi) == NULL)
          break;
      
        nLines++;
        nTotalLines++;

        // strip trailing carriage return, if any
        p = strrchr (sBuff, '\r');
        if (p)
          *p = 0;

        // make sure line ends with newline
        if (sBuff [strlen (sBuff) - 1] != '\n')
          strcat (sBuff, "\n");

        if (fputs (sBuff, fo) == EOF)
          {
          perror( "Error writing to output file" );
          printf ("File name: \"%s\".\n", sOutputFileName);
          bWriteError = TRUE;
          nErrors++;
          break;
          }

#endif    // not Mac-style read

        }   // end of read loop

      fclose (fi);
      fclose (fo);

// If no error, delete backup file

      if (bWriteError)
        printf ("Original file is now called \"%s\"\n", sInputFileName);
      else
        {
        iDeleteResult = remove (sInputFileName);
        if (iDeleteResult != 0)
          {
          perror( "Delete of original file failed" );
          printf ("Could not delete \"%s\".\n", sInputFileName);
          nErrors++;
          }
        nFiles++;   // count files successfully converted
        }

      }   // end of not being a subdirectory


    } while (!bWriteError && _findnext (nFindFileHandle, &fileinfo) != -1);   // end of file loop

  _findclose (nFindFileHandle);


  } // end of ProcessWildcard

int main (int iArgumentCount, char * sArgument [])
  {

  int iArgument;

  if (iArgumentCount <= 1)
    {
    printf ("Usage: " PROGRAMNAME " <wildcard1> [ <wildcard2> ...]\n");
    return 1;
    }

  printf (PROGRAMNAME " Version 1.01 (Gammon Software Solutions) 13-Mar-98\n");

  // process each wildcard or filename supplied on the command line

  for (iArgument = 1; iArgument < iArgumentCount; iArgument++)
    ProcessWildcard (sArgument [iArgument]);

  // show file count
  printf ("%ld file%s converted.\n", PLURAL (nFiles));
  // show line count
  printf ("%ld total line%s converted.\n", PLURAL (nTotalLines));
  // show error and warning count
  printf ("%ld error%s.\n", PLURAL (nErrors));
  printf ("%ld warning%s.\n", PLURAL (nWarnings));

	return nErrors;   // no errors will mean OK return

  } // end of main