/**************************************************************************
* mp.h:		Main header file.
*		Part of MP, the MIDI Playground.
*
* Author:	Daniel Barrett
* Version:	See the file "version.h".
* Copyright:	None!  This program is in the Public Domain.
*		Please share it with others.
***************************************************************************/

	
#ifndef _MP_H

#include <devices/serial.h>
#include <exec/devices.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <exec/types.h>
#include <exec/interrupts.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <functions.h>
#include <stdio.h>

#ifndef __C_MACROS__
#define __C_MACROS__
#endif
#include <ctype.h>


/**************************************************************************
* Types.
**************************************************************************/
	
typedef unsigned char	STATE_T;	/* An automaton state.		*/
typedef UBYTE		MIDI_VALUE;	/* A single MIDI data value.	*/
typedef	signed char	MIDI_RESULT;	/* What happened while reading?	*/
typedef char		FLAGS;		/* Internal flags.		*/
	
/**************************************************************************
* Return values from our input routine.
**************************************************************************/
	
#define	RESULT_OK		(MIDI_RESULT)(1)    /* Legal value read.   */
#define	RESULT_ERROR		(MIDI_RESULT)(2)    /* Illegal value read. */
#define	RESULT_OVERFLOW		(MIDI_RESULT)(3)    /* Value overflowed.   */
#define	RESULT_STOP		(MIDI_RESULT)(4)    /* End of data.        */
	
/**************************************************************************
* States of our finite automaton for reading input.
**************************************************************************/
	
#define	STATE_SUCCESS		1	/* Got a legal value. */
#define	STATE_ERROR		2	/* Had an input error. */
#define	STATE_OVERFLOW		3	/* Read too big a value. */
#define	STATE_NORMAL		4	/* Haven't read anything yet. */
#define	STATE_INCOMMENT		5	/* Skipping a comment. */
#define	STATE_INDECIMAL		6	/* Reading a base 10 number. */
#define	STATE_LEADZERO		7	/* Read a leading zero. */
#define	STATE_INOCTAL		8	/* Reading an octal number. */
#define	STATE_STARTHEX		9	/* Read 1st digit of hex number. */
#define	STATE_INHEX		10	/* Reading a hex number. */
#define	STATE_STARTBINARY	11	/* Read 1st symbol of binary num. */
#define	STATE_INBINARY		12	/* Reading a binary number. */
#define	STATE_NEGATIVE		13	/* UNUSED.  FOR FUTURE UPDATE. */
#define	STATE_INCHAR		14	/* Reading a char constant. */
#define	STATE_EXPECTQUOTE	15	/* Finishing a char constant. */
#define	STATE_BACKSLASHINCHAR	16	/* Backslash in a char constant. */
#define	STATE_BACKSLASHINSTRING	17	/* Backslash in a string constant. */
#define	STATE_INCLUDEFILE	18	/* UNUSED.  FOR FUTURE UPDATE. */

	
/**************************************************************************
* Macros for converting characters to numbers:
*
*	D_TO_INT(c)	Convert a digit to its numeric value.
*	L_TO_INT(c)	Convert a letter (A..F) to its base 16 value.
*	H_TO_INT(c)	Convert a hex digit to its numeric value.
**************************************************************************/
	
#define	D_TO_INT(c)	((long)((c) - '0'))
#define	L_TO_INT(c)	((long)((toupper(c)) - 'A') + 10)
#define	H_TO_INT(c)	(isdigit(c) ? D_TO_INT(c) : L_TO_INT(c))
	
/**************************************************************************
* Macros for classifying types of input.  The rest are in <ctype.h>.
**************************************************************************/
	
#define	isoctal(c)	(((c) >= '0') && ((c) <= '7'))

/**************************************************************************
* Other macros.
**************************************************************************/

#define	MAX(a,b)	(((a) > (b)) ? (a) : (b))
#define	MIN(a,b)	(((a) < (b)) ? (a) : (b))

#define OpenReadFile(filename)	OpenAFile(filename, "r", "read")
#define OpenWriteFile(filename)	OpenAFile(filename, "w", "write")

	
/**************************************************************************
* The largest legal value our input routine can handle.
**************************************************************************/
	
#define	LARGEST_VALUE		(MIDI_VALUE)(255)
#define	BITS_IN_MIDI_VALUE	BITSPERBYTE		/* in types.h */

/***************************************************************************
* Character constants for classifying the input.
***************************************************************************/

#define	START_BINARY	'#'	/* Symbol for start of binary number. */
#define	HELP_SYMBOL	'?'	/* Symbol for help request from user. */
#define	START_COMMENT	';'	/* Start-comment symbol. */
	
/***************************************************************************
* Command-line Options.
***************************************************************************/

#define	OPT_INPUT	'i'		/* Input format. */
#define	OPT_OUTPUT	'o'		/* Output format. */
#define	OPT_TEXT	't'		/* Text I/O. */
#define	OPT_BINARY	'b'		/* Binary I/O. */
#define	OPT_MIDI	'm'		/* MIDI I/O. */
#define	OPT_SYSEX	'x'		/* UNUSED. FOR FUTURE UPDATE. */
#define	OPT_INFILE	'g'		/* Get from file. */
#define	OPT_OUTFILE	'p'		/* Put to file. */

/* For getopt(). */
#define	GETOPT_OPTIONS	"i:o:g:p:x";
extern int optind;
extern char *optarg;

/***************************************************************************
* Flags, and their associated macros.
***************************************************************************/

#define	NUM_FLAGS	3	/* How many flags? */

#define	FLAG_ITYPE	0	/* Flag ID's. */
#define	FLAG_OTYPE	1
#define	FLAG_SYSEX	2

	
/***************************************************************************
* Prototypes.
***************************************************************************/

/* read.c */
STATE_T NewState(int c, STATE_T state, MIDI_VALUE *answer);
STATE_T NonStringState(int c, STATE_T state, MIDI_VALUE *answer);
STATE_T DoNormal(int c, MIDI_VALUE *answer);
STATE_T DoDecimal(int c, MIDI_VALUE *answer);
STATE_T DoOctal(int c, MIDI_VALUE *answer);
STATE_T DoHex(int c, MIDI_VALUE *answer);
STATE_T DoInHex(int c, MIDI_VALUE *answer);
STATE_T DoBinary(int c, MIDI_VALUE *answer);
STATE_T DoInBinary(int c, MIDI_VALUE *answer);
STATE_T DoLeadZero(int c, MIDI_VALUE *answer);
STATE_T IncreaseIfPossible(MIDI_VALUE *answer, int newNum, int base, 
				STATE_T newState);
STATE_T DoInChar(int c, MIDI_VALUE *answer);
STATE_T DoExpectQuote(int c, MIDI_VALUE *answer);
STATE_T DoBackslash(int c, MIDI_VALUE *answer, STATE_T newState);
STATE_T DoInString(int c, STATE_T state, MIDI_VALUE *answer,
			 short *inString);
STATE_T DoComment(int c);
void InputHelp();

void PrintNumber(MIDI_VALUE number, FILE *out);
void PrintBinary(MIDI_VALUE number, FILE *out);

/* serial.c */
short SerialSetup(FLAGS sysex);
void SerialShutdown(void);
void ResetSerialPort(void);
long AnyMidiData(void);
void PrepareToReadMidi(UBYTE *buf, int len);
void PrepareToWriteMidi(UBYTE *buf, int len);
long DoTheIO(void);
long FastSerialRead(UBYTE buf[]);

/* iofunctions.c */
MIDI_RESULT FromMidi(FILE *in, MIDI_VALUE *value);
BOOL ToMidi(FILE *in, MIDI_VALUE value);
MIDI_RESULT FromText(FILE *in, MIDI_VALUE *value);
BOOL ToText(FILE *in, MIDI_VALUE value);
MIDI_RESULT FromBinary(FILE *in, MIDI_VALUE *value);
BOOL ToBinary(FILE *in, MIDI_VALUE value);
void SkipText(FILE *in, MIDI_VALUE value);
void SkipMidi(FILE *in, MIDI_VALUE junk);
void SkipBinary(FILE *in, MIDI_VALUE junk);

/* main.c */
BOOL IsIOType(char ioType);
BOOL CheckIOType(char opt, int ioFlag, FLAGS theFlags[]);
BOOL HandleOptions(int argc, char *argv[], FLAGS theFlags[],
		   char **infile, char **outfile);
void ReadAndWriteStuff(FLAGS theFlags[], FILE *in, FILE *out);
void SetTheFunctions(MIDI_RESULT (**getfcn)(), BOOL (**putfcn)(),
		    void (**skipfcn)(), FLAGS theFlags[]);
BOOL CheckFlags(FLAGS theFlags[]);
void InitStuff(FLAGS theFlags[], FILE **in, FILE **out, char **inFile,
		char **outFile);
BOOL MIDIPlayground(FLAGS theFlags[], FILE *in, FILE *out);

/* wb.c */

/* help.c */
void BegForUsage(char *progName);
void Help(char *progName);

/* files.c */
FILE *OpenAFile(char *filename, char *mode, char *readOrWrite);
BOOL FileExists(char *filename);
BOOL DontOverwriteExistingFile(char *filename);
BOOL SetupFiles(char *infile, char *outfile, FILE **in, FILE **out);
void CloseFiles(FILE *in, FILE *out, char *filein, char *fileout);
BOOL MakeFilename(char **dest, char *src);

#ifndef OpenReadFile
FILE *OpenReadFile(char *filename);
#endif

#ifndef OpenWriteFile
FILE *OpenWriteFile(char *filename);
#endif


#endif /* _MP_H */
