/*----------------------------------------------------------*/
/* TOS-Kommandozeilen-Interpreter 1.2						*/
/* (c) Jens Mller 1992										*/
/*----------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <process.h>
#include <errno.h>
#include <ext.h>
#include <tos.h>
#include <aes.h>

#define	TRUE	1
#define	FALSE	0

#define	CON	2

#define	cmd_length	255			/* max. Zeilenl„nge				*/
#define	cmd_num		21			/* Anzahl interner Kommandos	*/
#define	exec_num	4			/* Anz. ausfhrbarer Prg.typen	*/

typedef	int	BOOLEAN;

int 	ap_id;
int 	mbuf[8];						/* Mitteilungspuffer	*/
char	*phys_scr;
char	*log_scr;
char	*new_scr;
char	screen[32256];

int		max_cmd_length, scr_rez;

struct ffblk	d_info;
struct ftime	*d_time;

struct baspag	*bp_ptr;

int		tos_ver;
long	tos_date;

char	path_buf[MAXPATH], help_str[254];
char	in_buf[cmd_length + 4], history_buf[cmd_length] = "";
char	env[MAXPATH];
char	*arg[4];

int		num_files;


/*--------------------------------------------------------------*/
/* Tabelle der drei Standardkan„le								*/

char	*std_ch[] = {"CON:", "AUX:", "PRN:"};


/*--------------------------------------------------------------*/
/* Tabelle der internen Kommandos								*/

char	*cmd_tab[cmd_num] =
	{"EXIT", "DIR", "CHDIR", "CD", "DEL", "ERA",
	 "MKDIR", "MD", "RMDIR", "RD", "CLS", "VER",
	 "RENAME", "REN", "TYPE", "COPY", "INV", "DATE",
	 "TIME", "HELP", "?"};


/*--------------------------------------------------------------*/
/* Hilfstext													*/

char	*t_help1 = {
			"\x1Bv"							/* Wrap On			*/
			"Kommando       Argumente                  Erl„uterung  [...] kann entfallen\n"
			"---------------------------------------------------------------------------\n"
			"CHDIR, CD      [Pfad]                     Pfad anzeigen/„ndern\n"
			"CLS                                       Bildschirm l”schen\n"
			"COPY           Maske      Zielpfad        Dateien kopieren\n"
			"               Quelldatei Zieldatei       Datei duplizieren\n"
			"DATE           [Datum]                    Datum anzeigen/„ndern\n"
			"DEL, ERA       Maske                      Dateien l”schen\n"
			"DIR            [Maske]                    Directory anzeigen\n"
			"EXIT                                      Shell verlassen\n"
			"HELP, ?                                   dieser Text\n"
			"INV                                       Bildschirm invertieren\n"
			"MKDIR, MD      Name                       Unterverzeichnis anlegen\n"
			"RENAME, REN    Altname Neuname            Datei umbenennen bzw. verschieben"
		};

char	*t_help2 = {
			"RMDIR, RD      Name                       leeres Unterverzeichnis l”schen\n"
			"TIME           [Zeit]                     Zeit anzeigen/„ndern\n"
			"TYPE           Dateiname [-W]             Datei anzeigen [mit warten]\n"
			"               Dateiname -P               Datei drucken\n"
			"VER                                       Version anzeigen\n"
			"X:                                        Laufwerk wechseln\n"
			"Diese Funktionen sind ber den "
		};

char	*t_help3 = {
			"zentralen Command-Shell-Einsprung-\n"
			"vektor ($0004F6) nutzbar.\n"
			"Allgemeine Abbruchtaste ist UNDO.\n"
			"Das Programm l„uft als TOS und ACC."
			"\x1Bw"							/* Wrap Off			*/
		};


/*--------------------------------------------------------------*/
/* Tabelle der Extensionen ausfhrbarer Dateien					*/

char	*exec_file_name[exec_num] = {"PRG", "APP", "TOS", "TTP"};


/*--------------------------------------------------------------*/
/* Tabelle der Fehlermeldungen									*/

char	*err_ptr[] = {
			"Allgemeiner Fehler!",						/* 0	*/
			"Fehlerhafte Kommandozeile!",				/* 1	*/
			"Falsche Laufwerksangabe!",					/* 2	*/
			"Zugriff verweigert!",						/* 3	*/
			"Zu viele Dateien offen!",					/* 4	*/
			"Datei nicht gefunden!",					/* 5	*/
			"Zu wenig Speicher!",						/* 6	*/
			"Falsches Dateiformat!",					/* 7	*/
			"Fehlerhafter Programmaufruf!",				/* 8	*/
			"Pfad nicht gefunden!",						/* 9	*/
			"Ordner nicht gefunden!",					/* 10	*/
			"Umbenennen nicht m”glich!",				/* 11	*/
			"Unzul„ssige Optionen!",					/* 12	*/
			"Datei kann nicht ge”ffnet werden!",		/* 13	*/
			"Datei kann nicht gelesen werden!",			/* 14	*/
			"Directory voll!",							/* 15	*/
			"Laufwerk voll!",							/* 16	*/
			"Drucker nicht bereit!",					/* 17	*/
			"Falsche Datumsangabe! (TT.MM.JJ)",			/* 18	*/
			"Falsche Uhrzeitangabe! (hh.mm.ss)"			/* 19	*/
		};


/*--------------------------------------------------------------*/
/* Ausgabe Fehlermeldung										*/

void out_err(int err_num)
	{
	printf("\a%s\n", err_ptr[err_num]);
	}


/*--------------------------------------------------------------*/
/* String vom Ende beginnend kopieren							*/

void strrcpy(char *dest_ptr, char *source_ptr)
	{
	int	pos;

	pos = (int)strlen(source_ptr);
	source_ptr = source_ptr + pos;
	dest_ptr = dest_ptr + pos;
	while(pos >= 0)
		{
		*dest_ptr = *source_ptr;
		source_ptr--;
		dest_ptr--;
		pos--;
		}
	}


/*--------------------------------------------------------------*/
/* Zeiger auf Textanfang oder Textende setzen					*/

void atxt(char **textptr)
	{
	char	sign;

	(*textptr)--;
	do
		{
		(*textptr)++;
		sign = **textptr;
		}
	while(sign == 32 || sign ==9); 
	}

void etxt(char **textptr)
	{
	char	sign;

	(*textptr)--;
	do
		{
		(*textptr)++;
		sign = **textptr;
		}
	while(sign != 32 && sign !=9 && sign); 
	}


/*--------------------------------------------------------------*/
/* Abtrennen des Dateinamens bzw. Dateimaske, 					*/
/* Rckgabe eines Zeiger auf das Ende des Pfadstrings			*/

char	*cutpath(char *path_only_ptr, char *name_ptr)
	{
	char	*help_ptr, *help_ptr2;

	strcpy(path_only_ptr, name_ptr);
	atxt(&path_only_ptr);
	help_ptr2 = path_only_ptr;
	if(*(help_ptr2 + 1) == ':')
		help_ptr2 = help_ptr2 + 2;
	help_ptr = strrchr(help_ptr2, '\\');
	if(help_ptr)
		{						/* Pfadende						*/
		help_ptr++;
		*help_ptr = 0;
		}
	else
		{						/* nur Dateiname bzw. ~maske	*/
		*help_ptr2 = 0;
		help_ptr = path_only_ptr;
		}
	return(help_ptr);
	}


/*--------------------------------------------------------------*/
/* Bidschirmzeile ab Kursor l”schen, Zeile ab Zeiger ausgeben,	*/
/* ohne Kursorposition zu ver„ndern								*/

void show_eol(char *help_ptr)
	{
	printf("\x1B\x66\x1Bj\x1BK%s\x1Bk\x1B\x65", help_ptr);
	}


/*--------------------------------------------------------------*/
/* Eingabe einer Zeichenkette, max. L„nge in "max_cmd_length"	*/

void in_string(char *sign_ptr)
	{
	int		pos = 0;
	long	taste;
	char	ascii, scan, *a_buf, *help_ptr;

	a_buf = sign_ptr;
	*sign_ptr = 0;
	do
		{
		taste = Crawcin();
		ascii = (char)taste;
		scan = (char)(taste >> 16);
		if(ascii == 9)	ascii = 0x20;		/* TAB -> Space		*/
		if(abs(ascii) >= 0x20 && ascii != 0x7F && pos < max_cmd_length)
			{			/* gew”hnliches ASCII-Zeichen schreiben	*/
			strrcpy(sign_ptr + 1, sign_ptr);
								/* Zeilenberlauf verhindern	*/
			*(a_buf + max_cmd_length) = 0;
			*sign_ptr = ascii;
			sign_ptr++;
			pos++;
			Cconout((char)ascii);
			show_eol(sign_ptr);
			}
		if(ascii == 8 && pos > 0)
			{
			sign_ptr--;
			pos--;
			strcpy(sign_ptr, sign_ptr + 1);
			printf("\b");
			show_eol(sign_ptr);
			}
		if(ascii == 0x7F && *sign_ptr)
			{
			strcpy(sign_ptr, sign_ptr + 1);
			show_eol(sign_ptr);
			}
		if(scan == 75 && pos > 0)
			{
			sign_ptr--;
			pos--;
			printf("\x1B\x44");				/* Kursor links		*/
			}
		if(scan == 77 && *sign_ptr)
			{
			sign_ptr++;
			pos++;
			printf("\x1B\x43");				/* Kursor rechts	*/
			}
		if(scan == 61)
			{
			help_ptr = history_buf;
			while(*help_ptr && pos < max_cmd_length)
				{
				strrcpy(sign_ptr + 1, sign_ptr);
								/* Zeilenberlauf verhindern	*/
				*(a_buf + max_cmd_length) = 0;
				*sign_ptr = *help_ptr;
				Cconout((char)*sign_ptr);
				sign_ptr++;
				help_ptr++;
				pos++;
				}
			show_eol(sign_ptr);
			}
		if(scan == 97)
			{
			printf("\x1B\x66");					/* CursorOff	*/
								/* Bildspeicher zurckschalten	*/
			Setscreen(log_scr, phys_scr, -1);
			do
				{
				evnt_mesag(mbuf);
				}
			while (mbuf[0] != AC_OPEN);
			phys_scr = Physbase();	/* Bildspeicher umschalten	*/
			log_scr = Logbase();
			Setscreen(new_scr, new_scr, -1);
			printf("\x1B\x65");					/* CursorOn		*/
			}
		}
	while(ascii != 0xD && ascii != 0x1A);
	strcpy(history_buf, a_buf);
	if(ascii == 0x1A)
		{
		*sign_ptr = 0x1A;
		*(sign_ptr + 1) = 0;
		printf("^Z");
		}
	puts("");
	}


/*--------------------------------------------------------------*/
/* Test auf vorhandenes Laufwerk 								*/
/* Output: -1 = Fehler, sonst Laufwerksnummer					*/

int tst_dev(int dev)
	{
	dev = dev - 'A';
	if(!(Drvmap() & (1 << dev)))
		{
		out_err(2);
		dev = -1;
		}
	return(dev);
	}


/*--------------------------------------------------------------*/
/* Titelausschrift												*/

void title(void)
	{
	puts("TOS-Kommandozeilen-Interpreter");
	puts("* Version 1.2  Puplic Domain *\n");
	}


/*--------------------------------------------------------------*/
/* Warten auf Tastendruck, ASCII-Wert wird zurckgegeben		*/

int	wait_key(void)
	{
	long	taste;

	printf("Taste drcken...");
	taste = Bconin(2);
	if((taste >> 16) == 97)
		taste = 3;
	puts("");
	return((char)taste);
	}


/*--------------------------------------------------------------*/
/* Testet auf UNDO und ^C										*/
/* Output: FALSE = Abbruch gedrckt, TRUE = OK					*/

BOOLEAN	tst_break(void)
	{
	int		status = TRUE;
	long	taste;

	if(Bconstat(2))
		{
		taste = Bconin(2);
		if((char)(taste >> 16) == 97 || (char)taste == 3)
			status = FALSE;
		}
	return(status);
	}


/*--------------------------------------------------------------*/
/* Hilfestellung												*/

void help(void)
	{
	int	taste = 0;

	puts(t_help1);
	if(!scr_rez)
		taste = wait_key();
	if(taste != 3)
		{
		printf("%s", t_help2);
		if(!scr_rez)
			puts("");
		puts(t_help3);
		}
	}


/*--------------------------------------------------------------*/
/* Datum und Uhrzeit											*/

void ch_date(void)
	{
	int		year, mon, day;
	int		h_date;

	if(*arg[0])
		if(*arg[1])
			out_err(18);
		else
			{
			sscanf(arg[0], "%d.%d.%d", &day, &mon, &year);
			if(year < 100)
				{
				year = year + 1900;
				if(year < 1980)
					year = year + 100;
				}
			if(!day || !mon)
				out_err(18);
			else
				{
				h_date = (day & 0x1F) | ((mon & 0xF) << 5)
							| (((year - 1980) & 0x7F) << 9);
				if((int)Tsetdate(h_date) == -1)
					out_err(18);
				}
			}
	h_date = Tgetdate();
	Settime(Tgettime() | ((long)h_date << 16));
	printf("Es ist der %02d.%02d.%d.\n", h_date & 0x1F,
			(h_date >> 5) & 0xF, ((h_date >> 9) & 0x7F) + 1980);
	}

void ch_time(void)
	{
	int		hour, min, sec;
	int		h_time;

	if(*arg[0])
		if(*arg[1])
			out_err(19);
		else
			{
			sscanf(arg[0], "%d.%d.%d", &hour, &min, &sec);
			h_time = ((sec >> 1) & 0x1F) | ((min & 0x3F) << 5)
						| ((hour & 0x1F) << 11);
			if((int)Tsettime(h_time) == -1)
				out_err(19);
			}
	h_time = Tgettime();
	Settime(h_time | ((long)Tgetdate() << 16));
	printf("Es ist %02d:%02d:%02d Uhr.\n", (h_time >> 11) & 0x1F,
			(h_time >> 5) & 0x3F, (h_time & 0x1F) << 1);
	}


/*--------------------------------------------------------------*/
/* Bildschirm invertieren (Farbregister negieren)				*/

void inv(void)
	{
	int	i;

	if(*arg[0])
		out_err(1);
	else
		for(i = 0; i < 16; i++)
			Setcolor(i, (~Setcolor(i, -1)) & 0xFFF);
	}


/*--------------------------------------------------------------*/
/* Dateien kopieren												*/

void copy_std(int channel)
	{
	int		f_handle, num;
	char	help_buf[1024], *help_ptr;
	long	bytes;
	BOOLEAN	ende = FALSE;

	f_handle = Fcreate(arg[1], 0);
	if(f_handle <= -34)
		switch(f_handle)
			{
			case	-34:	out_err(9);
							break;
			case	-35:	out_err(4);
							break;
			case	-36:	out_err(15);
							break;
			}
	else
		{
		while(!ende)
			{
			if(channel == 1)
				{										/* AUX	*/
				num = 0;
				while(num < 1024 && !ende)
					{
					if(Bconstat(1))
						{
						if((help_buf[num] = Bconin(1)) == 0x1A)
							ende = TRUE;
						num++;
						}
					else
						if(!tst_break())
							ende = TRUE;
					}
				}
			else
				{
				in_string(help_buf);
				strcat(help_buf, "\n");
				help_ptr = strchr(help_buf, 0x1A);	/* Dateiende	*/
				if(help_ptr)
					{
					*(help_ptr + 1) = 0;
					ende = TRUE;
					}
				num = (int)strlen(help_buf);
				}
			bytes = Fwrite(f_handle, num, help_buf);
			if(bytes != num)
				{
				if(bytes == -36)
					out_err(3);
				else
					out_err(16);
				ende = TRUE;
				}
			}
		Fclose(f_handle);
		num_files = 1;
		}
	}

void fill_buffer(char **buf_ptr, struct ffblk *f_dta, int *count)
	{
	char	*help_ptr, f_name[128];
	int		f_handle;
	long	bytes;
											/* gerade Adressen	*/
	*buf_ptr = (char *)((long)(*buf_ptr + 1) & (-2L));
	help_ptr = *buf_ptr;
	memcpy(help_ptr, f_dta, sizeof(struct ffblk));
	*buf_ptr = *buf_ptr + sizeof(struct ffblk);
	cutpath(f_name, arg[0]);
	strcat(f_name, f_dta->ff_name);
	f_handle = open(f_name, O_RDONLY);
	bytes = read(f_handle, *buf_ptr, f_dta->ff_fsize);
	close(f_handle);
	if(bytes != f_dta->ff_fsize)
		{
		printf("Fehler beim Lesen von %s!\n", f_dta->ff_name);
		*buf_ptr = help_ptr;
		}
	else
		{
		(*count)++;
		*buf_ptr = *buf_ptr + bytes;
		}
	}

BOOLEAN empty_buffer(char *buf_ptr, char **beg_ptr, int *count)
	{
	BOOLEAN			ok;
	struct ffblk	*f_dta;
	char			*help_ptr, f_name[128];
	int				f_handle;
	long			bytes;

	if(*count > 0)
		{
		puts("Datei(en) schreiben:");
		strcpy(f_name, arg[1]);
		help_ptr = f_name;
		etxt(&help_ptr);
		ok = tst_break();
		while(*count > 0 && ok)
			{								/* gerade Adressen	*/
			buf_ptr = (char *)((long)(buf_ptr + 1) & (-2L));
			f_dta = (struct ffblk *)buf_ptr;
			buf_ptr = buf_ptr + sizeof(struct ffblk);
			if(*(help_ptr - 1) == '\\' || f_name[1] == ':')
				strcpy(help_ptr, f_dta->ff_name);
			printf("  %s\n", f_name);
			f_handle = Fcreate(f_name, f_dta->ff_attrib);
			if(f_handle <= -34)
				{
				switch(f_handle)
					{
					case	-34:	out_err(9);
									break;
					case	-35:	out_err(4);
									break;
					case	-36:	out_err(15);
									break;
					}
				ok = FALSE;
				}
			else
				{
				bytes = Fwrite(f_handle, f_dta->ff_fsize, buf_ptr);
				if(bytes != f_dta->ff_fsize)
					{
					if(bytes == -36)
						out_err(3);
					else
						out_err(16);
					ok = FALSE;
					}
				Fdatime((DOSTIME *)&f_dta->ff_ftime, f_handle, 1);
				Fclose(f_handle);
				num_files++;
				}
			buf_ptr = buf_ptr + f_dta->ff_fsize;
			(*count)--;
			tst_break();
			}
		*beg_ptr = buf_ptr;
		*count = 0;	
		}
	return(ok);
	}

void copy(void)
	{
	char	*help_ptr, *buffer, *buf_ptr, *eo_buf;
	int		i, test, count = 0;
	long	m_free, help;
	BOOLEAN	ok = TRUE;

	if(*arg[0])						/* erster Name?				*/
		{
		if(*arg[2])					/* dritter Name -> Fehler	*/
			out_err(1);
		else
			{
			if(!*arg[1])
				{
				arg[1]++;
				*arg[1] = (char)Dgetdrv() + 'A';
				*(arg[1] + 1) = ':';
				*(arg[1] + 2) = 0;
				}
			num_files = 0;
			test = -1;				/* von Standardkanal lesen?	*/
			for(i = 0; i < 2 && test; i++)
				test = strcmp(arg[0], std_ch[i]);
			if(!test)
				copy_std(i - 1);
			else
				{
				help_ptr = arg[1];
				etxt(&help_ptr);
				if(*(help_ptr - 1) != '\\' && *(help_ptr - 1) != ':')
					{
					test = findfirst(arg[1], &d_info, FA_DIREC);
					if(strpbrk(arg[0], "*?") ||
						(!test && (d_info.ff_attrib & FA_DIREC)))
						strcpy(help_ptr, "\\");
					}
				m_free = coreleft() - 0x4000;	/* noch 16k briglassen	*/
				if(m_free < 0x4000)				/* wenigstens 16k		*/
					out_err(6);
				else
					{
					buffer = malloc(m_free);
					eo_buf = buffer + m_free;
					if(!buffer)
						out_err(6);
					else
						{
						buf_ptr = buffer;		/* Laufvariable		*/
						test = findfirst(arg[0], &d_info, 0);
						while(!test && ok)
							{
							help = d_info.ff_fsize + sizeof(d_info);
							if((long)eo_buf - (long)buf_ptr < help + 1)
								{
								ok = empty_buffer(buffer, &buf_ptr, &count);
								if(ok)
									{
									if(m_free < help + 1)
										{
										out_err(6);
										printf("%s kann nicht kopiert werden!\n", d_info.ff_name);
										}
									else
										fill_buffer(&buf_ptr, &d_info, &count);
									}
								}
							else
								fill_buffer(&buf_ptr, &d_info, &count);
							test = findnext(&d_info);
							}
						empty_buffer(buffer, &buf_ptr, &count);
						free(buffer);
						}
					}
				}
			printf("%d Datei(en) kopiert\n", num_files);
			}
		}
	else
		out_err(1);
	}


/*--------------------------------------------------------------*/
/* Datei anzeigen												*/

void print_file(char *name_ptr, int channel, BOOLEAN wait_page)
	{
	int		lines = 0;
	int		f_handle;
	BOOLEAN	ok = TRUE;
	char	sign;
	long	bytes = 0;

	f_handle = open(name_ptr, O_RDONLY);
	if(f_handle != -1)
		{
		while(ok)
			{
			if(wait_page && ok)
				{
				lines++;
				if(lines > 20)
					{
					if(wait_key() == 3) ok = FALSE;
					lines = 0;
					}
				}
			if(ok)
				{
				sign = 0;
				while(sign != 10 && ok)
					{
					bytes = read(f_handle, &sign, 1);
					if(bytes == 1 && tst_break())
						if(channel == 3)
							{
							if(!Cprnout(sign))
								{
								puts("");
								out_err(17);
								ok = FALSE;
								}
							}
						else
							Cconout(sign);
					else
						ok = FALSE;
					}
				}
			}
		close(f_handle);
		puts("");
		if(bytes == -1)
			out_err(14);
		}
	else
		out_err(13);
	}

void file_type(void)				/* -P drucken, -W warten	*/
	{
	int		channel = 1;				/* Bildschirm			*/
	BOOLEAN	wait_page = FALSE;			/* am Seitenende warten	*/

	if(*arg[2] || !*arg[0])
		out_err(1);
	else
		{
		if(*arg[1])
			if(!strcmp(arg[1], "/P") || !strcmp(arg[1], "-P"))
				{
				if(Cprnos())
					{
					channel = 3;
					print_file(arg[0], channel, wait_page);
					}
				else
					out_err(17);
				}
			else
				if(!strcmp(arg[1], "/W") || !strcmp(arg[1], "-W"))
					{
					wait_page = TRUE;
					print_file(arg[0], channel, wait_page);
					}
				else
					out_err(12);
		else
			print_file(arg[0], channel, wait_page);
		}
	}


/*--------------------------------------------------------------*/
/* Datei umbenennen												*/

void file_rename(void)
	{
	if(*arg[0] && *arg[1])			/* erster und zweiter Name?	*/
		if(*arg[2])					/* noch etwas -> Fehler		*/
			out_err(1);
		else
			{
			if(rename(arg[0], arg[1]))
				out_err(11);
			}
	else
		out_err(1);
	}


/*--------------------------------------------------------------*/
/* Versionsabfrage												*/

long get_version(void)				/* nur im Supervisormode!	*/
	{
	struct _syshdr **sysbase_ptr;

	sysbase_ptr = (struct _syshdr**) 0x4F2L;
	tos_ver = (*sysbase_ptr)->os_version;
	tos_date = (*sysbase_ptr)->os_gendat;
	return(0);				/* Wert egal, nur wegen Supexec()	*/
	}


void ver(void)
	{
	if(*arg[0])
		out_err(1);
	else
		{
		puts("");
		title();
		Supexec(get_version);
		printf("TOS %x.%x vom %02x.%02x.%x\n", 
				(char)(tos_ver >> 8), (char)tos_ver,
				(char)(tos_date >> 16), (char)(tos_date >> 24),
				(int) tos_date);
		}
	}


/*--------------------------------------------------------------*/
/* Bildschirm l”schen											*/

void cls(void)
	{
	if(*arg[0])
		out_err(1);
	else
		printf("\x1B\x45");
	}


/*--------------------------------------------------------------*/
/* Directory anlegen bzw. l”schen								*/

void mkdir(void)
	{
	int	dcret;

	if(*arg[0])
		if(*arg[1])
			out_err(1);
		else
			{
			dcret = Dcreate(arg[0]);
			if(dcret == -34)	out_err(9);
			if(dcret == -36)	out_err(3);
			}
	else	out_err(1);
	}


void rmdir(void)
	{
	int	dcret;

	if(*arg[0])
		if(*arg[1])
			out_err(1);
		else
			{
			dcret = Ddelete(arg[0]);
			if(dcret == -34)	out_err(10);
			if(dcret == -36)	out_err(3);
			if(dcret == -65)	out_err(0);
			}
	else	out_err(1);
	}


/*--------------------------------------------------------------*/
/* Dateien l”schen												*/

void delete(void)
	{
	char	*help_ptr, sign, sign2 = 'J';
	int		test, i = 0;
	int		no_del = FA_RDONLY | FA_HIDDEN | FA_DIREC | FA_LABEL;

	if(*arg[0])
		if(*arg[1])
			out_err(1);
		else
			{
			if(strchr(arg[0], '*'))
				{
				sign2 = 'N';
				printf("Dateien l”schen? (J) ");
				sign = getch();
				if(sign != 13)
					sign2 = sign;
				Cconout(sign);
				while(sign != 13)
					{
					sign = getch();			
					if(sign != 13)
						{
						printf("\b%c", sign);
						sign2 = sign;
						}
					}
				puts("");
				}
			if(sign2 == 'J' || sign2 == 'j')
				{
				help_ptr = cutpath(path_buf, arg[0]);
				test = findfirst(arg[0], &d_info, 0);
				while(!test)
					{
					if(!(d_info.ff_attrib & no_del))
						{
						strcpy(help_ptr, d_info.ff_name);
						if(!remove(path_buf))
							{
							i++;
							printf("  %s\n", path_buf);
							}
						}
					test = findnext(&d_info);
					}
				printf("%d Datei(en) gel”scht\n", i);
				}
			}
	else
		out_err(1);
	}


/*--------------------------------------------------------------*/
/* Laufwerk / Pfad „ndern bzw. anzeigen							*/

void change_dir(void)
	{
	int		dev = 0, old_dev;

	old_dev = Dgetdrv();
	if(*arg[0])
		{
		if(*arg[1])
			out_err(1);
		else
			if(*(arg[0] + 1) == ':')	/* Laufwerksangabe?		*/
				{
				dev = tst_dev(*arg[0]);
				if(dev != -1)
					{					/* Laufwerk wechseln	*/
					Dsetdrv(dev);
					arg[0]++;
					arg[0]++;
					if(*arg[0])			/* plus Pfad?			*/
						{
						if(chdir(arg[0]))
							{			/* Fehler -> altes LW	*/
							Dsetdrv(old_dev);
							out_err(9);
							}
						}
					else
						{		/* keine Pfadangabe -> anzeigen	*/
						getcwd(path_buf, MAXPATH);
						Dsetdrv(old_dev);		/* zum alten LW	*/
						puts(path_buf);
						}
					}
				}
			else
				if(chdir(arg[0]))			/* nur Pfadangabe	*/
					out_err(9);
		}
	else
		{
		getcwd(path_buf, MAXPATH);			/* Pfad anzeigen	*/
		puts(path_buf);
		}
	}


/*--------------------------------------------------------------*/
/* Directory anzeigen											*/

void show_dir(char *maske_ptr)
	{
	int		i, test, lines = 0, f_num = 0;
	long	pre_zero, f_bytes = 0;
	char	*help_ptr;

	test = findfirst(maske_ptr, &d_info, FA_DIREC);
	while(!test)
		{
		if(!tst_break())
			test = -1;
		else
			{
			lines++;
			if(lines > 20)
				{
				if(wait_key() == 3) test = -1;
				lines = 0;
				}
			}
		if(!test)
			{			/* formatierte Ausgabe des Dateinamens	*/
			help_ptr = strchr(d_info.ff_name, '.');
			if(help_ptr == d_info.ff_name)	/* DIR "." und ".."	*/
				printf("%-12s", help_ptr);
			else
				{
				if(help_ptr)
					{
					*help_ptr = 0;
					help_ptr++;
					}
				printf("%-9s", d_info.ff_name);
				if(help_ptr)
					printf("%-3s", help_ptr);
				else
					printf("   ");
				}
			if(d_info.ff_attrib & FA_DIREC)
				printf("    (DIR)  ");
			else
				if(d_info.ff_attrib & FA_LABEL)
					printf("    (VOL)  ");
				else
					{						/* Ausgabe Dateil„nge		*/
					ltoa(d_info.ff_fsize, help_str, 10);
					pre_zero = 8 - strlen(help_str);
					if(pre_zero < 0) pre_zero = 0;
					for(i=0; i<pre_zero; i++) Cconout(0x20);
					printf(" %s  ", help_str);
					}
			if(scr_rez)	/* Datum und Zeit nicht in niedriger Aufl.	*/
				{
				printf("%.2d:%.2d:%.2d  %.2d.%.2d.%.2d  ",
						d_time->ft_hour, d_time->ft_min,
						d_time->ft_tsec * 2,
						d_time->ft_day, d_time->ft_month,
						d_time->ft_year + 1980);
				}
										/* Dateiattribute anzeigen	*/
			if(d_info.ff_attrib & FA_RDONLY)
				Cconout('r');
			else	Cconout('-');
			if(d_info.ff_attrib & FA_HIDDEN)
				Cconout('h');
			else	Cconout('-');
			if(d_info.ff_attrib & FA_ARCH)
				Cconout('a');
			else	Cconout('-');
			puts("");
			if(!(d_info.ff_attrib & (FA_DIREC | FA_LABEL)))
				f_num++;
			f_bytes = f_bytes + d_info.ff_fsize;
			test = findnext(&d_info);
			}
		}
		printf("%ld Bytes in %d Datei(en)\n", f_bytes, f_num);
	}


void dir(void)
	{
	char	show_all[4] = "*.*";
	char	*help_ptr;

	d_time = (struct ftime*) &d_info.ff_ftime;
	if(*arg[0])
		if(*arg[1])
			out_err(1);
		else
			{						/* nur Unterverzeichnisse?	*/
			help_ptr = strrchr(arg[0], '\\');
			if(help_ptr && (!*(help_ptr + 1)))
				strcpy(help_ptr + 1, show_all);
			else
				{						/* nur Laufwerksangabe?	*/
				help_ptr = strrchr(arg[0], ':');
				if(help_ptr && (!*(help_ptr + 1)))
					strcpy(help_ptr + 1, show_all);
				}
			show_dir(arg[0]);
			}
	else
		show_dir(show_all);
	}


/*--------------------------------------------------------------*/
/* Kommandozeile ausfhren										*/

BOOLEAN exec_line(char *cmd_line)
	{
	char	*help_ptr, *h_ext;
	int		i, j, dev, erg;
	BOOLEAN	found, break_flag = FALSE;

	strupr(cmd_line);
	atxt(&cmd_line);
	if(*cmd_line)				/* leere Kommandozeile?			*/
		{
		help_ptr = cmd_line + 1;
		if(*help_ptr == ':')
			{					/* Laufwerk wechseln			*/
			help_ptr++;
			atxt(&help_ptr);
			if(*help_ptr)
				out_err(1);
			else
				{				/* richtige Laufwerksangabe?	*/
				dev = tst_dev(*cmd_line);
				if(dev != -1)
					Dsetdrv(dev);
				}
			}
		else
			{
			found = FALSE;		/* internes Kommando suchen		*/
			for(i=0; i<cmd_num && !found; i++)
				if(strstr(cmd_line, cmd_tab[i]) == cmd_line)
					{
					help_ptr = cmd_line + strlen(cmd_tab[i]);
					if(!*help_ptr || *help_ptr == 0x20
								  || *help_ptr == 9
								  || *help_ptr == '.')
						found = TRUE;
					}
			if(found)			/* internes Kommando starten	*/
				{
				i--;
				atxt(&help_ptr);
				for(j = 0; j < 4; j++)
					{
					arg[j] = help_ptr;
					etxt(&help_ptr);
					if(*help_ptr)
						{
						*help_ptr = 0;	/* Argument	abtrennen	*/
						help_ptr++;
						}
					atxt(&help_ptr);
					}
				switch(i)
					{
					case 	0:	if(*arg[0])			/* EXIT		*/
									out_err(1);
								else
									break_flag = TRUE;
								break;
					case	1:	dir();				/* DIR		*/
								break;
					case	2:	change_dir();		/* CHDIR	*/
								break;
					case	3:	change_dir();		/* CD		*/
								break;
					case	4:	delete();			/* DEL		*/
								break;
					case	5:	delete();			/* ERA		*/
								break;
					case	6:	mkdir();			/* MKDIR	*/
								break;
					case	7:	mkdir();			/* MD		*/
								break;
					case	8:	rmdir();			/* RMDIR	*/
								break;
					case	9:	rmdir();			/* RD		*/
								break;
					case	10:	cls();				/* CLS		*/
								break;
					case	11:	ver();				/* VER		*/
								break;
					case	12:	file_rename();		/* RENAME	*/
								break;
					case	13:	file_rename();		/* REN		*/
								break;
					case	14:	file_type();		/* TYPE		*/
								break;
					case	15:	copy();				/* COPY		*/
								break;
					case	16:	inv();				/* INV		*/
								break;
					case	17:	ch_date();			/* DATE		*/
								break;
					case	18: ch_time();			/* TIME		*/
								break;
					case	19:	help();				/* HELP		*/
								break;
					case	20:	help();				/* ?		*/
								break;
					}
				}
			else
				{					/* externes Prg. starten	*/
				help_ptr = cmd_line;
				etxt(&help_ptr);	/* Programmname bergehen	*/
				if(*help_ptr)
					{
					*help_ptr = 0;	/* Argumente abspalten		*/
					help_ptr++;
					atxt(&help_ptr);	/* Zeiger auf Argumente	*/
					}				/* "cmd_line": Programmname	*/
				strcpy(help_str, help_ptr);
				if(strchr(cmd_line, '\\'))
					out_err(8);		/* kein Pfad zugelassen		*/
				else
					{				/* Evironmentvariable		*/
					strcpy(env, "PATH= ");
					getcwd(env + strlen(env), MAXPATH);
					env[strlen(env) + 1] = 0;	/* Doppelnull	*/
									/* Test auf Extension		*/
					if(!strchr(cmd_line, '.'))
						{
						strcat(cmd_line, ".");
						h_ext = strchr(cmd_line, '.') + 1;
						found = FALSE;
						for(i=0; i<exec_num && !found; i++)
							{
							strcpy(h_ext, exec_file_name[i]);
							if(!findfirst(cmd_line, &d_info, 0))
								found = TRUE;
							}
						}
					if(exec(cmd_line, help_str, env, &erg))
						switch(errno)
							{
							case	EACCES:	out_err(3);
									break;
							case	EMFILE:	out_err(4);
									break;
							case	ENOENT:	out_err(5);
									break;
							case	ENOMEM:	out_err(6);
									break;
							case	EPLFMT:	out_err(7);
									break;
							default:	out_err(0);
							}
					else
						puts("\x1Bw\x1Bq");
					}
				}
			}
		}
	return(break_flag);
	}


/*--------------------------------------------------------------*/
/* Eingabeschleife												*/

void input_loop(void)
	{
	BOOLEAN	break_flag = FALSE;

	scr_rez = Getrez();
	max_cmd_length = 76;			/* max. Eingabezeilenl„nge	*/
	if(scr_rez == 0)
		max_cmd_length = 36;
	do
		{
		getcwd(path_buf, MAXPATH - 1);
											/* CursorOn			*/
		printf("\x1B\x65%s>", path_buf);
		in_string(in_buf);
		break_flag = exec_line(in_buf);
		}
	while(!break_flag);
	}


void main(void)
	{
	new_scr = (char *)((((long)screen) + 255L) & 0xFFFF00L);
	bp_ptr = (struct baspag *)_BasPag;
	if(bp_ptr->p_parent == NULL)
		{									/* Accessory		*/
		ap_id = appl_init();
		menu_register(ap_id, "  TOS-Command");

		phys_scr = Physbase();			/* Bildspeicher umschalten	*/
		log_scr = Logbase();
		Setscreen(new_scr, new_scr, -1);
		puts("\x1B\x45\x1Bw\x1Bq");			/* CLS, WrapOff, InvOff	*/
		title();
		puts("Hilfe mit \"?\"");
		puts("\x1B\x66");					/* CursorOff			*/
		Setscreen(log_scr, phys_scr, -1);	/* zurckschalten		*/

		while(TRUE)
			{
			evnt_mesag(mbuf);
			if(mbuf[0] == AC_OPEN)
				{
				phys_scr = Physbase();	/* Bildspeicher umschalten	*/
				log_scr = Logbase();
				Setscreen(new_scr, new_scr, -1);
				input_loop();
				printf("\x1B\x66");					/* CursorOff	*/
				Setscreen(log_scr, phys_scr, -1);	/* zurckschalten		*/
				}
			}
		}
	else
		{
		puts("\x1Bw\x1Bq");					/* WrapOff, InvOff	*/
		title();
		puts("Hilfe mit \"?\"");
		input_loop();
		}
	exit(0);
	}

