/*
 * MultiCV v1.01 - Copyright (C) 1995 by Giuseppe Ghibo'
 *
 * Converts ASCII files from/to the systems Amiga, Macintosh and DOS.
 *
 * Written by Giuseppe Ghibo' <ghibo@galileo.polito.it>
 *
 * Version 1.01 - 7 Jun 1995
 *
 */

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

#ifndef min
#define min(a,b) (a < b ? a : b)
#endif

enum {DOS2AMI, AMI2DOS, DOS2MAC, MAC2DOS, AMI2MAC, MAC2AMI, NOPT};

struct convopt {
	int val;
	char *opt;
	char *desc;
};

struct convopt convopt[NOPT] = {
	{ DOS2AMI, "dos2ami", "Convert DOS file to AMIGA file" },
	{ AMI2DOS, "ami2dos", "Convert AMIGA file to DOS file" },
	{ DOS2MAC, "dos2mac", "Convert DOS file to MACINTOSH file" },
	{ MAC2DOS, "mac2dos", "Convert MACINTOSH file to DOS file" },
	{ AMI2MAC, "ami2mac", "Convert AMIGA file to MACINTOSH file" },
	{ MAC2AMI, "mac2ami", "Convert MACINTOSH file to AMIGA file" }
};

struct mybuf
{
	int n;
	unsigned char *buf;
};

static unsigned char charset[NOPT][256]= {
{ /* dos2ami */
   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127,199,252,233,226,228,224,229,231,234,235,232,
   239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,
   162,163,165, 80,102,225,237,243,250,241,209,170,186,191, 45,172,
   189,188,161,171,187, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 97,223, 71,182, 83,115,181,116,248, 81, 32,
   240, 32,248, 69, 32, 61,177, 62, 60, 32, 32,247, 61,176,183,183,
    86,110,178, 32,160 },
{ /* ami2dos */
   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,
   139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,
   155,156,157,158,159,32 ,173,155,156,164,157,166,167,168,169,166,
   174,170,173,174,175,248,241,253,179,180,230,227,249,184,185,167,
   175,172,171,190,168,192,193,194,195,142,143,146,128,200,144,202,
   203,204,205,206,207,208,165,210,211,212,213,153,215,216,217,218,
   219,154,221,222,225,133,160,131,227,132,134,145,135,138,130,136,
   137,141,161,140,139,240,164,149,162,147,245,148,246,248,151,163,
   150,129,253,254,152},
{ /* dos2mac */
   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127,130,159,142,137,138,136,140,141,144,145,143,
   149,148,147,128,129,131,207,206,153,154,152,158,157,216,133,134,
   162,163,180, 80,196,135,146,151,156,150,132,187,188,192, 45,194,
    32, 32,193,199,200, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 97,167, 71,185,183,115,181,116, 70, 81,189,
   182,176,197, 69, 32,217,177,179,178, 32, 32,214,197,161,165,165,
   195,110, 50,165,202},
{ /* mac2dos */
   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127,142,143,128,144,165,153,154,160,133,131,132,
   131,134,135,130,138,136,137,161,141,140,139,164,162,149,147,148,
   147,163,151,150,129, 43,248,155,156, 21,249, 20,225, 82, 67, 32,
    39, 34, 61,146,232,236,241,243,242,157,230,235,228,185,185, 83,
   166,167,234,145,237,168,173,194,251,159,237, 30,174,175, 95,255,
    65, 65, 79, 32, 32, 45,196, 34, 34, 96, 39,246, 32,152,240,179,
    32, 60, 62, 32, 32, 32,250, 44, 32, 37, 65, 69, 65, 69, 69, 73,
    73, 73, 73, 79, 79, 32, 79, 85, 85, 85, 49, 94, 94, 45, 32, 32,
   248, 32, 34, 32, 32},
{ /* ami2mac */
   0,1,2,3,4,5,6,7,8,9,13,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
    32, 32, 32, 32, 32,202,193,162,163,215,180,124,164,172,169,187,
   199,194, 45,168,208,161,177, 50, 51,171,181,166,165, 44, 49,188,
   200, 32, 32, 32,192,203,203,204,204,128,129,174,130,131,131, 69,
    69, 73, 73, 73, 73, 68,132,152,151,153,155,133,120,175,157,156,
   158,159, 89, 80,167,136,135,137,139,138,140,190,141,143,142,144,
   145,147,146,148,149,182,150,152,151,153,155,154,214,191,157,156,
   158,159,121,112,216},
{ /* mac2ami */
   0,1,2,3,4,5,6,7,8,9,10,11,12,10,14,15,16,17,18,19,20,21,22,23,24,
   25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,
   46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,
   67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,
   88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,
   107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,
   123,124,125,126,127,196,197,199,201,209,214,220,225,224,226,228,
   227,229,231,233,232,234,235,237,236,238,239,241,243,242,244,246,
   245,250,249,251,252, 43,176,162,163,167,183,182,223,174,169,174,
   180,168, 61,198,216, 32,177, 60, 62,165,181,240, 83,182,182, 83,
   170,186, 32,230,248,191,161,172, 86,102,248, 32,171,187, 95,160,
   192,195,213,198,230, 45, 45, 34, 34, 96, 39,247, 32,255, 61,166,
   164, 60, 62, 32, 32, 32,183,184, 32, 37,194,202,193,203,200,205,
   206,207,204,211,212, 32,210,218,219,217,185, 94, 94,175, 32, 32,
   176, 32, 32, 32, 32}
};

#define LF '\012'
#define CR '\015'

#ifdef MSDOS
#define DIMBUF 16000
#define OPTCHAR '/'
#define READBIN "rb"
#define WRITEBIN "wb"
#else
#define DIMBUF 60000
#define OPTCHAR '-'
#define READBIN "r"
#define WRITEBIN "w"
#endif

#define DOUBDIMBUF	2*DIMBUF
#define FNAMEIN		argv[2]
#define FNAMEOUT	argv[3]

char tmpbuf[1024];

void usage_exit(void);
struct mybuf *convert(struct mybuf *inbuf, int opt);


void main(int argc, char **argv)
{
	FILE *fhin, *fhout;
	struct mybuf inbuf, *outbuf;
	int i, opt;

	fprintf(stderr,"MultiCV v1.01 - (C) 1995 by Giuseppe Ghibo'\n\n");

	if (argc == 1)
		usage_exit();

	if (argc > 4)
	{
		fprintf (stderr,"Bad arguments!\n\n");
		usage_exit();
	}

	for (i = 0; i < NOPT; i++)
	{
		if (stricmp(&argv[1][1],convopt[i].opt) == NULL)
		{
			opt = i;
			break;
		}
	}

	if (i >= NOPT)
	{
		fprintf(stderr,"Bad arguments: `%s'\n\n", argv[1]);
		usage_exit();
	}

	if (argc == 2 || argc == 3)
	{
		fhin = stdin;
		fhout = stdout;
	}

	if (argc == 4)
	{
		if ((fhin = fopen(FNAMEIN, READBIN)) == NULL)
		{
			sprintf(tmpbuf, "multicv: error: Can't open input file '%s'", FNAMEIN);
			perror(tmpbuf);
			exit(1);
		}

		if ((fhout = fopen(FNAMEOUT, WRITEBIN)) == NULL)
		{
			sprintf(tmpbuf, "multicv: error: Can't open output file '%s'", FNAMEOUT);
			perror(tmpbuf);
			exit(1);
		}
	}

	if ((inbuf.buf = malloc(DIMBUF)) == NULL)
	{
		fprintf(stderr, "multicv: error: Can't alloc %u bytes of memory\n", DIMBUF);
		exit(1);
	}
	
	while ((inbuf.n = fread(inbuf.buf, 1, DIMBUF, fhin)) > 0)
	{

		outbuf = convert(&inbuf, opt);

		fwrite(outbuf->buf, 1, outbuf->n, fhout);

		if (outbuf != &inbuf)
		{
			free(outbuf -> buf);
			free(outbuf);
		}
	}

	if (inbuf.buf)
		free(inbuf.buf);

	if (fhin != stdin)
		fclose(fhin);

	if (fhout != stdout)
		fclose(fhout);

}

void usage_exit(void)
{
	int i;

	fprintf(stderr, "Usage:\tmulticv %c<opt> <filein> <fileout>\n", OPTCHAR);
	fprintf(stderr, "Where <opt> is one of:\n");

	for (i = 0; i < NOPT; i++)
		fprintf(stderr,"\t%s - %s\n",convopt[i].opt, convopt[i].desc);
		
	exit(0);
}

struct mybuf *convert(struct mybuf *inbuf, int opt)
{
	struct mybuf *outbuf;
	register unsigned char *p, *q, *r;

	if ((opt == AMI2DOS) || (opt == MAC2DOS))
	{
		if ((outbuf = malloc(sizeof(struct mybuf))) == NULL)
		{
			fprintf(stderr, "multicv: error: Can't alloc %u bytes of memory!\n", sizeof(struct mybuf));
			exit(1);
		}

		if ((outbuf->buf = malloc(DOUBDIMBUF)) == NULL)
		{
			fprintf(stderr, "multicv: error: Can't alloc %u bytes of memory!\n", DOUBDIMBUF);
			exit(1);
		}
	}  
	else
		outbuf = inbuf;

	switch(opt)
	{
		case AMI2MAC: case MAC2AMI:

			q = inbuf->buf + inbuf->n;

			for (p = inbuf->buf; p < q; p++)
				*p = charset[opt][*p];

			break;

		case DOS2AMI:

			q = inbuf->buf + inbuf->n;

			for (p = r = inbuf->buf; p < q; p++, r++)
			{
				if (*p == CR)
				{
					*r = LF;
					p++;	/* skip next LF */
				}
				else
					*r = charset[opt][*p];
			}
			outbuf->n = r - outbuf->buf;

			break;

		case DOS2MAC:

			q = inbuf->buf + inbuf->n;

			for (p = r = inbuf->buf; p < q; p++, r++)
			{
				if (*p == CR)
				{
					*r = CR;
					p++;	/* skip next LF */
				}
				else
					*r = charset[opt][*p];
			}
			outbuf->n = r - outbuf->buf;

			break;

		case AMI2DOS:

			q = inbuf->buf + inbuf->n;

			for (p = inbuf->buf, r = outbuf->buf; p < q; p++, r++)
			{
				if (*p == LF)
					*r++ = CR;

				*r = charset[opt][*p];
			}

			outbuf->n = r - outbuf->buf;

			break;

		case MAC2DOS:

			q = inbuf->buf + inbuf->n;

			for (p = inbuf->buf, r = outbuf->buf; p < q; p++, r++)
			{
				if (*p == CR)
				{
					*r++ = CR;
					*r = LF;
				}
				else
					*r = charset[opt][*p];
			}

			outbuf->n = r - outbuf->buf;

			break;

		default:

			break;

	}
	
	return(outbuf);
}
