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

/*  REM  #define DEBUG 0   *** Uses new the Proprocessor Symbol *** */

#define LINE_LENGHT 32000			/* Maximum line lenght from file to convert */
#define MAX_LL 80							/* Maximum size for breaking line */
#define MAX_CONV_LINE	80      /* Maximum size of conversion data line */

int lower = 0;
int upper = 0;
int noconv = 0;
int breakline = 0;
int quiet = 0;

FILE *convfile,*input_file,*output_file;

char *line,*input_line,*output,*output_line;
	
char carr[2] = {'\n','\0'};

char first[80][80],second[80][80];   /* these variables are globals */

char chr[256] = {'\0',' ',' ',' ',' ',' ',' ','\a','\b','\t','\n','\v','\f','\r'
		 ,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','\x1b',' ',' ',' ',' '
		 ,'\x20','!','\"','#','$','%','&','\'','(',')','*','+',',','-','.','/'
		 ,'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?'
		 ,'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'
		 ,'Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_','`'
		 ,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'
		 ,'q','r','s','t','u','v','w','x','y','z','{','|','}','~'};


void	mid();
void	egale();
void	compare();
void	change();
int	goget();
void reservation();
void libere();

void main(argc,argv)
int argc;
char *argv[];

{
	int conversion,line_numb,cn,x,count,fileind,ar;
	char *c,*newconv,temp[MAX_LL];

	ar = 0;
	cn = 0;
	line_numb = 0;
	conversion = 0;
	x = 0;
	count = 0;
	fileind = 0;

	printf("\f");
	printf("\x1b[33mConvert It!\x1b[0m V 1.0. \xa9 1990 by Rejean Gravel.\n");

	if (argc<2) {
		x=-1;
		argv[0][0] = '-';
		argv[0][1] = 'h';
		argv[0][2] = '\0';
		}
	else {
		for(ar=1;ar < argc;++ar) {
			if (*argv[ar] != '-' && *argv[ar] != '/')	
				fileind = 1;
			}
		}

	if (!fileind) {
		printf("\x1b[1musage\x1b[0m: 'conv [-\x1b[33mu\x1b[0m] [-\x1b[33ml\x1b[0m] [-\x1b[33mb\x1b[0m] [-\x1b[33mq\x1b[0m] [-\x1b[33mn\x1b[0m] [-\x1b[33mc\x1b[0mCONVFILE] \x1b[33mfilename\x1b[0m ...'\n");
		if(argc == 2 && (argv[1][1] != 'h' && argv[1][1] != '?')) {
			printf("       Need a \x1b[33mfilename\x1b[0m to convert.\n\n");
			exit(0);
			}
		}

	while ((*argv[++x] == '-') || (*argv[x] == '/')) {
		c=argv[x]+1;
		switch(*c) {
			case 'c':
				if(conversion) {
					printf("-- \x1b[1mERROR\x1b[0m -- Only one \x1b[33mconversion\x1b[0m file allowed!\n\n");
					exit(0);
					}
				conversion = 1;
				newconv = argv[x]+2;
				--argc;
				++cn;
				break;
			case 'u':
				if(upper) {
					printf("-- \x1b[1mERROR\x1b[0m --  -\x1b[33mu\x1b[0m (upper) defined more than once!\n\n");
					exit(0);
					}
				if (lower) {
					printf("-- \x1b[1mERROR\x1b[0m -- Only one { [-\x1b[33mu\x1b[0m] \x1b[33;4mXOR\x1b[0m [-\x1b[33ml\x1b[0m] } can be used at a time.\n\n");
					exit(0);
					}
				upper = 1;
				--argc;
				++cn;
				break;
			case 'l':
				if(lower) {
					printf("-- \x1b[1mERROR\x1b[0m --  -\x1b[33ml\x1b[0m (lower) defined more than once!\n\n");
					exit(0);
					}
				if(upper) {
					printf("-- \x1b[1mERROR\x1b[0m -- Only one { [-\x1b[33mu\x1b[0m] \x1b[33;4mXOR\x1b[0m [-\x1b[33ml\x1b[0m] } can be used at a time.\n\n");
					exit(0);
					}
				lower = 1;
				--argc;
				++cn;
				break;
			case 'b':
				if(breakline) {
					printf("-- \x1b[1mERROR\x1b[0m --  -\x1b[33mb\x1b[0m (line break on) defined more than once!\n\n");
					exit(0);
					}
				breakline = 1;
				--argc;
				++cn;
				break;
			case 'n':
				if(noconv) {
					printf("-- \x1b[1mERROR\x1b[0m --  -\x1b[33mn\x1b[0m (no conversion) defined more than once!\n\n");
					exit(0);
					}
				noconv = 1;
				--argc;
				++cn;
				break;
			case 'q':
				if(quiet) {
					printf("-- \x1b[1mERROR\x1b[0m --  -\x1b[33mq\x1b[0m (quiet mode) defined more than once!\n\n");
					exit(0);
					}
				quiet = 1;
				--argc;
				++cn;
				break;
			case 'h':
			case '?':
			  printf("        -\x1b[33mu\x1b[0m  Convert to \x1b[33mupper case\x1b[0m.\n");
				printf("        -\x1b[33ml\x1b[0m  Convert to \x1b[33mlower case\x1b[0m.\n");	
				printf("        -\x1b[33mb\x1b[0m  Convert to \x1b[33m80 chars per lines\x1b[0m where possible.\n");
				printf("        -\x1b[33mq\x1b[0m  Activate \x1b[33mQuiet mode\x1b[0m on.\n");
				printf("        -\x1b[33mn\x1b[0m  Does not use any \x1b[33mconvfile\x1b[0m.\n");
				printf("        -\x1b[33mc\x1b[0;1mconvfile\x1b[0m Use your own \x1b[33mconversion\x1b[0m file.\n");
				printf("            Default = s:\x1b[33mDefault.cnv\x1b[0m.\n\n");

				exit(0);
				break;
			default:
				printf("conv: -\x1b[33m%c\x1b[0m not supported.\n\n",*c);
				exit(0);
				break;
			}
		}

	if (conversion != 1)
		newconv = "S:Default.cnv";

	/* print relevant information */
	printf("Conversion file used \x1b[33m%s\x1b[0m.\n",newconv);
	if (upper)
		printf("\x1b[33mUpper Case\x1b[0m mode enabled.\n");
	if (lower)
		printf("\x1b[33mLower Case\x1b[0m mode enabled.\n");
	if (breakline)
		printf("\x1b[33m%d Break Lines\x1b[0m mode enabled.\n",MAX_LL);
	if (quiet)
		printf("\x1b[33mQuiet\x1b[0m mode enabled.\n",MAX_LL);
	if(noconv)
		printf("\x1b[33mNo Conversion\x1b[0m mode enabled.\n");


	/* ----------------------------------------------------------- */
	 /* start here the functions to open, read and write to files */
  /* ------------------------------------------------------------*/

	reservation();

	if((convfile = fopen(newconv,"r")) == NULL) {
		printf("Cannot open conversion file \x1b[33m%s\x1b[0m.\n\n",newconv);
		libere(1);
		exit(0);
		}

	while (fgets(line,LINE_LENGHT,convfile) != NULL) {		/* Get each line of Conversion DATA */

#if DEBUG
		printf("%s is the line read!\n",line);   /* test */
#endif


		mid(line,atoi(line),line_numb++); /* get the number... */
																			/* and separates the */
																			/* line into its     */
																			/* separate components */

		}

	fclose(convfile);

	/* *** the following sorts the conversion datas  *** */

	count = 1;
	while (count) {
		count = 0;
		for (x=0;x < line_numb-1;x++)
			if(strlen(first[x]) < strlen(first[x+1])) {
				strcpy(temp,first[x]);
				strcpy(first[x],first[x+1]);
				strcpy(first[x+1],temp);
				strcpy(temp,second[x]);
				strcpy(second[x],second[x+1]);
				strcpy(second[x+1],temp);
				count = 1;
				}
		}

#if DEBUG
	for (x=0;x < line_numb;x++)
		printf("There are the sorted conversion words !! %s  %s\n",first[x],second[x]);
#endif


	/* the following opens the data files  */

	while (--argc) {

		if((input_file = fopen(argv[++cn],"r")) == NULL) {
			printf("Cannot open data file \x1b[33m%s\x1b[0m.\n\n",argv[cn]);
			libere(1);
			exit(0);
			}
		else
			change(output,argv[cn]);


		if((output_file = fopen(output,"wt")) == NULL) {
			printf(" -- ERROR -- Opening the file named \x1b[33m%s\x1b[0m.\n\n",output);
			libere(1);
			exit(0);
			}


	/* The following part reads, compare, transform...
	   then converts to UPPER or lower and then print the result in
           the output_file.					*/

		printf("\nConverting \x1b[33m%s\x1b[0m ",argv[cn]);

		while (fgets(input_line,LINE_LENGHT,input_file) != NULL) {

#if DEBUG
			printf("%s\n",input_line);
#endif

			compare(output_line,input_line,line_numb);		/* Does the conversion..*/
			fprintf(output_file,"%s",output_line);				/* then prints the new line.*/

			}

		 fclose(input_file);
		 fclose(output_file);
		
		 printf("\nConversion saved under \x1b[33m%s\x1b[0m.\n\n",output);

	}

#if (!DEBUG)
	printf("\x1b[33mEnd of Conversion.\x1b[0m\n\n");
#endif

	libere(0);

}




void mid(a,b,c)
char *a;  					/* a points to the conversion data line just read!! */
int b,c; 					  /* b = number of letters to read: c = # of line read! */
{
	int x;
	x = 0;

	if(b>0 && b<10)   /* if the conv # [of char] is lower then 10 */
		++a;
	else
		a += 2;					/* get the pointer 'over' the number        */

	for(x=0 ; b-x ; x++)
		switch (*++a) {   /* ++ is for jumping over the ':' */
			/* If the characters is '\'   */
			case '\\':
			 	/* if '\' (one of them only!) and next character is a digit  */
				if((*(a+1) != '\\') && (isdigit(*(a+1)) != 0)) {
					/* then Jump over the three newly converted digit! */
					first[c][x] = chr[goget(a+1)];
					a += 3;
					}
				else {
					++a;							/* Else if there is 2 '\' or '\\' then take it as is.. */
					first[c][x] = *a;	/* even is there is only one '\' but followed with a letter ! */
					}
				break;
			default:
				first[c][x] = *a;							/* If '\' is NOT encountered! */
				break;
		}

	first[c][x] = '\0';   							/* puts a 'end of string' in string */

	x = -1;

	while (*++a != '\n') {
		x++;
		switch (*a) {
			case '\\':
				if ((*(a+1) != '\\') && (isdigit(*(a+1)) != 0)) {
					second[c][x] = chr[goget(a+1)];
					a += 3;
					}                           /* Same Description as Above */
				else {												/* Except that this involves */
					++a;												/* the SECOND word!          */
					second[c][x] = *a;
					}
				break;
			default:
				second[c][x] = *a;
				break;
			}
		}

	second[c][x+1] = '\0';   /* puts a 'end of string' in string */

#if DEBUG
	printf("This is first variable = %s\n\n",first[c]);
	printf("This is second variable = %s\n\n",second[c]);
#endif

	return;

}




void change(s,a)
char *s,*a;
{
	int x;
	x = 0;

	/* while (a[x] != '.' && a[x] != '\0') { */
	while (a[x] != '\0') {
		*(s+x)=*(a+x);
		x++;
		}

	s[x++] = '.';  	/* puts the '.' for the new extension ! */
	s[x++] = 'c';		/* then the first 'o'			*/
	s[x++] = 'v';		/* then the second 'o'			*/
	s[x++] = 'o';		/* and the final 'o' to complete the extension. */
	s[x] = '\0';		/* last but not least, the '\0' to terminate the string	*/

#if DEBUG
	printf("This is S   %s\n\n",s);
#endif

	return;

}




void compare(c,a,b)
char *c,*a;       /* *c= output_line,  *a = input_line  b=line# */
int b;
{
	int xx,y,conv,z,ln2;
	long int x;
	char *p[MAX_LL],*first_part,*second_part,*temp;

	conv = 1;

	if(noconv)   /* This variable determines if we do conversion or not! */
		conv = 0;  /* The process (with no conv) could have been shorterned */

	temp = c;
	if((first_part = (char *) malloc(LINE_LENGHT * sizeof(char))) == NULL) {
		printf("\n\n-- \x1b[33;1mOut of Memory Error\x1b[0m -- Cannot allocate %d bytes of memory.\n",LINE_LENGHT);
		libere(1);
		exit(0);
		}

	temp[0] = '\0';            /* This is done so that we can STRCAT to temp */
	second_part = a;           /* this is done so that if no conversion */
														/* occurs, the right data will be returned!! */
	while (conv) {

		conv = 0;
		y = 0;
		xx = 0;

		for (x=0;x < b;x++)
			if ((p[x] = strstr(a,first[x])) != NULL) {
				conv = 1;
				if (y < strlen(p[x])) {
					y = strlen(p[x]);
					xx = x;
					}
				}

			for (x=0;x<b;x++)
				if ((strlen(p[x]) == y) && (x != xx))
					if(strlen(first[x]) > strlen(first[xx]))
						xx = x;


		if (conv) {
			if (!quiet)
				printf(".");  
			egale(first_part,a);
			z = strlen(first_part) - strlen(p[xx]);
			*(first_part + z) = '\0';
			second_part = p[xx] + strlen(first[xx]);
			strcat(first_part,second[xx]);
			strcat(temp,first_part);
			a = second_part;
			}
		}

		strcat(temp,second_part);
		free ((char *)first_part);

	/* put here the checkout for string too long e.a. +MAX_LL chars */
	if (breakline) {
		while ((x = strcspn(temp,carr)) > MAX_LL) {
			ln2=strcspn(temp,carr)-(strcspn(temp,carr)%MAX_LL);

			while (((x > ln2) || (*(temp+x) != ' ')) && (x > 0)) {

#if DEBUG
	printf("x = strcspn(temp,carr) = %d.\n",x);
	printf("ln2 = strcspn(temp,carr)-(strcspn(temp,carr)%MAX_LL) = %d.\n",ln2);
	printf("MAX_LL = %d.\n",MAX_LL);
#endif

				--x;	/* This assumes that you are using text based files */
				}

			if(x > 0) 
				*(temp+x) = '\n';		/* Put a Carriage Return instead of Space. */
		}
	}

	/*  now that we have the final string, let's convert it to UPPER */
	/*  before returning from the procedure!! and Upper!             */

	if (upper)
		strupr(temp);

	if (lower)
		strlwr(temp);

	return;

}



void egale(first,a)
char *first;
char *a;
{
	int x;

	for (x=0;x<strlen(a);x++)
		*(first+x) = *(a+x);

	*(first+x) = '\0';

	return;
}




int goget(a)
char *a;
{
	char b[3];
	int x;

	for (x=0;x<3;x++)
		b[x] = *(a+x);

	b[x] = '\0';

	return atoi(b);
}


void reservation()
{

	if ((line = (char *) malloc(MAX_CONV_LINE*sizeof(char))) == NULL) {
		printf("-- \x1b[33;1mOut of Memory Error\x1b[0m -- Cannot allocate %d bytes of memory.\n",MAX_CONV_LINE);
		exit(0);
		}
	if ((input_line = (char *) malloc(LINE_LENGHT*sizeof(char))) == NULL) {	
		printf("-- \x1b[33;1mOut of Memory Error\x1b[0m -- Cannot allocate %d bytes of memory.\n",LINE_LENGHT);
		libere(0);
		exit(0);
		}
  if ((output = (char *) malloc(MAX_CONV_LINE*sizeof(char))) == NULL) {
		printf("-- \x1b[33;1mOut of Memory Error\x1b[0m -- Cannot allocate %d bytes of memory.\n",MAX_CONV_LINE);
		libere(0);
		exit(0);
		}
	if ((output_line = (char *) malloc(LINE_LENGHT*sizeof(char))) == NULL) {
		printf("-- \x1b[33;1m Out of Memory Error\x1b[0m -- Cannot allocate %d bytes of memory.\n",LINE_LENGHT);
		libere(0);
		exit(0);
		}

	return;

}


void libere(int filiere)
{
	if (line)
		free(line);
	if (input_line)
		free(input_line);
	if (output)
		free(output);
	if (output_line)
		free(output_line);

	if (filiere) {
		if (output_file)
			fclose(output_file);
		if (input_file)
			fclose(input_file);
		if (convfile)
			fclose(convfile);
		}

	return;
}
