#include <stdio.h>
#include <sgtty.h>
#include <libraries/dos.h>

/* Maximale Anzahl Zeichen pro Zeile; Anzahl der ExCLI-Befehle */
#define MAXC 80
#define KOM  14

/* Festlegen der globalen Variablen */

FILE *tastatur, *file, *drucker;

int dir(),cd(),del(),mdir(),help(),cls(),ren();       /* eigene KOMmandos */
int ende(),view(),type(),save(),new(),pfad();

int maschine=0;
int flag=0;
int p=-1;
int z=-1;

unsigned char aktuellDir[200];
unsigned char store[200];
unsigned char zeile[MAXC+1];
unsigned char kommando[MAXC+1];
unsigned char parameter[MAXC+1];
unsigned char cbef[MAXC+7];
unsigned char esc[96][MAXC+1];
unsigned char ftaste[10][MAXC+1];
unsigned char par[2][MAXC+1];

/* Befehlsworte */
unsigned char bef[KOM][10]={
	"dir",
	"cd",
	"del",
	"mdir",
	"help",
	"cls",
	"view",
	"type",
	"save",
	"new",
	"pfad",
	"ren",
	"endcli",
	"exit"
};
/* Funktionsnamen der Befehle */
int (*funk[KOM])() = {
	&dir,
	&cd,
	&del,
	&mdir,
	&help,
	&cls,
	&view,
	&type,
	&save,
	&new,
	&pfad,
	&ren,
	&ende,
	&ende
};

struct sgttyb stty;
struct FileLock *verz;
struct FileInfoBlock *eintrag;

/*              ____________            */
/*               Funktionen             */
/*              ¯¯¯¯¯¯¯¯¯¯¯¯            */

ren()
/* Unbennen eines Eintrags - Dos-Funktion Rename() */
{
	int i=0;
	int j=0;
	int k=0;
	char c;

	if(parameter[0]=='\0'){
		printf("Aufruf: ren ALTER_NAME NEUER_NAME\n");
		return;
	}
	while(((c=parameter[i])!=0) && (j<2)){
		if(c==' '){
			if(k!=0){
				par[j][k]='\0';
				if(strcmp(&par[j],"to")!=0) j++;
				k=0;
			}
			i++;
			continue;
		}
		par[j][k]=c;
		k++;
		i++;
	}
	par[j][k]='\0';

	if(j<1){
		printf("Aufruf: ren ALTER_NAME NEUER_NAME\n");
		return;
	}
	if(!Rename(par[0],par[1])) printf("Kann nicht %s als %s umbenennen!\n",par[0],par[1]);
	else printf("%s heißt jetzt %s!\n",par[0],par[1]);
}

pfad()
{
	if(aktuellDir[0]=='\0') printf("Erst mit 'cd NAME' wird ein aktueller Pfad angelegt!");
	printf("%s\n",aktuellDir);
}

new()
/* löschen der Tastaturbelegung */
{
	int i;

	for(i=0;i<95;i++) esc[i][0]='\0';
	printf("Tastenbelegung gelöscht!\n");
}

raw_on()
/* ExCLI Übernimmt die Kontrolle Über die Tastatur */
{
	ioctl(0,TIOCGETP,&stty);	/* console-Parameter holen */
	stty.sg_flags |= RAW;		/* Parameter erweitern	*/
	ioctl(0,TIOCSETP,&stty);	/* console-Parameter setzen */
}

raw_off()
/* Amiga kontrolliert die Tastatur */
{
	ioctl(0,TIOCGETP,&stty);
	stty.sg_flags ^= RAW;
	ioctl(0,TIOCSETP,&stty);
}

ende()
/* Programmende */
{
	printf("\n\n");
	flag=0;
	run("RAM:C/assign C: SYS:c");
	run("del RAM:C/assign");
	run("del RAM:C/run");
	run("del RAM:C");
	raw_off();
	Close(tastatur);
	if(maschine) Close(drucker);
	exit(0);	
}

save()
/* Tastaturbelegung speichern */
{
	int i;

	if(parameter[0]!='\0')
		if(parameter[strlen(parameter)-1]!=':') strcat(parameter,"/");
	strcat(parameter,"ExCLI.key");
	if(!(file=Open(parameter,MODE_NEWFILE))){ /* File öffnen */
		printf("Kann Tasten nicht speichern\n");
		return;
	}
	for(i=0;i<95;i++) Write(file,esc[i],80);
	Close(file);
}

type()
/* ähnlich dem CLI-Komando 'type' */
{
	unsigned char c;
	char Dblock[512];
	int i=0;
   	int blocklaenge, zaehler;

	if(parameter[0]=='\0'){
		printf("Aufruf: type FILE\n");
		return;
	}
	if(!(file=Open(parameter,MODE_OLDFILE))){
		printf("Kann File nicht öffnen!\n");
		return;
	}
	cls();
        do {
		blocklaenge = Read(file, Dblock, 512);/* Block  lesen  */
		for (zaehler = 0; zaehler < blocklaenge; zaehler++) {
			if(Dblock[zaehler] == '\n'){
				putchar(Dblock[zaehler]);/* RETURN erlaubt */
				i++;
				if(i>19){
				  i=0;
				  printf("\n\033[2mTASTE - weiter | ESC - stop\033[0m\n");
				  raw_on();
				  if((c=getchar())==27){
					blocklaenge=0;
					raw_off();
					break;
				  }
				  else cls();
				  raw_off();
				}
			}
			else if(Dblock[zaehler] >= 0x20)      /* < 32 verboten  */
				putchar(Dblock[zaehler]);
		}
	} while (blocklaenge == 512);/* ein ganzer Block wurde gelesen */
	Close(file); /* File schliessen */
	putchar('\n');
}

view()
/* Tastaturbelegung einer einzelnen Taste anzeigen */
{
	int nr;

	if(parameter[0]=='\0'){
			printf("Aufruf: view TASTE\n");
			return;
	}
	if(parameter[0]>=32 && parameter[0]<=126){
		nr=parameter[0]-32;
		if(esc[nr][0]!='\0') printf("%s\n",esc[nr]);
		else printf("Nicht belegt!\n");
	}
	else printf("Taste nicht frei definierbar!\n");
}

mdir()
/* makedir-Kommando - Dos-Funktion CreatDir() */
{
	if(parameter[0]=='\0'){
		printf("Aufruf: mdir VERZEICHNISNAME\n");
		return;
	}
	if((verz=CreateDir(parameter))==0){ /* CreatDir - Dir anlegen */
	  if(flag) 
	    printf("Verzeichnis '%s' konnte nicht angelegt werden!\n",parameter);
	}
	else{
		UnLock(verz); /* freigeben der Lockstructur */
		if(flag) printf("Verzeichnis '%s' angelegt!\n",parameter);
	}
}

del()
/* File löschen - Dos-Funktion DeleteFile() */
{
	if(parameter[0]=='\0'){
		printf("Aufruf: del FILENAME\n");
		return;
	}
	if(DeleteFile(parameter)==0){
		if(flag)
		  printf("Eintrag %s konnte nicht gelöscht werden!\n",parameter);
	}
	else if(flag) printf("Eintrag %s gelöscht!\n",parameter);
}
	
dir()
/* Einträge eines Verzeichnisses listen */
{
	int i;

	/* Speicher fÜr FileInfoBlock schaffen */
	eintrag = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),0);
	if(parameter[0]=='\0') strcpy(store,aktuellDir);
	else strcpy(store,parameter);

    	if((verz=Lock(store, ACCESS_READ))==0){
		printf("Finde Directory %s nicht!\n",store);
		return; /* nicht gefunden */
	}
	if(Examine(verz,eintrag)!=0){
		if(eintrag->fib_DirEntryType<=0){/* File oder Verzeichnis ? */
			printf("%s ist kein Verzeichnis!\n",store);
			return;
		}
	}
	else printf("Kann %s nicht listen!",store);
	printf("\n\033[4mEinträge von %s:\033[0m\n\n",eintrag->fib_FileName);
	ExNext(verz,eintrag); 
	while (IoErr() != ERROR_NO_MORE_ENTRIES){ /* Dir-Einträge lesen */
		if (eintrag->fib_DirEntryType > 0){  /* Directoryname */
			printf("\033[2m%s\n\033[0m",eintrag->fib_FileName);
		}
		else{		/* Filename */
			printf("%s \r\t\t\t\t(%ld)\n",eintrag->fib_FileName,eintrag->fib_Size);
		}
		ExNext(verz,eintrag); /* nächster Eintrag */
	}
	FreeMem(eintrag,sizeof(struct FileInfoBlock)); /* Speicher freigeben */
	UnLock(verz);
}

cd()
/* festlegen einer neuen aktuellen Directory - Dos-Funktion CurrentDir() */
{
   int i;
   int bad=0;

   strcpy(store,aktuellDir); /* 'Sicherheitskopie' */
   eintrag=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),0);

   if(parameter[0]=='\0'){ /* nur cd */
        verz=Lock(aktuellDir, ACCESS_READ);
	Examine(verz,eintrag);
	printf("%s\n",eintrag->fib_FileName);
   }
   else{
	if (parameter[0]=='/') { /* aufsteigen mit 'cd /' */
	  for (i=strlen(aktuellDir);aktuellDir[i]!='/'&&aktuellDir[i]!=':';i--);
	  if(aktuellDir[i] == ':') i++;
	  aktuellDir[i] = '\0';
	}
	else { /* neue Directory */
	  if((index(parameter,':'))==0){ /* kein ':' enthalten */
	  	if(aktuellDir[strlen(aktuellDir)-1] != ':'){/* keine Rootdir */
			strcat(aktuellDir,"/");
		}
		strcat(aktuellDir, parameter); /* neues Verzeichnis anhängen */
	  }	   			
	  else strcpy(aktuellDir, parameter); /* parameter enthält ':' */
	}

        if((verz = Lock(aktuellDir, ACCESS_READ)) != 0){
		if(Examine(verz,eintrag)!=0){
		   if(eintrag->fib_DirEntryType<=0) bad++;
		   else verz=CurrentDir(verz); /* neues Verzeichnis anmelden */
		}
		else bad++;
        }
	else bad ++;
	if(bad) {	/* Das neue Verzeichnis existiert nicht! */
		printf("Finde Verzeichnis %s nicht!\n",parameter);
		strcpy(aktuellDir,store);/* RÜckkopieren der Sicherheitskopie */
        }
   } /* else */
   UnLock(verz);
   FreeMem(eintrag,sizeof(struct FileInfoBlock)); /* Speicher freigeben */
}

_abort()
/* Prompt (») schreiben. Der Namen _abort bewirkt, daß die Tastenkombination
   CTRL-C nicht mehr zum Programmabbruch fÜhrt.                              */
{	
	p=-1;
	z=-1;
	printf("\033[33m» \033[31m");
}

help()
/* Hilfsseite listen */
{
	int i;

	printf("\f\033[4mBefehle von ExCLI:\033[0m\n\n");
	printf("dir  - Verzeichnis listen       cd   - Arbeitsverzeichnis festlegen\n");
	printf("del  - File löschen             mdir - Verzeichnis anlegen\n");
	printf("type - File als Text listen     help - Hilfsseite listen\n");
	printf("cls  - Bilschirm löschen        view - Tastenbelegung prÜfen\n");
	printf("new  - Tastenbelegung löschen   pfad - kompletter Pfadname listen\n");
	printf("ren  - Eintrag umbenennen       exit - ExCLI beenden\n");
	printf("\n\033[4mFunktionstasten:\033[0m\n\n");
	for(i=0;i<9;i++) printf(" %d) %s\n",i+1,ftaste[i]);
			 printf("10) %s\n\n",ftaste[i]);
}

run(befehl)
/* Aufruf einer ExCLI-Funktion oder starten eines Programms */
	char *befehl;
{
	int i=-1;
	int j= 0;
	int eigen=0;

	do{	/* Kommando und Parameter trennen */
		i++;
		kommando[i]=befehl[i];
	}while((kommando[i]!=' ') && (kommando[i]!='\0'));
	if(kommando[i]!='\0'){
		kommando[i]='\0';
		i++;
		while(befehl[i++]==' '); /* spaces Überlesen */
		i--;
		while((parameter[j++]=befehl[i++])!='\0');
	}
	else parameter[0]='\0';

	/* Funktionstasten von links nach rechts shiften */
	if(flag){
		for(i=0;i<9;i++) strcpy(ftaste[i],ftaste[i+1]);
		strcpy(ftaste[i],befehl);
	}
	raw_off(); /* erlaubt Anhalten durch Space */
	for (i=0;i<KOM;i++){
		if(strcmp(kommando,bef[i])==0){
			(*funk[i])();	/* Aufruf einer ExCLI-Funktion */
			eigen++;
		}
	}
	if(!eigen) Execute(befehl,0,0); /* Starten eines Programms */
	raw_on(); /* Tastaturkontrolle an ExCLI */
	p=-1;
	z=-1;
}

checkkey(c)
/* checken der Funktionstasten und der Helptaste */
	unsigned char c;
{
	int nr;
	int i=-1;
	unsigned char buff[50];

	/* Funktiontaste F1: \233~0 */
	do{
		i++;
		buff[i]=c;
		c=getchar();
	}while((c!='~') && (c!='|'));

	if ((buff[i+1]=c)=='~' && i<1){
		if (buff[0] == '?'){ /* Helptaste: \233~? */
			flag=0;
			run("help");
			flag=1;
			_abort();
			return;
		}
		if(buff[0]>='0' && buff[0]<='9'){ /* Funktionstasten */
			nr=buff[0]-48;
			printf("\n\033[33m»\033[31m %s",ftaste[nr]);
			strcpy(zeile,ftaste[nr]); /* in die Kommandozeile */
			z=strlen(zeile)-1;        /* kopieren             */
			p=z;
			return;
		}
	}
}

c_del()
/* Funktion wird von DEL und BACKSPACE benutzt */
{
	int i;

	for(i=p+1;i<=z;i++){
		zeile[i]=zeile[i+1];
		printf("\b%c ",zeile[i]);
	}
	for(i-=p+1;i>0;i--) putchar('\b');
	z--;
}

cls()
/* Bildschirm löschen */
{
	printf("\f");
}

insert()
/* ein Space in die Kommanozeile einfÜgen */
{
	int i;

	if((z==p) || (z+1>=MAXC)){ /* mehr als 80 Zeichen */
		putchar(7);        /* Blitz */
		return;
	}
	z++;
	if(z>MAXC-6) putchar(7);   /* Blitz */
	cbef[0]=' ';		   /* Space */
	for(i=p;i<=z;i++) cbef[i-p+1]=zeile[i+1]; /* Space einfÜgen */
	cbef[i-p+1]='\0';  /* cbef abschließen und Zeile neu schreiben */
	for(i=p;(zeile[i+1]=cbef[i-p])!='\0';i++) putchar(zeile[i+1]);
	for(i=z-p;i>0;i--) putchar('\b'); /* Cursor zurÜck */
}

main()
{
	int i,nr;	/* Befehl-Nummer */
	unsigned char c;

	tastatur=Open("RAW:",MODE_OLDFILE); /* Tastatur 'öffnen' */
	run("mdir RAM:C"); /* Verzeichnis RAM:C anlegen */

	/* Ramdisk einrichten */
	printf("\n\n\033[3mRichte RAM-DISK ein ...\033[0m\n");
	run("copy SYS:C/run to RAM:C");
	run("copy SYS:C/assign to RAM:C");
	run("RAM:C/assign c: RAM:C");

	if(file=Open("ExCLI.key",MODE_OLDFILE)){ /* File zum Lesen öffnen */
		printf("\033[3mLade KEY's ...\033[0m\n");
		for(i=0;i<95;i++) Read(file,esc[i],80);
		Close(file);
	}
	printf("\233A\233A _______________________\n \033[2m\033[41m");
	printf(" -*- Gölzy's ExCLI -*- \033[40m\033[0m");
	printf("\n ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯\n");
	run ("cd SYS:");
	printf("» current dir:  SYS:\n");

	flag++;
	raw_on(); /* Tastaturkontrolle Übernimmt ExCLI */
	_abort(); /* Prompt */

	for(;;) { /* Endlosschleife */
		c=getchar(); /* Tastendruck */
		switch(c){
			case 8:{/* backspace */
				if(p>=0){
					p--;
					c_del();
				}
				break;
			}
			case '\t':{/* tab */
				if(maschine){
					Close(drucker);
					maschine=0;
					printf("\n\n \033[3m\033[4m'Schreibmaschine' OFF\033[0m\n\n");
					_abort();
				}
				else{
				   if(!(drucker=Open("PRT:",MODE_NEWFILE))){
				   	printf("Finde keinen Drucker!\n");
					_abort();
				   }
				   else{
					printf(" \033[3m\033[4m'Schreibmaschine' ON\033[0m\n\n");
					maschine=1;
				   }
				}
				break;
			}
			case '\r':{/* wagenrÜcklauf=<RETURN> */
				printf("\n");
				z++;
				if(maschine){
					zeile[z]='\n';
					zeile[z+1]='\0';
					if(Write(drucker,zeile,strlen(zeile))<1)
					   printf("\nDrucker einschalten!\n");
					p=-1;
					z=-1;
					break;
				}
				zeile[z]='\0';
				if(z>0) {
					run(zeile);
				}
				_abort();
				break;
			}
			case 27:{/* ESC */
				printf("\033[33m\233A\r\233K  'ESC' - Taste belegen ");
				printf("oder 'Taste' - Kommando starten\033[31m\233B\r\233C\233C");
				c=getchar();
				if(c==27){
					printf("\033[33m\233A\r\233K  'Taste' - Kommando speichern\033[31m\233B\r\233C\233C");
					c=getchar();
					if(c>=32 && c<=126){
					   nr=c-32;
					   if(z>=0){
					      strcpy(esc[nr],zeile);
				      printf("\nESC-'%c' gespeichert!\n",c);
					   }
					   else printf("Keine Kommandozeile?\n");
					}
					else printf("Taste kann nicht belegt werden!\n");
				}
				else{
					if(c>=32 && c<=126){
						nr=c-32;
						if(esc[nr][0]!='\0'){
							printf("%s\n",esc[nr]);
							run(esc[nr]);
						}
						else printf("Nicht belegt!\n");
					}
					else printf("Taste kann nicht belegt werden!\n");
				}			
				_abort();
				break;
			}
			case 127:{ /* del-taste */
				if((z>=0) && (p<z)){
					printf("\233C");
					c_del();
				}
				break;
			}
			case 155:{/* CSI */
				c=getchar();
				if(c>='0' && c<='9' || c=='?'){
					checkkey(c);
				}
				else{
					if(c=='A') insert();/* C up */
					if((c=='B') && (z>=0) && (p<z)){/* C down */
						printf("\233C");
						c_del();
					}				
					if(c=='D' && p>=0){/* C left */
						printf("\b");
						p--;
					}
					if(c=='C' && p<z){/* C right */
						printf("\233C");
						p++;
					}
					if(c=='S'){/* C shift down */
						if(p>=MAXC-6)
						   printf("\r\233K\233A\233C\233C\233K");
						else printf("\233B\r\233K\233A\233C\233C\233K");
						p=-1;
						z=-1;
						zeile[0]='\0';
					}
					if(c=='T'){/* C shift up */
						if(p>=MAXC-6)
						   printf("\233K\233A\r\233C\233C");
						else printf("\233K\233B\r\233K\233A\233C\233C");
						z=p;
						p=-1;
						zeile[z+1]='\0';
						for(;p<z;p++) printf("\233C");
					}
					if(c==' '){
					   c=getchar();
					   if(c=='A'){/* C shift left */
						for(;p>=0;p--) printf("\b");
					   }
					   if(c=='@'){/* C shift right */
						for(;p<z;p++) printf("\233C");
					   }
					}
				}
				break;
			}
			case 255:{/* CTRL-d und Neuaufruf */
				printf("exit");
				ende();
				}
			default:{/* Kommandozeile aufbauen */
				/* z=Länge der Zeile; p=Cursorposition darin */
				if(z==p) z++;
				p++;
				if((p==z) && (z>MAXC-6)) putchar(7);
				if(z<MAXC){
					zeile[p]  = c;
					zeile[z+1]= '\0';
					putchar(c);
				}
				else{
					if(p==z) z--;
					p--;
				}
				break;
			}
		} /* switch */
	} /* while */
}
