#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "exec/types.h"

#ifdef AMIGA
#include <exec/execbase.h>
#endif

/********************************************************************/
/**************** START OF USER SETTABLE PREFERENCES ****************/

/*
 * Note: This program relies heavily on that the system which
 * automagically free()'s all malloc()'ed memory, works. The program
 * itself does never call free(). This is because we're doing lots of
 * tiny allocations, and a properly designed pooling system will
 * hopefully do a quicker job than we'll be able to do. So there.
 *
 * You may wish to modify the GetRCName() to better suit your
 * preferences. In any case, it should put the filename (and full path)
 * of the `.chktexrc' file into the ConfigFile array. The array is sized
 * BUFLEN bytes.
 *
 * The program does also assume that AMIGA is defined if the source
 * compiled on an Amiga machine, and that __unix__ is defined if the
 * source is compiled on a UNIX machine.
 *
 */


/*
 * The settings below work well with GCC. If you've got another compiler,
 * you should read through the whole file and define the settings yourself.
 * If you're using SAS/C Amiga, no adjustments have to be done at all.
 *
 * The #defines are necessary to use some non-ANSI functions, which exist 
 * only on some compilers. Btw., realloc() appears to be broken on GCC (at
 * least on the version I found at our university).
 */

#ifdef __GNUC__
	#define stricmp strcasecmp
	#define	STRUPR_NEED
	#define REALLOC_REPL
#endif


/*
 * You'll have to define stricmp(a, b) to a function which does
 * case-insensitive comparison between a and b.
 */

/*
#define stricmp		strcasecmp?
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * If you have a compiler which doesn't like prototypes, uncomment
 * the following line.
 */

/*
#define __NOPROTO
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Uncomment the following line if your compiler does not have the
 * strdup() function, which makes a duplicate of a string.
 */

/*
#define STRDUP_NEED
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Uncomment the following line if your compiler does not have the
 * strupr() function, which makes a string uppercase.
 */

/*
#define STRUPR_NEED
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Uncomment the following line if your version of realloc() does not
 * accept a previous memory pointer of NULL, or is broken in some other
 * way. I could only get it to work with GCC if I defined this one.
 */

/*
#define REALLOC_REPL
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * This will be the length of our buffers. If you're operating with
 * extremely long lines, you may wish to increase this one to avoid
 * errors. They should be non-fatal, but may cause extra spaces to be
 * inserted in the input.
 */
#define BUFLEN	256

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Uncomment the following line if you don't wish to have any
 * `twirling baton' (`\|/-'). Is a waste of cycles if you've got
 * a speedy CPU. Some displays do also not like this huge amount
 * of carriage returns without a subsequent line feed.
 */

/*
#define NO_TICTOC
*/

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * The next macro should return TRUE if the character should be
 * stripped from a string, e.g. if it is a space, tab, control
 * character or any other `invisible' character. I've listed a few
 * alternatives which should work OK on ASCII machines, select the
 * one that fits (or create your own :) ). Please embrace it with
 * parentheses.
 */

/*
 * This one is the most correct one - should always work
#define	SKIP_STRIP(c)	(isspace(c) || iscntrl(c))
 *
 * This one works better on ANSI X3.64-1979 terminals
#define SKIP_STRIP(c)	((c > 0 && <= ' ') || (c >= 0x7f && c <= 0xa0))
 *
 * This one works on 7-bits terminals, which is enough for most people.
 */

#define SKIP_STRIP(c)	(c > 0 && c <= ' ')

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * The next macro should return TRUE if LaTeX (and you?) considers
 * the character `c' as a space, which should be detected when
 * we're checking whether commands are terminated by spaces.
 *
 * The alternatives listed above should be suitable here, too.
 */

#define LATEX_SPACE(c)	(c > 0 && c <= ' ')

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * Here you should define what codes which should be returned to the
 * shell upon success/failure.
 *
 */

#ifndef EXIT_FAILURE
	#ifdef  AMIGA
		#define	EXIT_FAILURE	20
	#else
		#define	EXIT_FAILURE	1
	#endif
#endif

#ifndef EXIT_SUCCESS
#define	EXIT_SUCCESS	0
#endif

/*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */

/*
 * SLASH should be defined to the character your computer uses to
 * separate files/directories. Most systems use '/', messydos uses
 * '\'.
 *
 * DIRCHARS should be defined to the characters a directory entry
 * may end on. On Amigas, this is ":/" (either "FOO:BAR/" or "FOO:"),
 * Unix uses only "/", while messydos uses ":\".
 *
 * Adjust both to suit your needs.
 */


#if defined(__unix__) || defined(AMIGA)
	#define	SLASH		'/'
#endif

#if defined(__unix__)
 	#define DIRCHARS	"/"
#elif defined(AMIGA)
	#define DIRCHARS	":/"
#endif


/***************** END OF USER SETTABLE PREFERENCES *****************/
/********************************************************************/


/*
 * This is the name of the global resource file.
 */

#define RCFILE			".chktexrc"


/*
 * How many indexes we'll allocate first time
 */
#define MINPUDDLE	256

#define elif		else if
#define ifn(a)		if(!(a))

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

#ifndef max
#define max(a,b)	((a)>(b)?(a):(b))
#endif

struct Cmds
{
	STRPTR	*Cmds;
	ULONG	Size, Used;
	BOOL	Sorted;
};

#define	STRP_LFT			1
#define	STRP_RGT			2
#define	STRP_BTH			(STRP_LFT|STRP_RGT)

#ifndef __NOPROTO

#ifndef __PROTO
#define __PROTO(a) a
#endif

#else
#ifndef __PROTO
#define __PROTO(a) ()

#endif
#endif



UWORD main __PROTO((UWORD, STRPTR *));
void PrintStatus __PROTO((void));
BOOL FindErr __PROTO((STRPTR const, ULONG const));
void PrintError __PROTO((STRPTR const, ULONG, ULONG const, STRPTR const, ...));
void PerformCommand __PROTO((STRPTR const));

STRPTR strcatm __PROTO((STRPTR dest, STRPTR String, ...));
ULONG strrep __PROTO((STRPTR, UBYTE const, UBYTE const));
STRPTR strip __PROTO((STRPTR, WORDBITS const));
void tictoc __PROTO((void));
void tackon __PROTO((STRPTR, const STRPTR));
#ifdef STRUPR_NEED
STRPTR strupr __PROTO((STRPTR));
#endif

#ifdef STRDUP_NEED
STRPTR strdup __PROTO((STRPTR const));
#endif

#ifdef REALLOC_REPL
#define realloc	realloc_
void *realloc_ __PROTO((void *,size_t));
#endif

void GetRCName __PROTO((void));
BOOL ReadRC __PROTO((STRPTR const));
STRPTR ReadWord __PROTO((STRPTR, FILE *));
STRPTR ReadLine __PROTO((STRPTR, FILE *));

BOOL InsertWord __PROTO((STRPTR const, struct Cmds *));
BOOL HasWord __PROTO((STRPTR const, struct Cmds *));
int str_cmp __PROTO((void const *, void const *));

BOOL PushChar __PROTO((UBYTE const));
UBYTE PopChar __PROTO((void));
UBYTE TopChar __PROTO((void));

ULONG BrackIndex __PROTO((UBYTE const));
void AddBracket __PROTO((UBYTE const));
UBYTE MatchBracket __PROTO((UBYTE const));

