/*
 * This is a program for splitting "dms" files on unix systems.
 * Its usage is:
    dmssplit <option> file

 * With no option, dmssplit will create two files named "1_file" and "2_file"
 * (I was lazy about that), with the first being approximately 70% in size
 * of the original, and the second 30% (how did you guess?).
 
 * Options are:
    -h or -? : little help
    -t <n> : chose n to be the track number where the file is splitted
    -p <n> : chose n to be the size percentage of the first file
    -d : debug mode. Very verbose.

 * Option -p will eventually supersede option -t.

 * The code is pretty basic Unix, there should be no compiling problem,
 * just do "cc dmssplit.c -o dmssplit" to get the executable.
 * Care was taken to read and use the data as char arrays to avoid
 * alignement problems inside structures (a main portability nuisance).
 * But lint does not like that!

 * WARNING: I had no time to fully test this one. "dmscheck" tells the 
 *          resulting files are good, but I didn't actually try them.
 *          KEEP THE ORIGINAL FILE !!!!
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>

#define RATIO 70

typedef char BYTE;
typedef unsigned char UBYTE;
typedef short SHORT;
typedef unsigned short USHORT;
typedef long LONG;
typedef unsigned long ULONG;

#define SILENT 0
#define NORMAL 1
#define VERBOSE 2
#define DEBUG  3

int MessageLevel = NORMAL ;
int TrackNumber = 0 ;
int Percentage = 0 ;

#define NOERROR 0
#define NONFATAL 1
#define FATAL 2

int ErrorFlag = NOERROR ;

char * FileName ;

int FirstTrack = 0 ;
int MediumTrack = 0 ;
int LastTrack = 0 ;
int LastTrackRead = 0 ;

int FdIn ;
int FdOut ;

char IoBuf[12000] ;
USHORT Crc ;

#define MAXTRACKS 85
int CompSizes[MAXTRACKS] ;
int RawSizes[MAXTRACKS] ;
int CompText ;
int RawText ;

/* Format of a simple DMS file:

	Ident File_Head CRC Track_Head CRC Data Track_Head CRC Data  ....

*/

char Ident[6] ;			/* "DMS!" */

/* 
   These macros are used to access the file header components
   with no concern about the alignement requirements of each machine.
*/

#define DHEAD_FROM(tab)  (*((SHORT *) (tab+12)))
#define DHEAD_TO(tab)    (*((SHORT *) (tab+14)))
#define DHEAD_CSIZE(tab) (*((ULONG *) (tab+16)))
#define DHEAD_SIZE(tab)  (*((ULONG *) (tab+20)))
#define DHEAD_MODE(tab)  (*((SHORT *) (tab+48)))

char DHeaderIn[50] ;
char DHeaderOut[50] ;

struct File_Head		/*offset - sizeof(File_Head) = 50 */
{
	long u1  ;		/* 0 -  ???? */
	long u2  ;		/* 4 -  ???? */
	long date ;		/* 8 - Creation date of file */
	short from ;		/*12 - index of first track */
	short to ; 		/*14 - index of last track */
	ULONG  size_after ;	/*16 - total size of data after compression */
	ULONG  size_before ;	/*20 - total size of data before compression */
	long u3 ;		/*24 -  0 */
	short cpu ;		/*28 -  Cpu type ( 1:68000, 2:68010, ... ) */
	short copross ; 	/*30 -  Cpu coprocessor ( 1:68881 ) */
	short machine ;		/*32 -  Machine used ( 1:Amiga, 2:PC, ...) */
	short u4 ;		/*34 -  ??? */
	short cpu_speed ;	/*36 -  */
	long time ;		/*38 -  Time to create archive in sec. */
	short c_version ;	/*42 -  Version of creator (66, 67, 68) */
	short n_version ;	/*44 -  Version needed to extract */
	short disk_type ;	/*46 -  Disktype of archive */
	short cmode ;		/*48 -  compression mode 0-4 */
} ;

char THeader[18] ;

#define THEAD_IDENT(tab) (*((USHORT *) (tab+0 )))
#define THEAD_TNUM(tab)  (*((SHORT *)  (tab+2 )))
#define THEAD_CSIZE(tab) (*((ULONG *)  (tab+4 )))
#define THEAD_SIZE(tab)  (*((USHORT *) (tab+10 )))
#define THEAD_DCRC(tab)  (*((USHORT *) (tab+16)))

struct Track_Head		/*offset -  sizeof(Track_Head) = 18 */
{
	short delim ;		/* 0 - delimiter, 0x5452, is 'TR' */
	short number ;		/* 2 - number of track, sometimes -1 */
	ULONG size ;		/* 4 - size of data part */
	USHORT plength ;	/* 8 - length of encoded data */
	USHORT ulength ;	/*10 - length of non-encoded data */
	short mode ;		/*12 - encryption mode(0: simple, 102: quick)*/
	USHORT usum ;		/*14 - raw data checksum */
	USHORT dcrc ;		/*16 - data CRC */
} ;

static USHORT CRCTab[256]=
{
	0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
	0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
	0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
	0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
	0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
	0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
	0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
	0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
	0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
	0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
	0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
	0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
	0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
	0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
	0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
	0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
	0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
	0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
	0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
	0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
	0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
	0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
	0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
	0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
	0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
	0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
	0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
	0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
	0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
	0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
	0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
	0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
};

USHORT DoBlockCRC(Mem, Size)
UBYTE* Mem;
int Size ;
{
	register USHORT CRC = 0;

	while(Size--)
		CRC = CRCTab[((CRC ^ *Mem++) & 255)] ^ ((CRC >> 8) & 255);

	return(CRC) ;
}

static void ReadError(s,n)
char* s;
int n;
{
	if ( MessageLevel >= VERBOSE )
	    printf("\tError reading %s (%d char read)\n",s,n) ;
}

static void WriteError(s,n)
char* s;
int n;
{
	if ( MessageLevel >= VERBOSE )
	    printf("\tError writing %s (%d char written)\n",s,n) ;
}

static void WhereInFile(fd,s)
int fd ;
char *s;
{
	off_t init;

	init = lseek(fd,(off_t) 0, L_INCR) ;
	if ( MessageLevel >= DEBUG )
	    printf("\tStarting I/O of %s at offset %d\n",s,(int) init ) ;
}

/*
 * Reading a track in IoBuf.
 *
 */

static void ReadTrackHeader(fd)
int fd ;
{
	int n_read ;

	WhereInFile(fd,"Track header") ;

	n_read = read(fd, THeader, sizeof(THeader) ) ;
	if ( n_read != sizeof(THeader)  )	
	{
	    ReadError("Theader DATA",n_read) ;
	    ErrorFlag = FATAL;
	    return;
	}

	n_read = read(fd, (char *) &Crc, 2) ;
	if ( n_read != 2 )	
	{
	    ReadError("THeader CRC",n_read) ;
	    ErrorFlag = FATAL;
	}
}

static void VerifyTrackHeader()
{
	USHORT crc ;

	if ( THEAD_IDENT(THeader) != 0x5452 )	/* Magic string "TR" */
	{
	    if ( MessageLevel >= VERBOSE )
	        printf("\tBAD THeader identifier: %x\n",
					(int) THEAD_IDENT(THeader) );

	    ErrorFlag = FATAL ;
	    return ;
	}

	crc = DoBlockCRC((UBYTE*) THeader, sizeof(THeader) ) ;

	if ( crc != Crc )
	{
	    if ( MessageLevel >= VERBOSE )
	        printf("\tBAD THeader checksum. Read %d, computed %x\n",
		       				(int) Crc, (int) crc ) ;
	    ErrorFlag = FATAL ;	/* size is not sure */
	}
	else if ( MessageLevel >= DEBUG )
	    printf("\tTrack Header checksum OK (%x)\n",(int) crc ) ;
}

static void ReadTrackData(fd)
int fd ;
{
	int n_read ;

	if ( MessageLevel >= DEBUG )
            printf("\tSize of track data: %d\n", (int) THEAD_CSIZE(THeader) );

	if ( MessageLevel >= VERBOSE )
        {
            printf("\tTrack: %2d ", (int) THEAD_TNUM(THeader)) ;
	}

	n_read = read(fd, IoBuf, (int) THEAD_CSIZE(THeader)) ;
	if ( n_read != THEAD_CSIZE(THeader) )	
	{
	    ReadError("track data",n_read) ;
	    ErrorFlag = FATAL ; 
	    return;
	}
}

static void VerifyTrackData()
{
	USHORT crc ;

	crc = DoBlockCRC((UBYTE*) IoBuf, (int) THEAD_CSIZE(THeader) ) ;

	if ( crc != THEAD_DCRC(THeader) )
	{
	    if ( MessageLevel >= VERBOSE )
		printf("-BAD CRC: read %x, computed %x\n",
				(int) THEAD_DCRC(THeader), (int) crc ) ;
	    ErrorFlag = NONFATAL ;
	}
	else if ( MessageLevel >= VERBOSE )
	    printf("-GOOD CRC: %x\n",(int) crc ) ;
}

static void ReadVerifyTrack(fd)
int fd ;
{
	ReadTrackHeader(fd) ;

	if ( ErrorFlag == NOERROR )
		VerifyTrackHeader() ;
	
	if ( ErrorFlag == NOERROR )
		ReadTrackData(fd) ;

	if ( ErrorFlag == NOERROR )
		VerifyTrackData() ;

	if ( ErrorFlag == NOERROR )
		LastTrackRead = THEAD_TNUM(THeader) ;
}

static void ReadTrack(fd)
int fd ;
{
	ReadTrackHeader(fd) ;

	if ( ErrorFlag == NOERROR )
		ReadTrackData(fd) ;

	if ( ErrorFlag == NOERROR )
		LastTrackRead = THEAD_TNUM(THeader) ;
}


/*
 * Writing a track
 *
 */

WriteTrackData(fd)
int fd ;
{
	int n_write ;

	n_write = write(fd, IoBuf, (int) THEAD_CSIZE(THeader) ) ;
	if ( n_write <  (int) THEAD_CSIZE(THeader) )	
	{
	    WriteError("THeader DATA",n_write) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}
}

WriteTrackHeader(fd)
int fd ;
{
	int n_write ;

	n_write = write(fd, THeader, sizeof(THeader)) ;
	if ( n_write < sizeof(THeader) )	
	{
	    WriteError("THeader DATA",n_write) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}

	n_write = write(fd, (char *) &Crc, 2) ;
	if ( n_write < 2 )	
	{
	    WriteError("THeader CRC",n_write) ;
	    ErrorFlag = FATAL ;
	}
}

WriteTrack(fd)
int fd ;
{
	WriteTrackHeader(fd) ;

	if ( ErrorFlag == NOERROR )
		WriteTrackData(fd) ;
}

/*
 * Handling one file dms header
 *
 */

void VerifyDHeader()
{
	USHORT crc ;

	if ( strncmp(Ident, "DMS!", 4 ) )
	{
	    if ( MessageLevel >= NORMAL )
		printf("\tThis is *not* a dms archive\n") ;
	    ErrorFlag = FATAL ; 
	    return;
	}

	crc = DoBlockCRC((UBYTE*) DHeaderIn, sizeof(DHeaderIn) ) ;

	if ( crc != Crc )
	{
	    if ( MessageLevel >= VERBOSE )
		printf("\tBAD file header checksum. Read %x, computed %x\n",
					(int) Crc, (int) crc) ;
	    ErrorFlag = FATAL ;
	}
	else if ( MessageLevel >= DEBUG )
	    printf("\tDms Header checksum OK (%x = %x)\n",
						(int) crc, (int) Crc );
}

static void UpdateFileData()
{
	int medium ;

	if ( MessageLevel >= VERBOSE )
	{
	    printf("\tContains tracks: %d to %d\n",
		(int) DHEAD_FROM(DHeaderIn), (int) DHEAD_TO(DHeaderIn) );

	   printf("\tCompression mode: %d\n", (int) DHEAD_MODE(DHeaderIn)) ;
	   printf("\tData sizes: raw: %d     compressed: %d\n",
		(int) DHEAD_SIZE(DHeaderIn), (int) DHEAD_CSIZE(DHeaderIn));
	}

	FirstTrack = (int) DHEAD_FROM(DHeaderIn) ;
	LastTrack = (int) DHEAD_TO(DHeaderIn) ;
}

void ReadDHeader(fd)
int fd ;
{
	int n_read ;

	WhereInFile(fd,"Ident") ;

	n_read = read(fd, Ident, 4) ;
	if ( n_read < 4 )	
	{
	    ReadError("Ident",n_read) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}

	WhereInFile(fd,"DHeader") ;

	n_read = read(fd, DHeaderIn, sizeof(DHeaderIn)) ;
	if ( n_read < sizeof(DHeaderIn) )	
	{
	    ReadError("DHeader DATA",n_read) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}

	n_read = read(fd, (char *) &Crc, 2) ;
	if ( n_read < 2 )	
	{
	    ReadError("DHeader CRC",n_read) ;
	    ErrorFlag = FATAL ;
	}
}

void TreatDHeader(fd)
int fd ;
{
	ReadDHeader(fd) ;

	if ( ErrorFlag == NOERROR )
	    VerifyDHeader() ;

	if ( ErrorFlag == NOERROR )
	    UpdateFileData() ;
}

/*
 * Writing the first part
 *
 */

static void WriteDHeader(fd)
int fd ;
{
	int n_write;
	USHORT crc ;

	crc = DoBlockCRC((UBYTE*) DHeaderOut, sizeof(DHeaderOut) ) ;

	n_write = write(fd, "DMS!", 4) ;
	if ( n_write < 4 )	
	{
	    WriteError("Ident",n_write) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}

	WhereInFile(FdOut,"DHeader") ;

	n_write = write(fd, DHeaderOut, sizeof(DHeaderOut)) ;
	if ( n_write < sizeof(DHeaderOut) )	
	{
	    WriteError("DHeader DATA",n_write) ;
	    ErrorFlag = FATAL ; 
	    return ;
	}

	n_write = write(fd, (char *) &crc, 2) ;
	if ( n_write < 2 )	
	{
	    WriteError("DHeader CRC",n_write) ;
	    ErrorFlag = FATAL ;
	}
}
	
static void WriteFirstTracks()
{
	while ( LastTrackRead < (MediumTrack-1) )
	{
	    ReadTrack(FdIn) ;

	    if ( ErrorFlag == NOERROR )
	    	WriteTrack(FdOut) ;

	    if ( ErrorFlag != NOERROR )
		break ;
	}
}

static void WriteLastTracks()
{
	while ( LastTrackRead < LastTrack )
	{
	    ReadTrack(FdIn) ;

	    if ( ErrorFlag == NOERROR )
	    	WriteTrack(FdOut) ;

	    if ( ErrorFlag != NOERROR )
		break ;
	}
}

/*
 * Writing Files
 *
 */

static int ComputeCompSize(first, last)
int first,last ;
{
	int i, total ;

	if ( first == -1 )
	{    total = CompText ; i=0 ; }
	else
	{    total = 0 ; i=first ; }

	for ( ; i <= last ; i++ )
	    total += CompSizes[i] ;

	return total ;
}

static int ComputeSize(first, last)
int first,last ;
{
	int i, total ;


	if ( first == -1 )
	{    total = RawText ; i=0 ; }
	else
	{    total = 0 ; i=first ; }

	for ( ; i <= last ; i++ )
	    total += RawSizes[i] ;

	return total ;
}

static void WriteSecondFile()
{
	int i ;
	
	strcpy(IoBuf, "2_") ;
	strcat(IoBuf,FileName) ;

	if ( MessageLevel >= VERBOSE )
		printf("\tSecond output file name: %s\n",IoBuf) ;

	if ( (FdOut = open(IoBuf, O_WRONLY | O_CREAT, 0664)) == -1 )
	{
		fprintf(stderr,"\tError creating file: %s\n", IoBuf) ;
		ErrorFlag = FATAL ;
		return ;
	}

	for ( i=0 ; i< sizeof(DHeaderIn); i++ )
		DHeaderOut[i] = DHeaderIn[i] ;

	DHEAD_FROM(DHeaderOut) = MediumTrack ;
	DHEAD_CSIZE(DHeaderOut) = 
			(ULONG) ComputeCompSize(MediumTrack, LastTrack) ;
	DHEAD_SIZE(DHeaderOut) = 
			(ULONG) ComputeSize(MediumTrack, LastTrack) ;

	WriteDHeader(FdOut) ;

	if ( ErrorFlag == NOERROR )
	    WriteLastTracks() ;

	close(FdOut) ;
}

static void WriteFirstFile()
{
	int i ;
	
	strcpy(IoBuf, "1_") ;
	strcat(IoBuf,FileName) ;

	if ( MessageLevel >= VERBOSE )
		printf("\tFirst output file name: %s\n",IoBuf) ;

	if ( (FdOut = open(IoBuf, O_WRONLY | O_CREAT, 0664)) == -1 )
	{
		fprintf(stderr,"\tError creating file: %s\n", IoBuf) ;
		ErrorFlag = FATAL ;
		return ;
	}

	for ( i=0 ; i< sizeof(DHeaderIn); i++ )
		DHeaderOut[i] = DHeaderIn[i] ;

	DHEAD_TO(DHeaderOut) = MediumTrack - 1 ;
	DHEAD_CSIZE(DHeaderOut) = 
			(ULONG) ComputeCompSize(-1, MediumTrack-1) ;
	DHEAD_SIZE(DHeaderOut) = 
			(ULONG) ComputeSize(-1, MediumTrack-1) ;

	WriteDHeader(FdOut) ;

	if ( ErrorFlag == NOERROR )
	    WriteFirstTracks() ;

	close(FdOut) ;
}

/*
 *
 */

static void ComputeMediumTrack()
{
	int i, c, c1 ;

	if ( TrackNumber && !Percentage )	/* just a -t parameter */
	{
	    if ( TrackNumber <= FirstTrack )
		MediumTrack = FirstTrack + 1  ;
	    else if ( TrackNumber >= LastTrack )
		MediumTrack = LastTrack - 1 ;
	    else
		MediumTrack = TrackNumber ;

	    printf("TrackNumber: %d   MediumTrack: %d\n",
						 TrackNumber, MediumTrack) ;
	}
	else	/* a -p parameter (then -t ignored), or no parameter */
	{
	    if ( !Percentage )
		Percentage = RATIO ;	/* no parameter, split 70/30 */

	    c1 = DHEAD_CSIZE(DHeaderIn) * Percentage / 100 ;
	    c = CompText ;
	    for ( i=0 ; (c<c1) && (i<MAXTRACKS) ; i++ )
		c += CompSizes[i] ;
	    MediumTrack = i-1 ;
	    if ( MediumTrack <= FirstTrack )
		MediumTrack = FirstTrack + 1  ;
	    if ( MediumTrack >= LastTrack )
		MediumTrack = LastTrack - 1 ;
	    printf("\tPercentage: %d   MediumTrack: %d\n",
						 Percentage, MediumTrack) ;
	}
}

static void SplitFile(file_)
char * file_ ;
{
	if ( lseek(FdIn, (off_t) 0, L_SET) == -1 )
	{				 /* return to beginning of file */
	    printf("Unable to lseek to beginning of file\n") ;
	    ErrorFlag = FATAL ;
	}
		
	if ( ErrorFlag == NOERROR )
	{
	    ReadDHeader(FdIn) ;		/* Skip header */
	    LastTrackRead = -1 ;
	}

	if ( ErrorFlag == NOERROR )
	    WriteFirstFile() ;	

	if ( ErrorFlag == NOERROR )
	    WriteSecondFile() ;

	close(FdIn) ;
}

static void ScanFile(file_)
char * file_ ;
{
	if ( (FdIn = open(file_, 0)) == -1 )
	{
		fprintf(stderr,"\tError opening file: %s\n", file_) ;
		return ;
	}

	printf("Splitting file: %s\n", file_ ) ;

	TreatDHeader(FdIn) ;

	while ( LastTrackRead < LastTrack && ErrorFlag == NOERROR )
	{
	    ReadVerifyTrack(FdIn) ;

	    if ( LastTrackRead == -1 )
	    {
		
		CompText = (int) THEAD_CSIZE(THeader) ;
		RawText = (int) THEAD_SIZE(THeader) ;
	    }
	    else
	    {
	        CompSizes[LastTrackRead] = (int) THEAD_CSIZE(THeader) ;
	        RawSizes[LastTrackRead] = (int) THEAD_SIZE(THeader) ;
	    }
	}
       
	if ( ErrorFlag == NOERROR )
		ComputeMediumTrack() ;
}


/*
 * Various intialisations and command line handle
 *
 */

static PrintHelp()
{
	puts("Valid options are:") ;
	puts("\t-p <n>: percentage") ;
	puts("\t-t <n>: track number") ;
	puts("\t-d : debug (very verbose)") ;
	puts("\t-h,-? : help") ;

	exit(0) ;
}

static int DecodeOption(argv, arg)
char * argv[] ;
int arg ;
{
        char *argp = argv[arg]+1 ;

        switch ( *argp )
        {
            case 't':
	    	 TrackNumber = atoi(argv[arg+1]) ;
		 if ( TrackNumber < 0 || TrackNumber > 79 )
			TrackNumber = 0 ;
                 return (arg+2) ;

            case 'p':
	    	 Percentage = atoi(argv[arg+1]) ;
		 if ( Percentage < 0 || Percentage > 100 )
			Percentage = 0 ;
                 return (arg+2) ;

            case 'd':
		 MessageLevel = DEBUG ;
                 return (arg+1) ;

            case 'h':
	    case '?':
	    default:
		 PrintHelp() ;
                 return (arg+1) ;		/* Not executed */

	}
}


void DecodeArgLine(argc, argv)
int argc ;
char * argv[] ;
{
  	int arg ;

	if ( argc <= 1)
	{
	    PrintHelp() ;
	}

        for ( arg = 1; arg < argc ; )
        {
            if ( *argv[arg] != '-' )
            {
                FileName = argv[arg] ;
                arg += 1 ;
            }
            else
                arg = DecodeOption(argv,arg) ;
        }
}

/*
 * Main part
 *
 */

int main(argc,argv)
int argc ;
char ** argv ;
{
	DecodeArgLine(argc, argv) ;
	
	ScanFile(FileName) ;
	
	SplitFile(FileName) ;

	if (ErrorFlag )
	    return 1 ;
	else
	    return 0 ;
}
