/*
 *		BBSINDEX.H
 *	
 *		All the standard variables and other stuff used by all the modules
 *		of BBSindex, and standard BBS-PC! headers (with a few modifications).
 *
 *		Important note: This header file cannot be precompiled with
 *		Lattice C V5.02, because of a bug which prevents bit fields
 *		from working properly when they are precompiled.
 */

#include "bbs.h"

#define TRUE	1
#define FALSE	0

#define BTOK(x) (((x)+1023)>>10)	/* Convert file size into K */

/*
 *		Default values for command line parameters and script commands
 */

#define FORMAT		"%15n %w %-6x-%b{B,T}  %c\n"
#define UDNAME		"UDHEAD.DAT"
#define CFGNAME		"CFGINFO.DAT"
#define PROGSCRIPT	"BBSCRIPT"
#define DEFSCRIPT	"BBSindex.scr"

/*
 *	Blocksize determines the largest contiguous memory segment which is
 *	needed. Larger values give faster processing, but need more continuous
 *	memory.
 */

#define	BLOCKSIZE	160				/* Number of records/block (~16K)		*/
#define MAXOUT		1024			/* The maximum length of an output line	*/
#define	MAXCOM		1024			/* Maximum size of a single command		*/
#define MAXSUB		256				/* Maximum size of a sub format string	*/
#define FRAGBLOCK	8192			/* Memory block to allocate in mymalloc */
#define FRAGTHRESH	200				/* Threshold for mem reqs in mymalloc	*/
#define BUFSIZE		8192			/* Maximum size of output buffer		*/
#define MAXEXPR		100				/* Max number of items in an expression	*/
#define MAXDIRENT	1000			/* Maximum number of unknown dir files	*/
#define DIRFRAG		100				/* Number of dir entries/block alloced	*/
#define DIRNAMESIZE	80				/* Maximum length of directory name		*/
#define MACROLEN	20				/* Maximum length of macro name			*/
#define MAXMACRO	50				/* Maximum number of macros allowed		*/
#define MAXNEST		10				/* Max number of macro nesting levels	*/
#define MAXCONST	20				/* Maximum length of a constant name	*/

/* Note: MAXSUB above is allocated on the stack, so don't make it too big */

/*
 *		This structure is used to build a tree structure representing
 *		the expression given with the SELECT command.
 */
struct expr {
	int		field;			/* Field to test, or boolean operator	*/
	int		op;				/* Operator to test against, if any		*/
	int		num;			/* First data field						*/
	char	*text;			/* Second data field					*/
	struct	expr *left;		/* Left subtree							*/
	struct	expr *right;	/* Right subtree						*/
};

typedef struct expr EXPR;

/*
 *		This structure is used to hold the name of a file found in
 *		a BBS-PC! file directory during CHECKFILES, which does not
 *		exist in the BBS-PC! file catalogue.
 */
typedef struct {
	char	name[32];		/* Disk filename						*/
	short	date;			/* In BBS-PC! format, max 16 bits		*/
	short	dirnum;			/* The directory number it was in		*/
	long	size;			/* The size of the file, in bytes		*/
} DIRENTRY;

#define DIRENTRYSIZE	sizeof(DIRENTRY)

/*
 *		This structure holds the names of files to be "ignored" during a
 *		CHECKFILES. I.e. they are marked as valid, even if their filesize
 *		on disk doesn't match that in the file catalogue. This structure
 *		is built up with the IGNORE command.
 */
struct ignore {
	struct ignore *next;
	char name[CAT_LEN+1];
};

typedef struct ignore IGNORE;

/*
 *		This structure is used to store macro definitions. Note that
 *		a single block is used to store both the macro and its definition.
 *		The structure is dynamically sized at runtime, to fit whatever
 *		size definition is given. The text[] array (nominally 1) gets
 *		expanded to hold the definition.
 */
typedef struct {
	char	name[MACROLEN];	/* Name of this macro					*/
	int		size;			/* Size of macro text		 			*/
	char	text[1];		/* Start of macro text					*/
} MACRO;

#define MACROSIZE		(sizeof(MACRO) - 1)		/* The -1 is for text[1] */

/*
 *		This structure holds a block of parameters for a macro that is
 *		executing.
 */
typedef struct {
	int		size;			/* Size of parameter block				*/
	char	params[1];		/* Start of parameter block				*/
} PARAM;

#define PARAMSIZE		(sizeof(PARAM) - 1)		/* The -1 is for params[1] */


/*
 *		This macro checks to make sure that the file database has been
 *		read in. This is delayed until as late as possible, so that if
 *		the script file contains errors, the errors will be spotted BEFORE
 *		the database is read in. The primary goal here is to save the user
 *		having to wait for 200K or so of database to be read in, just so
 *		they can see they have an error in their script. Instead, the
 *		database is only read in when a command cannot execute without
 *		having access to the files. Such commands are SORT, SCAN, LIST,
 *		CHECKFILES and FOREIGN.
 */
#define CHECKDATABASE() {if (!readfiles) readdatabase(databasename);}

/*
 *		Global variables, accessible to all modules
 */

#ifdef GLOBAL
#undef GLOBAL
#endif
#ifdef MAIN
#define GLOBAL
#else
#define GLOBAL extern
#endif

GLOBAL char *script;			/* Array for storing the script				*/
GLOBAL long scriptsize;			/* The size of the current script			*/
GLOBAL long scriptpos;			/* Position in the current script			*/
GLOBAL long linenum;			/* Line number in script file				*/
GLOBAL char out[MAXOUT];		/* Array for storing the output lines		*/
GLOBAL char combuf[MAXCOM];		/* Buffer to hold a single command			*/
GLOBAL char formatstring[MAXCOM];/* Used to store the output format string	*/
GLOBAL char databasename[256];	/* The name of the BBS-PC! file database	*/
GLOBAL char configname[256];	/* The name of the BBS-PC! config file		*/
GLOBAL char scriptname[256];	/* The name of the current script file		*/
GLOBAL UDHEAD **ptrblock;		/* Array of pointers to file records		*/
GLOBAL long numrecs;			/* The number of file headers read in		*/
GLOBAL long compos;				/* Position on the current command line		*/
GLOBAL long comlen;				/* Length of current command line			*/
GLOBAL BPTR outfile;			/* Output file (Default is stdout)			*/
GLOBAL BPTR errorfile;			/* Standard error file (screen usually)		*/
GLOBAL BPTR dirlock;			/* Lock used when scanning directories		*/
GLOBAL struct FileInfoBlock *fib;/* Global fib struct on longword boundary	*/
GLOBAL int checkfiles;			/* TRUE if file directories were scanned	*/
GLOBAL int readfiles;			/* TRUE if database file has been read in	*/
GLOBAL int toscreen;			/* TRUE if output is to screen				*/
GLOBAL int totalbytes;			/* Total number of bytes output so far		*/
GLOBAL int totalfiles;			/* Total number of files output so far		*/
GLOBAL int curbytes;			/* Number of bytes output by last LIST/SCAN	*/
GLOBAL int curfiles;			/* Number of files output by last LIST/SCAN	*/
GLOBAL int sorted;				/* True if file array has been sorted		*/
GLOBAL EXPR tree[MAXEXPR];		/* Array to hold parsed SELECT expression	*/
GLOBAL int numdirentries;		/* Number of fake directory entries			*/
GLOBAL DIRENTRY *direntries[MAXDIRENT];/* Storage for ptrs to dir entries	*/
GLOBAL char dirnames[NUM_SECT][DIRNAMESIZE];/* Storage for directory names	*/
GLOBAL CFGINFO config[1];		/* BBS-PC! Configuration file structure		*/
GLOBAL MACRO *macros[MAXMACRO];	/* Array of ptrs to macro definitions		*/
GLOBAL int nummacros;			/* Number of macros currently defined		*/
GLOBAL PARAM *params[MAXNEST];	/* Array of pointers to macro parameters	*/
GLOBAL int nestlevel;			/* Current macro nest level					*/
GLOBAL int tracemode;			/* Trace mode; TRUE if tracing enabled		*/
GLOBAL IGNORE *firstignore;		/* Pointer to first filename to ignore		*/

/*
 *		Global functions, accessible everywhere
 */

char *format();		/* Format output string from file header + format spec	*/
char *echoformat();	/* Formats output string for ECHO command				*/
char *itoa();		/* Convert integer into ASCII format					*/
char *getstring();	/* Get next string from command buffer					*/
void *mymalloc();	/* Safe memory tracker that handles out of memory 		*/
void *SafeAllocMem();/* Safe AllocMem that handles out of memory			*/
void execscript();	/* Executes all the commands in the current script		*/
void Cleanup();		/* Frees resources and exits program					*/
void chkabort();	/* Checks for Control-C, and aborts if detected			*/
void putstring();	/* Outputs string to standard I/O						*/
void flushout();	/* Flushes data buffer to output file					*/
void parse();		/* Parse command line and build expression tree			*/
void readdatabase();/* Reads in the BBS-PC! UDHEAD.DAT file database		*/
void readconfigfile();/* Reads in the BBS-PC! CFGINFO.DAT file				*/
void print();		/* Prints a string to stderr							*/
void com_select();	/* SELECT, specifies criteria for files to select		*/
void com_checkfiles();/* Scans file directories, updating catlague entries	*/
void com_sort();	/* Sorts file catalogue into a particular order			*/
void com_foreign();	/* Prints a list of all the unknown foreign files		*/
void com_norequest();/* Stop AmigaDos from putting up requesters			*/
int match();		/* Returns TRUE if record matches current selection		*/
int scandir();		/* Scans directory for files, returns TRUE if continue	*/
int sortcmp();		/* Internal routine used for sorting files				*/

/*
 *		print3()
 *		--------
 *		Prints 3 strings to standard error
 */
#define print2(s1,s2)	 (print(s1), print(s2))
#define print3(s1,s2,s3) (print(s1), print(s2), print(s3))

/*
 *		The list of identifiers used by SORT and SELECT.
 */

#define MAXINDEX 16

#define I_ANY			0
#define I_ACCESS		1
#define I_BINARY		2
#define I_COMMENT		3
#define I_DISKNAME		4
#define I_SECTION		5
#define I_ONLINE		6
#define I_LOCAL			7
#define I_NAME			8
#define I_OWNER			9
#define I_PATHNAME		10
#define I_DIRECTORY		11
#define I_DISKDIRNUM	12
#define I_VALID			13
#define I_DATE			14
#define I_SIZE			15
#define I_KSIZE			16

GLOBAL struct {
	int tag;
	char *name;
} indexes[MAXINDEX]
#ifdef MAIN
= {

{	I_ACCESS,		"ACCESS"},		/* Number of times file was accessed	*/
{	I_BINARY,		"BINARY"},		/* True if Binary, False if text		*/
{	I_COMMENT,		"COMMENT"},		/* The file comment						*/
{	I_DISKNAME,		"DISKNAME"},	/* The name of the file on disk			*/
{	I_SECTION,		"SECTION"},		/* # of the section the file is in		*/
{	I_ONLINE,		"ONLINE"},		/* True if file online					*/
{	I_LOCAL,		"LOCAL"},		/* True if file uploaded locally		*/
{	I_NAME,			"NAME"},		/* The name of the file in the catalog	*/
{	I_OWNER,		"OWNER"},		/* The name of uploader of the file		*/
{	I_PATHNAME,		"PATHNAME"},	/* Pathname to file on disk				*/
{	I_DIRECTORY,	"DIRECTORY"},	/* # of directory file is in			*/
{	I_DISKDIRNUM,	"DISKDIRNUM"},	/* # of disk directory file is in		*/
{	I_VALID,		"VALID"},		/* True if file is Valid				*/
{	I_DATE,			"DATE"},		/* The date the file was uploaded		*/
{	I_SIZE,			"SIZE"},		/* The size of the file					*/
{	I_KSIZE,		"KSIZE"}		/* The size of the file in K			*/
}
#endif
;

GLOBAL char *months[]
#ifdef MAIN
= {
	"xxx",
	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
}
#endif
;

/*
 *		Special characters that can occur in the script
 */
#define CHAR_TAB		'\t'
#define CHAR_SPACE		' '
#define CHAR_HASH		'#'
#define CHAR_NL			'\n'
#define CHAR_ESC		'\\'
#define CHAR_QUOTE		'\''
#define CHAR_QUOTES		'\"'
#define CHAR_SEMI		';'
#define CHAR_COMMA		','
#define CHAR_EQUALS		'='
#define CHAR_DOLLAR		'$'
#define CHAR_NULL		'\0'

#define CHAR_ASCEND		'+'
#define CHAR_DESCEND	'-'

/*
 *		The following symbols are used in the expression tree
 */

/*
 *		Boolean operations, which share storage with field selectors
 */

#define E_AND		30	/* <left> AND <right>	*/
#define	E_OR		31	/* <left> OR <right>	*/
#define	E_NOT		32	/* NOT <left>			*/
#define E_ALL		33	/* Always true			*/

/*
 *		Comparison operators, used for comparing record elements
 */
#define	E_EQ		34	/* Record == Value		*/
#define E_NE		35	/* Record != Value		*/
#define E_LT		36	/* Record <  Value		*/
#define E_GT		37	/* Record >  Value		*/
#define E_LE		38	/* Record <= Value		*/
#define E_GE		39	/* Record >= Value		*/

#define E_OPENPAR	40	/* Open parameter token		*/
#define E_CLOSEPAR	41	/* Close parameter token	*/

#define E_NUMBER	42	/* Any numeric value		*/
#define E_STRING	43	/* Anything in quotes		*/
#define E_END		44	/* End of command line		*/

#define E_TEXT		45	/* File is a text file		*/
#define E_REMOTE	46	/* File is a remote file	*/
#define E_INVALID	47	/* File is invalid			*/
#define E_OFFLINE	48	/* File is offline			*/


/*
 *		Wildcard special fields for strings
 */
#define tokentowild(x) ((x)+50)

#define W_OWNER		tokentowild(I_OWNER)
#define W_NAME		tokentowild(I_NAME)
#define W_DISKNAME	tokentowild(I_DISKNAME)
#define W_COMMENT	tokentowild(I_COMMENT)
