/* ------------------------------------------------------------------
                        MML compiler [M2]
               programmed by S.Yamamoto (SHINNOSUKE)
                    m2main.c   --  main function
------------------------------------------------------------------ */
/*
 *  (c) 1994-1995 S.Yamamoto
 *
 *  1994,07/01 [M] Ver 1.0
 *  1994,10/02 Version 1.0
 *  1994,12/13 Version 2.0
 *  1995,02/10 Version 2.1
 *  1995,02/19 Version 2.2
 *  1995,03/11 Version 2.3
 *  1995,03/17 Version 2.4
 *  1995,03/25 Version 2.5
 *  1995,06/09 Version 2.6
 *  1995,07/29 Version 2.7
 */

#include	<stdio.h>
#include	<stdlib.h>
#include	<ctype.h>
#include	<string.h>
#include	<stdarg.h>
#include	<limits.h>
#include	"m2.h"

#define	SUCCSESS	0
#define	FAILURE	(-1)
#define	TRUE	1
#define	FALSE	0
#define	ERR	(-1)
#define	YES	1
#define	NO	0

#define	CAT	0
#define	CHG	1

char	*msgTTL =
	"\n"
	"This is MML compiler for SMF on MS-DOS.\n"
	"\n"
	"Usage :M2 [-option] <file name>\n"
	"Option:-o -r -n -s -p -h\n"
	"Ex 1  :M2 sample.m2\n"
	"EX 2  :M2 -o -r sample.mid sample.m2\n";

char	*msgTTL2 =
	"\nMML compiler [M2] ver 2.7 -- (c)SHINNOSUKE 1995\n";

FILE	*fpo;
unsigned	long	dataSize = 0;
unsigned	int	workSize = 3000;
int	dispFlag = TRUE;


void	putDisp( char *format ,... )	/* 画面表示 */
{
	va_list	args;
	va_start( args ,format );
	if( dispFlag == TRUE )
		vprintf( format ,args );
	va_end( args );
	return;
}

int	putData(int argc,...)	/* データ出力 */
{
	int	d[32];
	int	i;
	int	n = 0;

	va_list	ap;
	va_start( ap ,argc );

	while( n < argc ) {
		d[n] = va_arg( ap ,int );
		n++;
	}
	va_end( ap );
	for( i=0;i<argc;i++ )
		fputc( d[i] ,fpo );
	dataSize = dataSize + argc;

	return(SUCCSESS);
}

void	sizeWrite( void )	/* データ長を書き込む */
{
	int	d1;
	int	d2;
	int	d3;
	int	d4;

	putData( 4 ,0x00 ,0xff ,0x2f ,0x00);	/* end of track */
	dataSize -= 22;	/* ヘッダ長をひく */

	d1 = (int) (( dataSize&0xff000000 ) >> 24 );
	d2 = (int) (( dataSize&0xff0000 ) >> 16 );
	d3 = (int) (( dataSize&0xff00 ) >> 8 );
	d4 = (int) ( dataSize&0xff );

	fseek( fpo ,18L ,SEEK_SET );
	fputc( d1 ,fpo );
	fputc( d2 ,fpo );
	fputc( d3 ,fpo );
	fputc( d4 ,fpo );

	return;
}

void	title(void)	/* タイトル表示 */
{
	printf( msgTTL );
	return;
}

int	fNameCat( int mode ,char *f ,char *s)	/* 拡張子の変換 */
{
	int	i;
	char	*f2;
	char	*f3;

	f2 = strrchr( f ,'\\' );
	if( f2 == NULL )	f2 = f;

	f3 = strrchr( f2 ,'.' );
	if( f3 == NULL ) {
		strcat( f ,s );
		return( SUCCSESS );
	}

	if( f3 != NULL && mode == CAT )
		return( SUCCSESS );

	for( i=0;i<=strlen(s);i++ )
		f3[i] = s[i];

	return(SUCCSESS);
}
int main(int argc,char *argv[]) /* メイン */
{
	char	ifn[FILENAME_MAX];
	char	ofn[FILENAME_MAX];

	char	*s;

	int	i;
	int	j;
	int	arg = argc;
	int	oof = FALSE;
	int	orf = 0;
	int	pre = FALSE;

	unsigned long	alcSize;

	FLGDAT	fgset;
	WORKMEM	*work;

	if( argc <= 1 ) {
		printf( msgTTL2 );
		printf( "Argument is not correct.\n" );
		title();
		exit( EXIT_FAILURE );
	}

	for( i=1;i<argc;i++ ) {
		if( argv[i][0]!='-' ) {
			arg = i;
			break;
		}
		for( j=1;j<255;j++ ) {
			if( argv[i][j] == '\0' )	break;
			switch( toupper( argv[i][j] )) {
			case 'O':	/* set output file */
				oof = TRUE;
				break;
			case 'R':	/* use running status */
				orf = orf | 1;
				break;
			case 'S':	/* shift status */
				orf = orf | 2;
				break;
			case 'H':	/* Hi-speed compile */
				orf = orf | 4;
				break;
			case 'C':	/* check data */
				orf = orf | 8;
				break;
			case 'N':	/* no print */
				dispFlag = FALSE;
				break;
			case 'P':	/* pre-process only */
				pre = TRUE;
				break;
			default:
				printf( msgTTL2) ;
				printf( "Illgel option '-%c'\n" ,argv[i][j] );
				title();
				exit( EXIT_FAILURE );
			}
		}
	}

	if(( argc==arg ) || (( oof == TRUE) && ( arg>argc-2 ))) {
		printf( msgTTL2 );
		printf( "Argument is not correct.\n" );
		title();
		exit( EXIT_FAILURE );
	}

	putDisp( msgTTL2 );

	if( oof == TRUE ) {
		strcpy( ifn ,argv[arg+1] );
		strcpy( ofn ,argv[arg] );
		fNameCat( CAT ,ifn ,".m2" );
	}
	else {
		strcpy( ifn ,argv[arg] );
		strcpy( ofn ,argv[arg] );
		fNameCat( CAT ,ifn ,".m2" );
		if( pre == FALSE )
			fNameCat( CHG ,ofn ,".mid" );
		else	fNameCat( CHG ,ofn ,".mp" );
	}

	if( Pre_open( ifn ) == ERR ) {
		printf( "%s ... Can't open file\n" ,ifn );
		exit( EXIT_FAILURE );
	}

	if( pre == TRUE ) {
		if(( fpo=fopen( ofn ,"w" )) == NULL ) {
			printf( "%s ... Can't create file\n" ,ofn );
			exit( EXIT_FAILURE );
		}
		while(( s=Pre_fgets() ) != NULL )
			fprintf( fpo ,"%s\n" ,s );
		putDisp( "***** pre-process completed *****\n" );
		exit( EXIT_SUCCESS );
	}

	if(( fpo=fopen( ofn ,"wb" )) == NULL ) {
		printf( "%s ... Can't create file\n" ,ofn );
		exit( EXIT_FAILURE );
	}

	putDisp( " %s -> %s\n" ,ifn ,ofn );
	putDisp( "--------------------------------------------------\n" );

	fgset = ctrlLine();
	alcSize = fgset.wksize * sizeof(WORKMEM);
	if( alcSize > UINT_MAX ) {
		printf( "Can't allocate Working area for MIDI event. (.malloc/max %u)\n" ,
			UINT_MAX / sizeof( WORKMEM ) );
		exit( EXIT_FAILURE );
	}
	if(( work=malloc(( unsigned int ) alcSize )) == NULL ) {
		printf( "Can't allocate memory(%lu bytes) (.malloc)\n" ,alcSize );
		exit( EXIT_FAILURE );
	}

	putDisp( "Working area  :%ld (byte)\n" ,alcSize );
	putDisp( "--------------------------------------------------\n" );

	mmlLine( fgset ,work ,orf );
	sizeWrite();
	fclose( fpo );

	putDisp( "--------------------------------------------------\n" );
	putDisp( "File size     :%ld\n" ,dataSize + 22L );
	putDisp( "***** compile completed *****\n" );
	return( SUCCSESS );
}

