/****************************************************************************


                            -----------------
                               V I E W 8 0
                            -----------------

                                  v1.1

                          by Federico Giannici




Lettore ultraveloce di file ASCII ad 80 colonne con scroll-bar.



Da linkare con:
	BLink FROM CBack.o+tinymain.o+view.o+fasttext.o+FileFinder.o TO View80 LIB LIB:lc.lib+LIB:amiga.lib NODEBUG BATCH VERBOSE


STORIA:

	10/08/89	v0.1
					Inizio
	14/08/89	v0.2
					Font proprio
	16/08/89	v0.3
					Routine fasttext
					Gestione tastiera
	17/08/89	v0.4
					Numero di linea
				    Gestione tastiera velocizzata
					Aggiunta nuove voci al menu
					Allocazione dinamica di ffdata (-4.3K)
	23/08/89	v0.5
					Inizio preparazione Requester
					Gadget OK e CANCEL
					Eliminato bug in findlines
					Miglioramento ed eliminazione bug gestione tastiera
					ALT up e down
					Inizio routine search()
					Modifica dimensioni AutoRequest
					Elimina CARRIAGE RETURN
	27/08/89	v0.6
					Routine print()
					Aggiunta menu My Colors
					Modifica routine print()
					My Colors
	29/08/89	v0.7
					Utilizzo del Blitter (WHOW!!!)
					Modifica gestione tastiera
					Tasto AutoScroll
					Modifica gestione tastiera
	01/09/89	v0.8
					Modifica menu
					Print di una linea
					Help dei tasti
					Implementazione TAB
					Eliminazione bug in reformat
					Modifica priorita`
					Esperimenti scrollup()
					CheckMark proprio
	11/09/89	v0.9
					Apparizione fine della linea in !fastscroll
					Movimento con il mouse
					Adattamento PAL - NTSC
					Caricamento da WB
					Files da WB
					Aggiunta del Logo e by
	21/09/89	v0.A
					Toglie mouse mentre si usa la tastiera
					Ottimizzazione GetMsg()
					Settaggio margini in stampa
					Compilato con Lattice C V5.02
	05/10/89	v0.B
					Eliminazione bug nella gestione repeat tasti
					Modifiche al menu
					Opzione WordWrap
					Eliminati Dead-Lock con MENUVERIFY (solo con nopointer)
					Eliminati bug in newfile()
	11/10/89	v0.C
					Piccoli ritocchi generali
					Uso di CBack.o
	18/10/89	v0.D
					Eliminazione menu durante uso tastiera
	20/10/89	v1.0
					Eliminazione piccolo bug nella title-bar
					PRIMA RELEASE UFFICIALE
	25/10/89	v1.01
					Risolto BUG in doppio uso del requester
	02/11/89	v1.02
					FastText in assembler
					Velocizzazione scrittura
	08/11/89	v1.03
					Piccolo bug in newfile()
	11/11/89	v1.04
					Uso tasti funzione
					Funzione scrolloutframe()
					Terza velocita`: TURBO scroll
	13/11/89	v1.05
					Stampa redirezionabile
	18/11/89	v1.06
					MultiFile
					Modifiche al menu`
					Clear file
					Free Memory
					Jump to
	25/11/89	v1.07
					flashpos()
	01/12/89	v1.1
					SECONDA RELEASE UFFICIALE
	01/12/89	Adesso



****************************************************************************/


/* #include	"exec/types.h" */
/* #include	"intuition/intuition.h" */
/* #include	"libraries/dos.h" */
/* #include	"string.h" */
/* #include	"clib/macros.h" */
/* #include	"proto/exec.h" */
/* #include	"proto/dos.h" */
/* #include	"proto/graphics.h" */
/* #include	"proto/intuition.h" */

#include	"General.h"		/*   sostituisce gli include precedenti   */
#include	"workbench/startup.h"
#include	"MyRoutines/FileFinder.h"
#include	"hardware/custom.h"
#include	"hardware/blit.h"


/* #define	PROVANTSC */

#define	VERSIONE	"1.1 "		/*   Deve essere 4 caratteri   */
#define	LIBVER	33
#define	MAXFN	3
#define	FRAMELAST	(framenum-1)
#define	SEARCHLEN	(30+1)		/*   Lunghezza search string   */
#define	LINELEN	(7+1)		/*   Lunghezza gadgets numero di linea   */
#define	SENDTOLEN	(40+1)
#define	DELTAFRAME	(framenum*3)	/* numero massimo di linee oltre cui fare outframe()   */
#define	SDELTAFRAME	(framenum+framenum/2)
#define	DOUBLECLICK	400000		/*   DoubleClick in 0.4 secondi   */
#define	REPDELAY	15		/*   Ritardo repeat dei tasti   */

#define	IDCMPFLAGS	(GADGETDOWN | GADGETUP | MENUPICK | RAWKEY | MOUSEBUTTONS | MOUSEMOVE)
#define	WINDOWW	640
#define	MEDSCREEN	(framenum<<2)
#define	MESSW	290
#define	MESSH	75
#define	GADGETH	11
#define	MENUCAR	40
#define	MENUW	(MENUCAR*8)		/*   Largezza del menu   */
#define	MENUH	(116+14*4+2+11+2)
#define	MENUL	(56+8)
#define	ITEMB	5		/*   Distanza degli item dal bordo   */
#define	ITEMB2	4		/*   Distanza delle scritte dal item box   */
#define	ITEMW	(MENUW-ITEMB*2)		/*   Largezza  degli item   */
#define	SITEMW	(ITEMW/2-1-8)		/*   Larghezza item piccoli   */
#define	SITEMT	111		/*   Inizio piccoli item   */
#define	SITEMD	12		/*   Distanza piccoli item   */
#define	ITEMGAP	3		/*   Distanza piccoli item e check item   */
#define	ITEMGAP2	2
#define	INFOT	0
#define	REQW	300
#define	REQH	90
#define	HREQW	500		/*   Requester Help   */
#define	HREQH	184
#define	OKGW	29
#define	CANCELGW	76
#define	REQGW	(90)
#define	REQGH	(11+2)
#define	REQGL	(6+12)
#define	REQGB	(-3-REQGH-4)
#define	PRINTGL	30
#define	HELPL	((HREQW-54*8)/2)
#define	HELPTT	23
#define	HELPTD	8		/*   distanza elementi help   */
#define	HELPG	1
#define	FREEMLEN	13
#define	FREEMT	(HREQH-8-8)

#define	UPID	1		/*   ID dei Gadgets   */
#define	DOWNID	2
#define	PROPID	3
#define	SEARCHID	10
#define	PRINTID		20
#define	FROMID		21
#define	TOID		22
#define	JUMPTOID		30
#define	CANCELID	100
#define	OKID		101		/*   ridefinito ogni volta   */

#define	MINX	0		/*   limiti area testo   */
#define	MINY	1
#define	MAXX	(MINX+WINDOWW-1)
#define	MAXY	(MINY+framenum*8-1)

#define	FLASHDELAY	3		/*   Usati da flashpos()   */
#define	FLASHREPEAT	2

#define	RAWUP		0x4c		/*   RAWKEY codes   */
#define	RAWDOWN		0x4d
#define	RAWRIGHT	0x4e
#define	RAWLEFT		0x4f
#define	RAWSPACE	0x40
#define	RAWHELP		0x5F
#define	RAWF1		0x50
#define	RAWF3		0x52
#define	RAWF4		0x53
#define	RAWF5		0x54
#define	RAWF6		0x55
#define	RAWF7		0x56
#define	RAWF8		0x57
#define	RAWF9		0x58
#define	RAWF0		0x59
#define	ALTMASK		(IEQUALIFIER_LALT | IEQUALIFIER_RALT)
#define	SHIFTMASK	(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)

#define	MOVEASC		0		/*   bltmove ascendente   */
#define	MOVEDISC	BC1F_DESC		/*   bltmove discendente   */

#define	BITMAPADD(l)	(bitmapstart+(l)*80*8)		/*   indirizzo linea l (da 0)   */
#define	TOLOW(c)	(((c)>='A' && (c)<='Z')?((c)+('a'-'A')):(c))
#define	ISSPACE(c)	((c)==' ' || (c)==9)


#include	"viewdata.c"


/*****   Le mie Proto   *****/
void newfile( BOOL formatonly );
void findlines( struct linee *linee);
void numcpy( UBYTE *to, LONG numero );
void makebartext( void );
void changefn( UWORD newfn );
void bltclear( UBYTE *add, UWORD lines );
void bltmove( UBYTE *from, UBYTE *to, UWORD lines, UWORD dir );
extern void __asm fasttext( register __a0 struct line *line, register __a1 UBYTE *tostart );
void outframe( LONG newpos );
void scrolloutframe( LONG newpos );
void scrollup( void );
void scrolldown( void );
void up( void );
void down( void );
void setprop( void );
void showreverse( LONG line );
void flashpos( void );
void search( void );
void print( LONG from, LONG to );
void helpkeys( void );
void openall( void );
LONG mygetmsg( void );
LONG messaggio2( UBYTE *testo, UBYTE *positivo, UBYTE*negativo );
void messaggio( UBYTE *testo );
void outs( UBYTE *text );
void fine( UBYTE *text );


extern	struct	Custom	__far	custom;
extern	struct	WBStartup	*WBenchMsg;

UWORD	framenum=29;		/*   numero di linee in un frame   */
struct	Window		*window=NULL;
struct	RastPort	*rp, *barrp;
struct	ViewPort	*vp;
struct	Screen		*screen=NULL;
struct	IntuitionBase	*IntuitionBase=NULL;
struct	GfxBase		*GfxBase=NULL;
struct	Process		*process=NULL;		/*   per i messaggi ADOS   */
APTR	adoswin;
BOOL	autoload=FALSE;
BPTR	lock=NULL;
BPTR	file=NULL;
struct	FileInfoBlock	*fib=NULL;

UWORD	fn=0;		/*   File Number attuale (0-2)   */
UBYTE	filenamefn[MAXFN][ 30+1 ];		/*   nome del file in memoria   */
UBYTE	*bufferfn[MAXFN]={NULL, NULL, NULL};
LONG	blenfn[MAXFN];
struct	line	*linepfn[MAXFN]={NULL, NULL, NULL};
LONG	linenumfn[MAXFN];		/*   Numero di linee (vedi linenum)   */
LONG	posfn[MAXFN];		/*   Linea corrente (vedi pos)   */
LONG	markfn[MAXFN][ 2 ];			/*   Mark F4-F5   */
LONG	printposfn[MAXFN][ 2 ];		/*   Prima e ultima linea di stampa F6-F7   */
BOOL	wordwrapfn[MAXFN]={FALSE, FALSE, FALSE};
UBYTE	tabfn[MAXFN]={0, 0, 0};		/*   Tab==none   */

LONG	pos;		/*   Per ridurre e velocizzare il codice   */
LONG	linenum;
struct	line	*linep=NULL;
BOOL	wordwrap=FALSE;
UBYTE	tab=0;

LONG	newpos, oldpos;
UBYTE	printername[]="prt:";
UWORD	propbody;
BOOL	fastscroll;
BOOL	turboscroll;
UBYTE	*tempbitmap=NULL;		/*   Buffer per la scrittura della linea   */
BOOL	nopointer=FALSE;
BOOL	clearmsg=FALSE;
WORD	olddheight;
UBYTE	*bitmapstart;

UBYTE	*bma1, *bma2, *bma3, *bma4, *bma5, *bma6, *bma7;
UWORD	cos1, cos2;

struct	IntuiMessage	*msg;
ULONG	class;
UWORD	code;
UWORD	qualifier;
ULONG	seconds, micros;
struct	Gadget	*gadget;

struct	ffdata	data;

/*****   Questi sono necessari per CBack.o   *****/
long 	_stack = 4000;             /* a reasonable amount of stack space */
char 	*_procname = "View80";
long 	_priority = 0;             /* run at standard priority */
long 	_BackGroundIO = 1;         /* perform background I/O */
extern 	BPTR 	_Backstdout;       /* file handle we will write to with */



/**************   MAIN   **************/
main( LONG argc, UBYTE **argv)
{
	LONG	oldseconds=0, oldmicros=0;
	WORD	y;		/*   usato in MOUSEBUTTONS   */
	BYTE	ritardo;
	COUNT	i;
	BOOL	dosetprop;		/*   usato dal TURBO scroll   */

	SetTaskPri( FindTask(NULL), 1 );

	if( (fib=AllocMem( sizeof(struct FileInfoBlock), MEMF_PUBLIC ))==NULL )
		fine( "No memory for FIB" );
	if( (tempbitmap=AllocMem( 80*8, MEMF_CHIP | MEMF_PUBLIC ))==NULL )
		fine( "No memory for TempBitMap" );

	openall();

	if( argc>MAXFN+1 || (argc==0 && WBenchMsg->sm_NumArgs>MAXFN+1) )
		messaggio( "I cannot load more than 3 files" );
	if( argc==1 || (argc==0  && WBenchMsg->sm_NumArgs==1) )		/*   niente argomenti   */
		newfile( FALSE );		/*   autoload=FALSE   */
	else if( argc>1 )
		{
		for( i=0; i<argc-1 && i<MAXFN; i++ )
			{
			if( strlen(argv[i+1])>=sizeof(data.complete) )
				messaggio( "Argument too long" );
			else
				{
				changefn( i );
				strcpy( data.complete, argv[i+1] );
				autoload=TRUE;
				newfile( FALSE );
				}
			}
		changefn( 0 );
		}
	else
		{
		for( i=0; i<WBenchMsg->sm_NumArgs-1 && i<MAXFN; i++ )
			{
			changefn( i );
			CurrentDir( (WBenchMsg->sm_ArgList+i+1)->wa_Lock );
			strcpy( data.complete, (WBenchMsg->sm_ArgList+i+1)->wa_Name );
			autoload=TRUE;
			newfile( FALSE );
			}
		changefn( 0 );
		}

	FOREVER     /* Main Loop */
		{
		if( pos!=oldpos && linenum )		/*   aggiorna la title bar   */
			{
			strncpy( &bartext[ BTLINE ], "      ", BTLINELEN );
			numcpy( &bartext[ BTLINE ], pos+1 );
			SetAPen( barrp, 3 );
			Move( barrp, (BTLINE)*8+5, 6+1 );
			Text( barrp, &bartext[ BTLINE ], BTLINELEN );
			oldpos=pos;
			}

		if( clearmsg )
			{
			while( mygetmsg () )
				;
			clearmsg=FALSE;
			}
		window->Flags &= ((ULONG)-1)^RMBTRAP;		/*   Ripristina menu   */
		WaitPort( window->UserPort );
		mygetmsg();
		window->Flags |= RMBTRAP;		/*   Elimina menu   */
		turboscroll=FALSE;

		switch( class )
			{
			case MENUPICK:
				while( code!=MENUNULL )
					{
					switch( ITEMNUM( code ) )
						{
						case 2:     /* newfile */
							newfile( FALSE );
							break;
						case 3:     /* quit */
							if( messaggio2( quitstr, " Yes ", " No " )==TRUE )
								fine( NULL );
							break;
						case 4:		/*   Search   */
							requester.ReqGadget=&searchgadg;
							requester.ReqText=&searchtext;
							okGadg.GadgetID=SEARCHID;
							if( Request( &requester, window )==TRUE )
								{
								Delay( 6 );
								ActivateGadget( &searchgadg, window, &requester );
								clearmsg=TRUE;
								}
							else
								messaggio( noreqstr );
							break;
						case 5:		/*   Search Next   */
							search();
							break;
						case 6:		/*   Print   */
							if( linenum==0 )
								{
								messaggio( nofilestr );
								break;
								}
							fromgstrinfo.LongInt=printposfn[fn][0];
							stci_d( frombuff, printposfn[fn][0] );
							togstrinfo.LongInt=printposfn[fn][1];
							stci_d( tobuff, printposfn[fn][1] );
							fromgstrinfo.DispPos=0;
							togstrinfo.DispPos=0;
							requester.ReqGadget=&fromgadg;
							requester.ReqText=&printtext;
							okGadg.GadgetID=PRINTID;
							if( Request( &requester, window )==TRUE )
								{
								Delay( 6 );
								ActivateGadget( &fromgadg, window, &requester );
								clearmsg=TRUE;
								}
							else
								messaggio( noreqstr );
							break;
						case 7:		/*   Print line   */
							if( linenum==0 )
								{
								messaggio( nofilestr );
								break;
								}
							print( pos, pos );
							fastscroll=TRUE;
							down();
							break;
						case 8:		/*   Jump to   */
							jumptogstrinfo.LongInt=0;
							jumptobuff[0]='\0';
							requester.ReqGadget=&jumptogadg;
							requester.ReqText=&jumptotext;
							okGadg.GadgetID=JUMPTOID;
							if( Request( &requester, window )==TRUE )
								{
								Delay( 6 );
								ActivateGadget( &jumptogadg, window, &requester );
								clearmsg=TRUE;
								}
							else
								messaggio( noreqstr );
							break;
						case 9:		/*   Clear file   */
							if( linenum )
								{
								FreeMem( linep, sizeof(struct line)*linenum );
								FreeMem( bufferfn[fn], blenfn[fn] );
								pos=posfn[fn]=0;
								linenum=linenumfn[fn]=0;
								linep=linepfn[fn]=0;
								outframe( 0 );
								makebartext();
								propbody=0xFFFF;
								setprop();
								markfn[fn][0]=markfn[fn][1]=0;
								}
							break;
						case 10:		/*   My colors   */
							LoadRGB4( vp, colormap, 4 );
							break;
						case 11:		/*   Help keys   */
							helpkeys();
							break;
						case 12:
						case 13:
						case 14:
							changefn( (UWORD)(ITEMNUM( code )-12) );
							break;
						case 15:		/*   WordWrap   */
						case 16:
							wordwrap=ITEMNUM( code )==15 ? FALSE : TRUE;
							newfile( TRUE );
							break;
						case 17:		/*   Tabs   */
						case 18:
						case 19:
						case 20:
						case 21:
							tab=ITEMNUM( code )-17;
							if( tab )
								tab=(1<<(tab-1));
							newfile( TRUE );
							break;
						default:
							fine( "INTERNAL ERROR #3" );
						}
					code=ItemAddress( &menu, code )->NextSelect;
					}
				break;

			case GADGETDOWN:
				switch( code )
					{
					case UPID:     /* up */
					case DOWNID:     /* down */
						fastscroll=(((seconds-oldseconds)<=1) && ((seconds-oldseconds)*1000000+(micros-oldmicros)<DOUBLECLICK) ?
									TRUE : FALSE);
						oldseconds=seconds;
						oldmicros=micros;
						do
							{
							if( code==UPID )
								up();
							else
								down();
							}while( gadget->Flags & SELECTED );
						break;
					case PROPID:     /* scroll bar */
						fastscroll=TRUE;
						turboscroll=TRUE;
						do
							{
							newpos=linenum>framenum ? ((ULONG)(linenum-framenum)*propinfo.HorizPot+(1<<15))>>16 : 0;
							if( newpos!=pos )
								{
								if( ABS(newpos-pos)>=DELTAFRAME )
									outframe( newpos );
								else
									if( newpos>pos )
										scrolldown();
									else
										scrollup();
								}
							}while( propgadg.Flags & SELECTED );
							scrolloutframe( linenum>framenum ? ((ULONG)(linenum-framenum)*propinfo.HorizPot+(1<<15))>>16 : 0 );
						break;
					default:
						fine( "INTERNAL ERROR #4" );
					}
				break;

			case GADGETUP:
				switch( code)
					{
					case SEARCHID:
						search();
						break;
					case PRINTID:
						{
						LONG	from, to;
						from=fromgstrinfo.LongInt-1;
						to=togstrinfo.LongInt-1;
						if( from>to || from<0 || to>=linenum )
							messaggio( "Invalid range of lines" );
						else
							print( from, to);
						}
						break;
					case FROMID:
						ActivateGadget( &togadg, window, &requester );
						break;
					case TOID:
						ActivateGadget( &sendtogadg, window, &requester );
						break;
					case JUMPTOID:
						{
						LONG	line=jumptogstrinfo.LongInt-1;
						if( line!=-1 )
							if( line<0 || line>=linenum )
								messaggio( "Line number out of range" );
							else
								if( line>linenum-framenum )
									showreverse( line );
								else
									scrolloutframe( line );
						}
						break;
					case CANCELID:
					case UPID:
					case DOWNID:
						break;		/*   Ignorali   */
					default:
						fine( "INTERNAL ERROR #5" );
					}
				break;

			case RAWKEY:
				if( helprequester.Flags & REQACTIVE )
					{
					if( code<128 )
						EndRequest( &helprequester, window );
					break;
					}
				if( code==RAWHELP )
					helpkeys();
				if( code>=RAWF1 && code<=RAWF3 )
					changefn( (UWORD)(code-RAWF1) );
				if( code==RAWF4 || code==RAWF5 )
					{
					UBYTE	i=code-RAWF4;
					if( qualifier & SHIFTMASK )
						{
						markfn[fn][i]=pos;
						flashpos();
						}
					else
						scrolloutframe( markfn[fn][i] );
					}
				if( code==RAWF6 || code==RAWF7 )
					{
					printposfn[fn][ code-RAWF6 ]=pos+1;
					flashpos();
					}
				if( code==RAWF8 )
					search();
				if( code==RAWF9 )
					newfile( FALSE );
				if( code==RAWF0 )
					if( messaggio2( quitstr, " Yes ", " No " )==TRUE )
						fine( NULL );
				if( code!=RAWSPACE && (code<RAWUP || code>RAWLEFT) )
					break;
				if( nopointer==FALSE )		/*   Elimina il pointer   */
					{
					SetPointer( window, pointerdata, 0, 0, 0, 0 );
					ReportMouse( window, TRUE );
					ModifyIDCMP( window, IDCMPFLAGS | MENUVERIFY );
					nopointer=TRUE;
					}
				if( qualifier & ALTMASK )
					turboscroll=TRUE;
				fastscroll=(qualifier & SHIFTMASK) || turboscroll ? TRUE : FALSE;
				if( code==RAWSPACE )
					{
					if( pos+framenum<linenum )
						{
						do
							{
							down();
							while( (mygetmsg() && class!=RAWKEY) || (msg && class==RAWKEY && code!=RAWSPACE) )
								;
							}while( pos+framenum<linenum && !(msg && class==RAWKEY && code==RAWSPACE) );
						if( turboscroll )
							setprop();
						}
					else
						DisplayBeep( screen );
					break;
					}
				ritardo=((code==RAWLEFT || code==RAWRIGHT) && !(qualifier & ALTMASK || qualifier & SHIFTMASK)) ? 0 : 1;
				dosetprop=turboscroll && (code==RAWUP || code==RAWDOWN) ? TRUE :FALSE;
				do
					{
					switch( code )
						{
						case RAWDOWN:
							down();
							break;
						case RAWUP:
							up();
							break;
						case RAWLEFT:
							if( turboscroll )
								{
								scrolloutframe( 0 );
								break;
								}
							if( pos )
								{
								if( fastscroll )
									for( i=0; i<framenum-1; i++ )
										{
										up();
										if( pos==0 )
											break;
										}
								else
									{
									outframe( MAX( pos-(framenum-1), 0 ) );
									setprop();
									}
								}
							else
								DisplayBeep( screen );
							break;
						case RAWRIGHT:
							if( turboscroll )
								{
								scrolloutframe( MAX( 0, linenum-framenum ) );
								break;
								}
							if( pos+framenum<linenum )
								{
								if( fastscroll )
									for( i=0; i<framenum-1; i++ )
										{
										down();
										if( pos+framenum>=linenum )
											break;
										}
								else
									{
									outframe( MIN( pos+(framenum-1), linenum-framenum ) );
									setprop();
									}
								}
							else
								DisplayBeep( screen );
							break;
						}
					if( !ritardo )
						for( ; ritardo<REPDELAY; ritardo++ )
							{
							if( mygetmsg() )
								break;
							Delay( 1 );
							}
					else
						mygetmsg();
					while( (msg && class!=RAWKEY) || (msg && class==RAWKEY && code<128) )
						mygetmsg();
					}while( msg==NULL || class!=RAWKEY || code<128 );
				if( dosetprop )
					setprop();
				break;

			case MOUSEBUTTONS:
				if( code!=SELECTDOWN )
					break;
				do
					{
					y=(window->MouseY)/8;
					fastscroll= (y<=1 || y>=framenum-2) ? TRUE : FALSE;
					if( y<(framenum/2)-1 )
						up();
					if( y>(framenum/2)+1 )
						down();
					while( mygetmsg() && class!=MOUSEBUTTONS && code!=SELECTUP )
						;
					}while( !msg || class!=MOUSEBUTTONS || code!=SELECTUP);
				break;

			case MOUSEMOVE:		/*   Servono solo per ripristinare il pointer   */
			case MENUVERIFY:
				break;

			default:
				fine( "INTERNAL ERROR #2" );
				break;
			}
		}
}


/*****   Carica un nuovo file   *****/
void newfile( BOOL formatonly )
{	
	LONG	errore;

	OffGadget( &Imml1Gadg, window, NULL );
	OffGadget( &Immr1Gadg, window, NULL );
	OffGadget( &propgadg, window, NULL );

	for(;;)
		{
		if( formatonly )
			{
			goto format;
			}

		if( lock )     /* in caso di errore */
			{
			UnLock( lock );
			lock=NULL;
			}
		if( file )
			{
			Close( file );
			file=NULL;
			}

		if( autoload==FALSE )
			{
			errore=filefinder( &data );			
			if( errore==FFERROR )
				{
				messaggio( "FileFinder error!" );
				goto newfileend;
				}
			if( errore==FFCANCEL )
				goto newfileend;
			}
		else
			autoload=FALSE;

		if( (lock=Lock( data.complete, ACCESS_READ ))==NULL )
			{
			if( IoErr()==ERROR_OBJECT_NOT_FOUND )
				messaggio( "File not found" );
			else
				messaggio( "Cannot make lock" );
			continue;
			}
		if( Examine( lock, fib )==NULL )
			{
			messaggio( "Cannot Examine" );
			continue;
			}
		if( fib->fib_DirEntryType>0 )
			{
			messaggio( "It's a directory!" );
			continue;
			}
		UnLock( lock );
		lock=NULL;
		if( fib->fib_Size==0 )
			{
			messaggio( "That file is empty!" );
			continue;
			}
		if( (file=Open( data.complete, MODE_OLDFILE ))==NULL )
			{
			messaggio( "Cannot Open file" );
			continue;
			}

		RectFill( rp, MINX, MINY, MAXX, MAXY );
		PrintIText( rp, &waittext, 0, MEDSCREEN );

				/* cancella vecchio buffer */
		if( linenum )
			{
			FreeMem( linep, sizeof(struct line)*linenum );
			FreeMem( bufferfn[fn], blenfn[fn] );
			linenum=0;
			}
				/*   leggi quello nuovo   */
		blenfn[fn]=fib->fib_Size;
		if( (bufferfn[fn]=AllocMem( blenfn[fn], NULL ))==NULL )
			{
			messaggio( "No memory for buffer" );
			continue;
			}
		if( Read( file, bufferfn[fn], blenfn[fn] )!=blenfn[fn] )
			{
			messaggio( "Cannot Read file" );
			FreeMem( bufferfn[fn], blenfn[fn] );
			continue;
			}
		Close( file );
		file=NULL;
		strcpy( filenamefn[fn], fib->fib_FileName );

format:
		RectFill( rp, MINX, MINY, MAXX, MAXY );
		PrintIText( rp, &formattext, 0, MEDSCREEN );
		if( formatonly && linenum )
			{
			FreeMem( linep, sizeof(struct line)*linenum );
			linenum=0;
			}
		formatonly=FALSE;
		findlines( NULL );     /* linenum e` 0 */
		if( linenum )
			{
			if( (linep=AllocMem( sizeof(struct line)*linenum, 0 ))==NULL )
				{
				messaggio( "No memory for index" );
				FreeMem( bufferfn[fn], blenfn[fn] );
				linenum=0;
				continue;
				}
			findlines( linep );
			}
		break;		/*   esce dal ciclo di richiesta file \/   */
		}
	markfn[fn][0]=0;		/*   Top of file   */
	markfn[fn][1]= linenum-framenum>0 ? linenum-framenum : 0;		/*   End of file   */
	printposfn[fn][0]=1;
	printposfn[fn][1]=linenum;

newfileend:		/*   routine di uscita   */
	makebartext();
	outframe( 0 );
	propbody=linenum>framenum ? (ULONG)(framenum*0xFFFF)/linenum : 0xFFFF;
	setprop();
	posfn[fn]=pos;
	linenumfn[fn]=linenum;
	linepfn[fn]=linep;

	OnGadget( &Imml1Gadg, window, NULL );
	OnGadget( &Immr1Gadg, window, NULL );
	OnGadget( &propgadg, window, NULL );
}

/*****   Trova gli inizi e le lunghezze delle linee   *****/
/*****   se linep!=NULL memorizza i dati   *****/
void findlines( struct line *linep)
{
	UBYTE	*p, *add, *lastspace=NULL;
	UBYTE	c;
	UBYTE	llen=0, plen=0;
	ULONG	oldlinenum;
	UBYTE	*plim=bufferfn[fn]+blenfn[fn];
	struct	line	*linepact=linep;

	oldlinenum=linenum;
	linenum=0;
	for( p=add=bufferfn[fn]; p<plim; p++ )
		{
		c=*p;
		if( wordwrap && plen>=80 && c!='\n' && !(c==0x0D && p+1<plim && *(p+1)=='\n') )
			{
			if( ISSPACE(c) || lastspace>add )
				{
				if( !ISSPACE(c) )
					{
					p=lastspace;
					llen=p-add;
					}
				while( ISSPACE(*p) )
					p++;
				p--;
				c='\n';
				}
			}		/*   prossimo test soddisfatto (plen>=80)   */
		if( c=='\n' || plen>=80 || (c==0x0D && p+1<plim && *(p+1)=='\n') )
			{
			if( linep )
				{
				linepact->add=add;
				linepact->len=llen;
				linepact++;
				}
			if( c==0x0D )
				c=*(++p);
			if( c=='\n' )
				{
				add=p+1;
				llen=plen=0;
				}
			else
				{
				add=p;
				llen=plen=1;
				}
			linenum++;
			}
		else if( c==9 && tab )
			{
			plen+=(tab-(plen%tab));
			llen++;
			}
		else
			{
			llen++;
			plen++;
			}
		if( wordwrap && ISSPACE(c) )
			lastspace=p;
		}
	if( llen )		/*   ultima linea non termina con \n   */
		{
		if( linep )
			{
			linepact->add=add;
			linepact->len=llen;
			}
		linenum++;
		}

	if( oldlinenum && oldlinenum!=linenum )
		fine( "INTERNAL ERROR #1" );
}


/*****   Scrive un numero all'indirizzo to, niente NULL alla fine   *****/
void numcpy( UBYTE *to, LONG numero )
{
	UBYTE	buff[ 12 ];

	stci_d( buff, numero );
	strncpy( to, buff, strlen(buff) );
}


/*****   Costruisce e visualizza la nuova BarText   *****/
void makebartext( void )
{
	strcpy( bartext, defbartext );
	if( linenum )
		{
		strncpy( &bartext[ BTFILE ], filenamefn[fn], MIN( strlen(filenamefn[fn]), BTFILELEN ) );
		numcpy( &bartext[ BTSIZE ], blenfn[fn] );
		numcpy( &bartext[ BTLINES ], linenum );
		oldpos=-1;		/*   Mostra il numero di linea   */
		}
	else
		{
		strcpy( &bartext[ BTFILE+11 ], "--== No File Loaded ==--" );
		}
	bartext[ BTFN ]='1'+fn;
	ShowTitle( screen, TRUE );
}


/*****   Cambia FileNumber   *****/
void changefn( UWORD newfn )
{
	COUNT	i;
	struct	MenuItem	*item;

	if( newfn!=fn )
		{
		posfn[fn]=pos;		/*   linenumfn e linepfn sono modificati   */
		tabfn[fn]=tab;		/*   e aggiornati solo da newfile()   */
		wordwrapfn[fn]=wordwrap;
		fn=newfn;
		pos=posfn[fn];
		linenum=linenumfn[fn];
		linep=linepfn[fn];
		tab=tabfn[fn];
		wordwrap=wordwrapfn[fn];
		outframe( pos );
		makebartext();
		oldpos=-1;
		propbody=linenum>framenum ? (ULONG)(framenum*0xFFFF)/linenum : 0xFFFF;
		setprop();
		/*   Aggiorna il menu`   */
		ClearMenuStrip( window );
		for( i=0, item=&item12; i<MAXFN; i++, item=item->NextItem )
			if( i==fn )
				item->Flags|=CHECKED;
			else
				item->Flags&=((USHORT)-1)^CHECKED;
		if( wordwrap )
			{
			item15.Flags&=((USHORT)-1)^CHECKED;
			item16.Flags|=CHECKED;
			}
		else
			{
			item15.Flags|=CHECKED;
			item16.Flags&=((USHORT)-1)^CHECKED;
			}
		if( !tab )
			item17.Flags|=CHECKED;
		else
			item17.Flags&=((USHORT)-1)^CHECKED;
		for( i=1, item=&item18; i<=8; i*=2, item=item->NextItem )
			if( i==tab )
				item->Flags|=CHECKED;
			else
				item->Flags&=((USHORT)-1)^CHECKED;
		SetMenuStrip( window, &menu );
		}
}


/*****   Azzeramento di memoria con Blitter   *****/
/*****   ipotizza possesso del blitter e WaitBlit()   *****/
void bltclear( UBYTE *add, UWORD lines )
{
	custom.bltdpt=(APTR)add;
	custom.bltdmod=0;
	custom.bltcon0=BC0F_DEST;
	custom.bltcon1=0;
	custom.bltafwm=0xFFFF;
	custom.bltalwm=0xFFFF;
	custom.bltsize=(80/2) | (lines<<6);
}


/*****   Spostamento di memoria con Blitter   *****/
/*****   ipotizza possesso del blitter e WaitBlit()   *****/
void bltmove( UBYTE *from, UBYTE *to, UWORD lines, UWORD dir )
{
	custom.bltapt=(APTR)from;
	custom.bltdpt=(APTR)to;
	custom.bltamod=0;
	custom.bltdmod=0;
	custom.bltcon0=A_TO_D | BC0F_DEST | BC0F_SRCA;
	custom.bltcon1=dir;
	custom.bltafwm=0xFFFF;
	custom.bltalwm=0xFFFF;
	custom.bltsize=(80/2) | (lines<<6);
}


/*****   La prossima routine e` stata sostituita in assembler dalla v1.1   *****/

/*****   Rotine di scrittura veloce   *****/
/*
void fasttext( struct line *li, UBYTE *tostart )
{
	register	UBYTE	*to;
	register	UBYTE	*from;
	UBYTE	*p=li->add;
	UBYTE	*plim=p+li->len;
	UBYTE	i;
	UBYTE	*tostart2=tostart;

	for( ; p<plim; p++ )
		{
		if( *p==9 && tab )
			tostart+=tab-(tostart-tostart2)%tab;
		else
			{
			from=(UBYTE *)CharData+*p;
			to=tostart++;
			for( i=0; i<8; i++ )
				{
				*to=*from;
				to+=80;
				from+=256;
				}
			}
		}
}
*/


/*****   Mostra tutto uno schermo da pos    *****/
void outframe( LONG newpos )
{
	UBYTE	i;
	struct	line	*line=linep+newpos;
	UBYTE	*add=BITMAPADD(0);

	OwnBlitter();
	WaitBlit();
	bltclear( BITMAPADD(0), (UWORD)(framenum*8) );
	WaitBlit();	
	for( i=0; i<framenum && newpos+i<linenum; i++, line++, add+=80*8 )
		fasttext( line, add );
	DisownBlitter();
	pos=newpos;
}

/*****   Mostra tutto uno schermo da pos possibilmente facendo lo scroll    *****/
void scrolloutframe( LONG newpos )
{
	COUNT	i=ABS(newpos-pos);

	if( !i ) return;
	if( i>SDELTAFRAME )
		outframe( newpos );
	else
		{
		fastscroll=TRUE;
		while( i-- )
			{
			if( newpos>pos )
				down();
			else
				up();
			}
		}
	setprop();
}



/*****   Sale di una linea lo schermo   *****/
void scrollup( void )
{
	--pos;
	OwnBlitter();
	WaitBlit();
	bltclear( tempbitmap, 8 );
	if( fastscroll )
		{
		WaitBlit();
		bltmove( bma1, bma2, cos1, MOVEDISC );
		fasttext( linep+pos, tempbitmap );
		WaitBlit();
		bltmove( tempbitmap, BITMAPADD(0), 8, MOVEASC );
		}
	else
		{
		UBYTE	i;

		for( i=0; i<4; i++)
			{
			WaitBlit();
			vp->DHeight=olddheight-70;
			WaitBOVP( vp );
			vp->DHeight=olddheight;
			bltmove( bma3, bma2, cos2, MOVEDISC );
			if( i==0 )
				fasttext( linep+pos, tempbitmap );
			WaitBlit();
			bltmove( bma4-i*2*80, BITMAPADD(0), 2, MOVEASC );
			}
		}
	DisownBlitter();
}


/*****   Scende di una linea lo schermo   *****/
void scrolldown( void )
{
	++pos;
	OwnBlitter();
	WaitBlit();
	bltclear( tempbitmap, 8 );
	if( fastscroll )
		{
		WaitBlit();
		bltmove( bma5, BITMAPADD(0), cos1, MOVEASC );
		fasttext( linep+(pos+FRAMELAST), tempbitmap );
		WaitBlit();
		bltmove( tempbitmap, bma6, 8, MOVEASC );
		}
	else
		{
		UBYTE	i;
		UBYTE	*tbm;

		for( i=0, tbm=tempbitmap; i<4; i++, tbm+=2*80)
			{
			WaitBlit();
			WaitBOVP( vp );
			bltmove( BITMAPADD(0)+80*2, BITMAPADD(0), cos2, MOVEASC );
			if( i==0 )
				fasttext( linep+(pos+FRAMELAST), tempbitmap );
			WaitBlit();
			bltmove( tbm, bma7, 2, MOVEASC );
			}
		}
	DisownBlitter();
}


/*****   Muovi in alto, se puoi ed aggiorna scrollbar   *****/
void up( void )
{
	if( linenum)
		if( pos )
			{
			scrollup();
			if( !turboscroll)
				setprop();
			}
		else
			DisplayBeep( screen );
}


/*****   Muovi in basso, se puoi ed aggiorna scrollbar   *****/
void down( void )
{
	if( linenum )
		if( pos+framenum<linenum )
			{
			scrolldown();
			if( !turboscroll )
				setprop();
			}
		else
			DisplayBeep( screen );
}


/*****   Setta body e pot della scroll bar   *****/
void setprop( void )
{
	UWORD  pot;

	pot=linenum>framenum ? MIN( 0xFFFF, ((pos<<16))/(linenum-framenum)) : 0;
	NewModifyProp( &propgadg, window, NULL, propinfo.Flags, pot, 0, propbody, 0, 1 );
}


/*****   Fa scrolloutframe() ed il reverse di una linea   *****/
void showreverse( LONG line )
{
	UBYTE	*screenadd;
	ULONG	*l;

	scrolloutframe( MIN( line, linenum-framenum ) );
	screenadd=BITMAPADD(line-pos);
	for( l=(ULONG *)screenadd; l<(ULONG *)(screenadd+80*8); l++ )
		*l=0;
	fasttext( linep+line, screenadd );
	for( l=(ULONG *)screenadd; l<(ULONG *)(screenadd+80*8); l++ )
		*l^=0xFFFFFFFF;
}


/*****   Lampeggia alla posizione attuale   *****/
void flashpos( void )
{
	COUNT	i;
	ULONG	*l;

	for( i=0; i<FLASHREPEAT; i++ )
		{
		showreverse( pos );
		Delay( FLASHDELAY );
		for( l=(ULONG *)BITMAPADD(0); l<(ULONG *)(BITMAPADD(0)+80*8); l++ )
			*l=0;
		fasttext( linep+pos, BITMAPADD(0) );
		Delay( FLASHDELAY );
		}
}


/*****   Routine di Search   *****/
void search( void )
{
	UBYTE	*p;
	WORD	slen;
	WORD	i;
	LONG	newpos;

	if( linenum==0 )
		{
		messaggio( nofilestr );
		return;
		}
	if( (slen=strlen(searchbuff))==0 )
		{
		messaggio( "Search string empty" );
		return;
		}

	for( p=searchbuff; p<searchbuff+slen; p++ )
		*p=TOLOW(*p);

	for( p=(linep+MIN(pos+1, linenum-1))->add ; p<bufferfn[fn]+blenfn[fn]; p++ )
		{
		for( i=0; i<slen; i++)
			if( searchbuff[i]!=TOLOW(*(p+i)) )
				break;
		if( i==slen )		/*   Trovato!   */
			{
			for( newpos=0; newpos<linenum; newpos++ )
				if( (linep+newpos)->add>p )
					break;
			newpos--;
			showreverse( newpos );
			return;
			}
		}
	messaggio( "Nothing found, from here" );
}


/*****   Routine di print   *****/
void print( LONG from, LONG to )
{
	BPTR	file;
	LONG	linea;
	struct	line	*lineact;
	UBYTE	c, *p, *plim;
	UBYTE	rep, i;
	UBYTE	plen;
	BOOL	printer;	
	BPTR	lock;
	LONG	mode=MODE_NEWFILE;

	for( i=0; i<4; i++ )
		if( printername[i]!=TOLOW(sendtobuff[i]) )
			break;
	printer= (i==4 ? TRUE : FALSE);

	if( !printer )
		if( (lock=Lock( sendtobuff, SHARED_LOCK ))!=NULL )
			{
			UnLock( lock );
			mode=MODE_OLDFILE;
			}
	if( (file=Open( sendtobuff, mode ))==NULL )
		{
		messaggio( "Cannot open the printer or file" );
		return;
		}
	if( !printer )
		if( Seek( file, 0, OFFSET_END )==-1 )
			{
			messaggio( "Problem with the print file" );
			goto fineprint;
			}
	if( from!=to )
		{
		requester.ReqGadget=&cancelGadg;
		requester.ReqText=&waitprinttext;
		if( Request( &requester, window )==FALSE )
			{
			messaggio( noreqstr );
			goto fineprint;
			}
		}
	if( printer )
		if( Write( file, "\x1B[1;80s", 7 )!=7 )		/*   Setta i margini   */
			{
			messaggio( priprostr );
			goto fineprint;
			}

	for( linea=from, lineact=linep+from; linea<=to; linea++, lineact++ )
		{
		if( from!=to && mygetmsg() && class==GADGETUP )
			goto fineprint;
		plen=0;
		for( p=lineact->add, plim=lineact->add+lineact->len; p<=plim; p++ )
			{
			rep=1;
			if( (c=*p)<32 )
				if( c==9 && tab )
					{
					c=' ';
					rep=tab-plen%tab;
					}
				else
					c='X';
			if( p==plim )
				c='\n';
			for( i=0; i<rep; i++ )
				{
				if( Write( file, &c, 1 )!=1 )
					{
					messaggio( priprostr );
					goto fineprint;
					}
				plen++;
				}
			}
		}

fineprint:
/* 	if( printer ) */
		/*Write( file, "\x1B#9\1B#0", 6 );*/		/*   ReSetta margini (?)   */

	if( requester.Flags & REQACTIVE )
		EndRequest( &requester, window );
	Close( file ); 
}


/*****   Stampa i tasti   *****/
void helpkeys( void )
{
	stci_d( &(helptext16.IText[FREEMLEN]), AvailMem(0) );		/*   Free Mem   */
	if( Request( &helprequester, window )==FALSE )
		messaggio( noreqstr );
	clearmsg=TRUE;
}


/*****  Apri screen e window  *****/
void openall( void )
{
	if( (IntuitionBase=(struct IntuitionBase *)OpenLibrary( "intuition.library", LIBVER ))==NULL )
		fine( "Intution.library not found" );
	if( (GfxBase=(struct GfxBase *)OpenLibrary( "graphics.library", LIBVER ))==NULL )
		fine( "Graphics.library not found" );
#ifndef PROVANTSC
	if( GfxBase->DisplayFlags & NTSC )
#endif
		{
		framenum=22;
		screendata.Height=200;
		windowdata.Height=200-11;
		requester.TopEdge=((200-11)-REQH)/2;
		helprequester.TopEdge=((200-11)-HREQH)/2;
		}
	if( (screen=(struct Screen *)OpenScreen( &screendata ))==NULL )
		fine( "Cannot open screen" );
	vp=&(screen->ViewPort);
	olddheight=vp->DHeight;
	barrp=screen->BarLayer->rp;
	SetBPen( barrp, 2 );
	data.screen=screen;
	data.title="File to load...";
	windowdata.Screen=screen;
	if( (window=(struct Window *)OpenWindow( &windowdata ))==NULL )
		fine( "Cannot open window" );
	rp=window->RPort;
	bitmapstart=rp->BitMap->Planes[0]+12*80;
	SetAPen( rp, 0 );
	SetMenuStrip( window, &menu );
			/* Messaggi AmigaDOS nella mia finestra */
	process=(struct Process *)FindTask( NULL );
	adoswin=process->pr_WindowPtr;
	process->pr_WindowPtr=(APTR)window;

		/*   definisce un po` di valori per velocizzare lo scroll   */
	bma1=BITMAPADD(framenum-1)-1;
	bma2=BITMAPADD(framenum)-1;
	bma3=bma2-80*2;
	bma4=tempbitmap+80*6;
	bma5=BITMAPADD(1);
	bma6=BITMAPADD(FRAMELAST);
	bma7=BITMAPADD(framenum)-80*2;
	cos1=(UWORD)((framenum-1)*8);
	cos2=(UWORD)(framenum*8-2);
}


/*****   Prende un messaggio, se esiste   *****/
LONG mygetmsg( void )
{
	if( msg=(struct IntuiMessage *)GetMsg( window->UserPort ) )
		{
		class=msg->Class;
		code=msg->Code;
		qualifier=msg->Qualifier;
		seconds=msg->Seconds;
		micros=msg->Micros;
		if( class==GADGETDOWN || class==GADGETUP )
			{
			gadget=(struct Gadget *)msg->IAddress;
			code=gadget->GadgetID;
			}
		ReplyMsg( (struct Message *)msg );
		if( nopointer==TRUE && class!=RAWKEY )		/*   ripristina pointer   */
			{
			ClearPointer( window );
			ReportMouse( window, FALSE );
			ModifyIDCMP( window, IDCMPFLAGS );
			nopointer=FALSE;
			}
		}
	return( (LONG)msg );
}


/*****   Mostra un messaggio con AutoRequest, con 2 risposte definibili   *****/
LONG messaggio2( UBYTE *testo, UBYTE *positivo, UBYTE*negativo )
{
	messtesto.IText=testo;
	messtesto.LeftEdge=(MESSW-25-strlen(testo)*8)/2;
	messpositivo.IText=positivo;
	messnegativo.IText=negativo;
	return( AutoRequest( window, &messtesto, positivo ? &messpositivo : NULL, &messnegativo, positivo?VANILLAKEY:NULL, positivo?NULL:VANILLAKEY, MESSW, MESSH ) );
}

/*****   Mostra un messaggio con AutoRequest   *****/
void messaggio( UBYTE *testo )
{
	messaggio2( testo, NULL, "Continue" );
}


/*****   Scrivi text in Output()   *****/
void outs( UBYTE *text )
{
	Write( _Backstdout, text, strlen(text) );
}

/***** Chiudi tutto e muori *****/
void fine( UBYTE *text )
{
	linenumfn[fn]=linenum;		/*   per sicurezza   */
	linepfn[fn]=linep;
	for( fn=0; fn<MAXFN; fn++)
		if( linenumfn[fn] )
			{
			FreeMem( linepfn[fn], sizeof(struct line)*linenumfn[fn] );
			FreeMem( bufferfn[fn], blenfn[fn] );
			}
	if( lock ) UnLock( lock );		/*   per sicurezza   */
	if( file ) Close( file );
	if( fib ) FreeMem( fib, sizeof(struct FileInfoBlock) );
	if( tempbitmap ) FreeMem( tempbitmap, 80*8 );
	if( process ) process->pr_WindowPtr=adoswin;
	if( window )
		{
		ClearMenuStrip( window );
		CloseWindow( window );
		}
	if( screen ) CloseScreen( screen );
	if( GfxBase ) CloseLibrary( (struct Library *)GfxBase );
	if( IntuitionBase ) CloseLibrary( (struct Library *)IntuitionBase );

	if( text && _Backstdout )
		{
		outs( "\n[33mView80 Error:[31m " );
		outs( text );
		outs( "!\n\n" );
		}
	if( _Backstdout ) Close( _Backstdout );


#ifndef DEBUG
	_exit( NULL );
#else
	exit( NULL );
#endif
}
