#include <fcntl.h>
#include <proto/dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum {AMIGA, IBM};

const char *version="$VER: AddCR 1.0 (4.8.93)";

/*********
  Protos
*********/
extern int __asm amiga2ibm(register __a0 char *inbuffer,
                             register __a1 char *outbuffer,
                             register __d1 int bytes_read);
extern int __asm ibm2amiga(register __a0 char *inbuffer,
                             register __a1 char *outbuffer,
                             register __d1 int bytes_read);

/********
  Usage
********/
void usage(void)
{
	printf("Usage: AddCR <switches> files..\n");
	printf("where <switches> is of the following\n");
	printf("    -a  Convert file to AMIGA format [CR].\n");
	printf("    -b  Convert file to IBM format [LF][CR].\n");
	printf("    -q  Quiet processing of file.\n");
	printf("    -s  Save backup. (Rename original file to '*.bak')\n");
	printf("Default: -b\n");
	exit(0);
}

/***********************
  Check if file exists
***********************/
int exists(char *filename)
{
	BPTR lock;

	if ((lock=Lock(filename, MODE_OLDFILE))==NULL)
		return(FALSE);
	else {
		UnLock(lock);
		return(TRUE);
	}
}

/*******
  Main
*******/
int main(int argc, char *argv[])
{
	int  c, bufsize, mode, verbose, backup;
	int  bytes_read, total_read, total_write, newlength;
	int  infile, outfile;
	char *inbuffer, *outbuffer;
	char filename[256], bakname[256];

	/*******************************
	  Initialise default variables
	*******************************/
	backup      = FALSE;
	verbose     = TRUE;
	mode        = IBM;
	bufsize     = 65536;

	/******************
	  Parse arguments
	******************/
	if (*argv[1] == '?') usage();
	while ((--argc>0) && ((*++argv)[0] == '-')) {
		while (c = *++argv[0])
			switch (c) {
			case 'a':
				mode=AMIGA;
				break;
			case 'b':
				mode=IBM;
				break;
			case 'q':
				verbose=FALSE;
				break;
			case 's':
				backup=TRUE;
				break;
			default:
				printf("AddCR: Unrecognised switch '-%c'!\n\n",c);
				usage();
			}
	}
	if (argc==0) usage();

	/********************
	  Title and credits
	********************/
	if (verbose) {
		printf("AddCR v1.0 by Son Le\nMode: ");
		if (mode==IBM)
			printf("Convert to IBM\n");
		else
			printf("Convert to AMIGA\n");
	}

	/***************************
	  Allocating buffer memory
	***************************/
	while ((inbuffer=(char *)malloc(bufsize*3))==NULL) {
		bufsize /= 2;
		if (bufsize<4096) {
			printf("AddCR: Cannot allocate memory!\n");
			exit(RETURN_FAIL);
		}
	}

	/********************************************************************
	 In IBM mode, buffer memory is divided 1:2 (in/out)
	   - for worse case scenario of buffer full of CR (->LF+CR)
	   - would double (x2) it's size when converted.
	 In AMIGA mode, buffer memory is divide 1:1 (in/out)
	   - no worse case scenario (LF+CR -> CR)
	   - worse case of buffer full of LF+CR will halve, when converted.
	********************************************************************/
	if (mode==AMIGA) bufsize = (bufsize/2)*3;
	outbuffer = (char *)((int)inbuffer + bufsize);

	/********************
	  Process all files
	********************/
	argc++;
	*argv--;
	while ((--argc>0) && (*++argv)) {

		/***********************
		  Check if file exists
		***********************/
		if (!exists(*argv)) {
			printf("AddCR: Cannot find file '%s'!\n",*argv);
			exit(0);
		}

		/*******************
		  Extract filename
		*******************/
		stcgfn(filename,*argv);

		/******************
		  Open input file
		******************/
		if ((infile=open(*argv,O_RDONLY))==-1) {
			printf("AddCR: Error opening file '%s'!\n",*argv);
			exit(RETURN_FAIL);
		}

		/****************************************
		  Check if temporary output file exists
		****************************************/
		if (exists("AddCR.tmp") && (verbose)) {
			printf("AddCR: Temporary file 'AddCR.tmp' exists! Overwrite? (Y/n) ");
			rawcon(1);
			c=getchar();
			rawcon(0);
			putchar(c);
			putchar('\n');
			if ((c=='N') || (c=='n')) exit(0);
		}

		/*******************
		  Open output file
		*******************/
		if ((outfile=creat("AddCR.tmp",0))==-1) {
			printf("AddCR: Error opening temporary file 'AddCR.tmp'!\n");
			exit(RETURN_FAIL);
		}

		/************************
		  Read and process file
		************************/
		total_read = total_write = 0;
		bytes_read = bufsize;
		while (bytes_read==bufsize) {
			bytes_read = read(infile,inbuffer,bufsize);
			total_read += bytes_read;
			if (verbose) {
				printf("\x0dProcessing %s: %ld bytes",filename,total_read);
				fflush(stdout);
			}
			newlength=(mode==IBM)?amiga2ibm(inbuffer,outbuffer,bytes_read):
								  ibm2amiga(inbuffer,outbuffer,bytes_read);
			if (bytes_read==bufsize) {
				if (inbuffer[bufsize-1]==13) {
					lseek(infile,-1,1);
					newlength--;
					total_read--;
				}
			}
			write(outfile,outbuffer,newlength);
			total_write += newlength;
		}
		if (verbose)
			printf("\x0dProcessing %s: (%ld bytes) => %ld bytes\n",
					filename, total_read, total_write);

		/**********
		  Cleanup
		**********/
		close(infile);
		close(outfile);
		if (backup) {
			strcpy(bakname,*argv);
			strcat(bakname,".bak");
			if (Rename(*argv,bakname)==NULL) {
				printf("Cannot rename '%s' to '%s'!\n",*argv,bakname);
				exit(RETURN_FAIL);
			}
		} else {
			if (DeleteFile(*argv)==NULL) {
				printf("Cannot delete original file '%s'!\n",*argv);
				exit(RETURN_FAIL);
			}
		}
		if (Rename("AddCR.tmp",filename)==NULL)
			printf("Cannot rename 'AddCR.tmp' to '%s'!\n",filename);
	}
	if (verbose) printf("Done!\n");
	exit(0);
}
