#include <exec/types.h>            /* BOOL etc. Type-Definitions     */
#include <dos/dos.h>               /* Definition of RETURN_FAIL etc. */

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

/* Konstanten -------------------------------------------------------------------------- */

#define MISSING_FILENAME	1
#define SIZE_NOT_LEGAL		2
#define NUMBER_NOT_LEGAL	3
#define WRONG_PARAMETERS	4
#define MISSING_WILDCARD  5
#define FROM_NOT_LEGAL		6
#define FROM_TOO_LOW			7
/* --------------------- */
#define PARSE_ERROR       7
/* --------------------- */
#define FILE_EXISTS			 20
#define NO_MEMORY        21
#define MISSING_FILE		 22
#define CANNOT_OPEN_FILE 23

/* Funktions-Protos -------------------------------------------------------------------- */

void PrintError(int );
void WrongArgs(char *);
char * MakeFileName(int);
char * Uppercase(char *);
BOOL   fileexist(char *);


/* Globale Variablen ------------------------------------------------------------------- */

BOOL force = FALSE;
BOOL quiet = FALSE;
BOOL doublenull = FALSE;
int  from = 0;
int  number = 0;
int  size = 0;
char * filename = NULL;
char * basename = NULL;
const char * wildcard = "*";

/* main -------------------------------------------------------------------------------- */

int main(int ArgC, char * ArgV[])
{
	int    arg = 1;												/* Aktuelle Argumentnummer */
	int    filenr = 0;                    /* Aktuelle Nummer des bearbeiteten Files */
	int    zeichen;                       /* Zeichen-Transfer-Puffer */
	int    WCpos = 0;                     /* Dient zum finden des Wildcards */
	int    baselen = 0;                   /* Länge des Basenames */
	int    filesize = 0;                  /* Größe des Trennfiles */	
	int    lastsize = 0;                  /* Größe des letzten erzeugten Files */
	int    portion = 0;                   /* Größe der einzelnen Files */
	int    charno = 0;                    /* Nummer des kopierten Zeichens */
	BOOL   ready = FALSE;                 /* Schleifenabbruchs-Boolean */
	FILE * Outfp = NULL;                  /* Output-FilePointer */
	FILE * Infp  = NULL;                  /* Input-FilePointer */
	char * actualfilename = NULL;         /* Name des aktuellen Files */

	/* ------------------------ Parsing ------------------------- */
/*fs*/
	if(1 == ArgC)                        /* keine Parameter ist unzulässig */
	{
		PrintError(MISSING_FILENAME);
		WrongArgs(ArgV[0]);
	}
	/* FileName-Parameter */
	filename = ArgV[arg];
	arg++;
	/* FROM-Parameter */
	if(arg+2 <= ArgC && 0 == strcmp("FROM", Uppercase(ArgV[arg]) ))
	{
		if(!isdigit(ArgV[arg+1][0]) ) 
		{
			PrintError(FROM_NOT_LEGAL);
			WrongArgs(ArgV[0]);
		}
		from = atoi(ArgV[++arg]);
		if(0 > from)
		{
			PrintError(FROM_TOO_LOW);
			WrongArgs(ArgV[0]);
		}
		arg++;		
	}
	/* INTO-Parameter */
	if(arg+2 <= ArgC && 0 == strcmp("INTO", Uppercase(ArgV[arg]) ))
	{
		basename = ArgV[++arg];
		baselen = strlen(basename);
		/* WildCard finden, Stelle in WCpos */
		for(WCpos = 0; WCpos <=baselen; WCpos++)
		{
			if(wildcard[0] == basename[WCpos]) break;
		}
		if(WCpos > baselen)
		{
			PrintError(MISSING_WILDCARD);
			WrongArgs(ArgV[0]);
		}
		arg++;
	}
	/* SIZE-Parameter */
	if(arg+2 <= ArgC && 0 == strcmp("SIZE", Uppercase(ArgV[arg]) ))
	{
		if(!isdigit(ArgV[arg+1][0]) )
		{
			PrintError(SIZE_NOT_LEGAL);
			WrongArgs(ArgV[0]);
		}
		size = atoi(ArgV[++arg]);
		if(0 >= size)
		{
			PrintError(SIZE_NOT_LEGAL);
			WrongArgs(ArgV[0]);
		}
		arg++;
	} 
	
	/* PARTS-Parameter */
	if(arg+2 <= ArgC && 0 == strcmp("PARTS", Uppercase(ArgV[arg]) ))
	{
		if(!isdigit(ArgV[arg+1][0]) )
		{
			PrintError(NUMBER_NOT_LEGAL);
			WrongArgs(ArgV[0]);
		}
		number = atoi(ArgV[++arg]);
		if(0 >= number)
		{
			PrintError(NUMBER_NOT_LEGAL);
			WrongArgs(ArgV[0]);
		}
		arg++;
	} 
	while(!ready && arg+1 <= ArgC)          /* Abfrage der Booleans */
	{
		/* NULL-Parameter */
		if(arg+1 <= ArgC && 0 == strcmp("NULL", Uppercase(ArgV[arg]) ))
		{
			doublenull = TRUE;
			arg++;
		}
		/* QUIET-Parameter */
		else if(arg+1 <= ArgC && 0 == strcmp("QUIET", Uppercase(ArgV[arg]) ))
		{
			quiet = TRUE;
			arg++;
		}
		/* FORCE-Parameter */
		else if(arg+1 <= ArgC && 0 == strcmp("FORCE", Uppercase(ArgV[arg]) ))
		{
			force = TRUE;
			arg++;
		}
		/* Müll-Parameter führt zum Ende */
		else 
		{
			PrintError(WRONG_PARAMETERS);
			ready = TRUE;
		}
	}
	if(arg != ArgC) WrongArgs(ArgV[0]);                   /* mind. ein  Parameter ungültig */
  if(0 == size && 0 == number) number = 2;
  if(NULL == basename)
  {
  	basename = (char *) malloc(strlen(filename)+2);
  	sprintf(basename, "%s*",filename);
  }
/* --------------------------------------------------------------------------------------- */
/*fe*/


	if(!quiet) printf("\n  MSplit V1.1 by Harald Löffler\n\n");

	if(!fileexist(filename))
	{
		if(!quiet) PrintError(MISSING_FILE);
		exit(RETURN_WARN);
	}

/* Größe des zu trennenden Files feststellen */
	Infp = fopen(filename, "r");
  if(!Infp)
  {
  	PrintError(CANNOT_OPEN_FILE);
  	exit(RETURN_ERROR);
  }
	filesize = 0;
	while(EOF != (zeichen = getc(Infp)))
	{
		filesize++;
	}
	fclose(Infp);
/* ----------------------------------------- */

	if(size != 0 && number == 0)
	{
		number = filesize/size;
		if(0 != filesize % size)
		{
			number++;
			lastsize = filesize - (number - 1) * size;
		}
		else {lastsize = size;}
	}
	else if(size == 0 && number != 0)
	{
		size = filesize/number;
		if(0 != (filesize % number))
		{
			lastsize = size + filesize - number * size;
			if(lastsize>size && 0 != filesize - (number - 1) * (size + 1))
			{
				size++;
				lastsize = filesize - (number - 1) * size;
			}
		}
		else {lastsize = size;}
	}
	else if(size != 0 && number != 0)
	{
		if(filesize < number * size)
		{
			number = filesize/size;
			if(0 != filesize % size)
			{
				number++;
				lastsize = filesize - (number-1) * size;
			}
			else {lastsize = size;}			
		}
		else
		{
			lastsize = filesize  - (number - 1) * size;
		}
	}

	Infp = fopen(filename, "r");
	if(!Infp)
	{
		PrintError(CANNOT_OPEN_FILE);
		exit(RETURN_ERROR);
	}

	filenr = from;
	do
	{
		actualfilename = MakeFileName(filenr);
		printf("Part %i -> %s | ", filenr, actualfilename);

		if(filenr == number-1+from)
		{
			portion = lastsize;
		}
		else
		{
			portion = size;
		}

/* Splitting in ein neues File mit maximal portion Bytes */
		if(fileexist(actualfilename) && !force)
		{
			if(!quiet) PrintError(FILE_EXISTS);
			exit(RETURN_WARN);
		}
		Outfp = fopen(actualfilename, "w");
		charno = 0;
		while(portion != charno++)
		{
			if(EOF == (zeichen = getc(Infp))) break;
			putc(zeichen, Outfp);
		}
		fclose(Outfp);
		free(actualfilename);
/* ---------------------------------------------------- */

    printf("%i Bytes\n", charno-1);

		filenr++;
		if(filenr == number+from) ready = TRUE;
	}
	while(!ready);
	
	printf("\n");
	free(basename);

	return(RETURN_OK);
}



/* Funktionen -------------------------------------------------------------------------- */

char * MakeFileName(int number)
/*fs*/
{
	char * str;
  char * frontpart;
  char * rearpart;
  int    WCpos = 0;
	int    nrlen = 1;
	int    baselen = 0;
	int    dummy = 0;
	int    step = 0;

	dummy = number;
	while(dummy > 9)
	{
		dummy /=10;
		nrlen++;
	}

	baselen = strlen(basename);

	/* WildCard finden, Stelle in WCpos */
	for(WCpos = 0; WCpos <=baselen; WCpos++)
	{
		if(wildcard[0] == basename[WCpos]) break;
	}

	frontpart = (char *) malloc(WCpos + 1);
	if(NULL == frontpart)
	{
	  printf("\n  MJoin V1.1 by Harald Löffler\n\n");
		PrintError(NO_MEMORY);
		exit(RETURN_FAIL);
	}

	rearpart = (char *) malloc(baselen - WCpos);
	if(NULL == rearpart)
	{
	  printf("\n  MJoin V1.1 by Harald Löffler\n\n");
		PrintError(NO_MEMORY);
		exit(RETURN_FAIL);
	}

	if(doublenull && number < 10) nrlen++;

	str = (char *)malloc(baselen + nrlen + 1);
	if(NULL == str)
	{
	  printf("\n  MJoin V1.1 by Harald Löffler\n\n");
		PrintError(NO_MEMORY);
		exit(RETURN_FAIL);
	}

	/* frontpart kopieren */
	for(step = 0; step < WCpos; step++)
	{
		frontpart[step] = basename[step];
	}
  frontpart[WCpos] = NULL;
	
	/* rearpart kopieren */
	for(step = WCpos+1; step < baselen; step++)
	{
		rearpart[step-WCpos-1] = basename[step];
	}
  rearpart[baselen-WCpos-1] = NULL;	

	if(doublenull && number < 10)
	{
		sprintf(str, "%s0%i%s", frontpart, number, rearpart);
	}
	else
	{
		sprintf(str, "%s%i%s", frontpart, number, rearpart);
	}
  free(rearpart);
  free(frontpart);
	return(str);
}
/*fe*/

BOOL fileexist(char * file)
/*fs*/
{
	FILE * fp = NULL;
	BOOL   ret = FALSE;

	fp = fopen(file,"r");

	if(NULL == fp)
	{
		ret = FALSE;
	}
	else
	{
		ret = TRUE;
	}

	if(fp) fclose(fp);
	return(ret);
}
/*fe*/

char * Uppercase(char * str)
/*fs*/
{
	int i = -1;
	while(str[++i] != NULL) str[i] = toupper(str[i]);
	return(str);
}
/*fe*/

void WrongArgs(char * progname)
/*fs*/
{
	printf("\nUSAGE: %s <filename> [FROM start] [INTO <basename>] [SIZE s] [PARTS n]\n\t\t\t [NULL|QUIET|FORCE]\n\n", progname);
	exit(RETURN_WARN);
}
/*fe*/

void PrintError(int error)
/*fs*/
{
	if(error <= PARSE_ERROR && !quiet)
	  printf("\n  MSplit V1.1 by Harald Löffler\n");
	if(!(error > PARSE_ERROR && quiet))
	{
		switch(error)
		{
			case MISSING_FILENAME:
				printf("\n  I need at least a basename!\n");
				break;
			case SIZE_NOT_LEGAL:
				printf("\n  SIZE-Value is not a legal number.\n");			
				break;
			case NUMBER_NOT_LEGAL:
				printf("\n  NUMBER-Value is not a legal number.\n");
				break;
			case WRONG_PARAMETERS:
				printf("\n  One or more wrong Parameter(s)!\n");
				break;
			case MISSING_WILDCARD:
				printf("\n  Where is the wildcard? :-|\n");
				break;
			case FROM_NOT_LEGAL:
				printf("\n  FROM-Value is not a legal number.\n");			
				break;
			case FROM_TOO_LOW:
				printf("\n  FROM-Value must be greater then zero.\n");
				break;
/* ----------------------------------- PARSE-Errors end ----------------------------------- */
			case MISSING_FILE:
				printf("  Your file does not exist :-o\n\n");
				break;
			case FILE_EXISTS:
				printf("  This Basename allready exists. Use FORCE to overwrite.\n\n");
				break;
			case CANNOT_OPEN_FILE:
				printf("  Can´t open file.\n\n");
				break;
			case NO_MEMORY:
			  printf("  Cannot allocate new memory. Abort.\n\n");
			  break;
		}
	}
}
/*fe*/
