#include <sys/emx.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
#include <malloc.h>
#include <process.h>

typedef __const__ char * __const__ * CONSTCHAR;
static char **org_env;

static char *timestr( unsigned t, char *buf )
{
    sprintf( buf, "%2.2d:%02.2d", (t >> 11) & 0x1f, (t >> 5) & 0x3f);
    return buf;
}

static char *datestr( unsigned d, char *buf )
{
    sprintf( buf, "%2.2d-%2.2d-%2.2d", d&0x1f, (d>>5) & 0x0f, (d>>9) + 80 );
    return buf;
}

static long show_filename(struct _find *pfind)
{
    char timebuf[10], datebuf[10];
    unsigned size = ((unsigned) pfind->size_hi << 16) + pfind->size_lo;

    datestr( pfind->date, datebuf );
	timestr( pfind->time, timebuf );

    if (pfind->attr & (_A_SUBDIR | _A_VOLID))
	printf( "%-15s  <DIR>\n", pfind->name);
    else
	printf( "%-15s %8u %8s %8s\n",
	    pfind->name, size, datebuf, timebuf);
    return size;
}

typedef enum {
    DEFAULT, SET, ORGENV, DIR, CD, DRIVE, ECHO, DEL, HELP, EXIT
} commands;

typedef struct {
    char *cp;
    commands t;
} item;

static item cmds[] =
{
    "set", SET,
    "orgenv", ORGENV,
    "dir", DIR,
    "cd", CD,
    "drive", DRIVE,
    "echo", ECHO,
    "del", DEL,
    "help", HELP,
    "exit", EXIT,
    NULL, 0
};

static int execute_command(char *argv[])
{
    int i;
    static char wild[]="*.*";
    int cmd = 0;

    for (i = 0; cmds[i].cp; i++)
	if (stricmp(cmds[i].cp, argv[0]) == 0) {
	    cmd = cmds[i].t;
	    break;
	}
    if (!cmd)
	cmd = DEFAULT;

    switch (cmd) {
    case SET:
	if (argv[1]) {
	    char *e = malloc(strlen(argv[1]) + 2);
	    if (!e) return 0;
	    strcpy(e, argv[1]);
	    strupr(e);
	    if (putenv(e)) {
		puts("Bad environmemt");
		free(e);
	    }
	}
	else
	    for (i=0; environ[i] != NULL; i++)
		puts(environ[i]);
	break;

    case ORGENV:
	environ = org_env;
	break;

    case DIR:
	{
	struct _find info;
	if (argv[1]==0)
	    argv[1]=wild;
	if (__findfirst(argv[1],_A_NORMAL | _A_SUBDIR | _A_RDONLY, &info)) {
	    puts("no files found");
	    return 0;
	}
	show_filename(&info);
	while (__findnext(&info) == 0)
	    show_filename(&info);
	}
	break;

    case CD:
	if (argv[1])
	    _chdir2(argv[1]);
	break;

    case DRIVE:
	if (argv[1])
	    _chdrive(argv[1][0]);
	break;

    case ECHO:
	break;

    case DEL:
	if (! argv[1])
	    return 0;
	else if (strpbrk(argv[1],"*?")) {
	    struct _find info;
	    if (__findfirst(argv[1], _A_NORMAL, &info)) {
		puts("no files found");
		return 0;
	    }
	    else remove(info.name);
	    while (__findnext(&info) == 0)
		remove(info.name);
	}
	else remove(argv[1]);
	break;

    case HELP:
	puts("commands: set, orgenv, cd, drive, dir, del, exit, help");
	puts("          and EMX prgs and .bat prgs");
	break;

    case EXIT:
	exit(1);

    case DEFAULT:
	if (argv[0][1] == ':') {
	    _chdrive(argv[0][0]);
	    break;
	}
	if (!strstr(argv[0], ".bat"))
	    return spawnvpe(P_WAIT, argv[0],
			    (CONSTCHAR) argv, (CONSTCHAR) environ);

    } /* switch */

    return 0;
}

int readline(FILE *fhandle, char *linebuf)
{
    int ch;
    int i = 0;

    for (;;) {
	ch = fgetc(fhandle);
	if (ch == EOF) {
	    if (i == 0)
		return -1;
	    linebuf[i] = 0;
	    return i;
	}
	else if (ch == '\n' || ch == '\r') {
	    linebuf[i] = 0;
	    return i;
	}
	else if (ch=='\t' || ch=='@') {
	    linebuf[i++]=' ';
	}
	else
	    linebuf[i++] = ch;
    }
}

/* build argv from string */
int make_tokens(char *string, char *argv[])
{
    int argc,i = 0;
    argv[0] = NULL;

    while (string[i]==' ')
	i++;
    if (string[i] == 0 || string[i] == '\n')
	return 0;

    argc = 1;
    argv[0] = string + i;
    for (i = 0; string[i] != 0; i++)
	if (string[i] == ' ') {
	    string[i] = 0;
	    if (string[i+1] == ' ')
		continue;
	    if (string[i+1] == 0)
		break;
	    argv[argc++] = string + i + 1;
	}
    argv[argc] = 0;
    return argc;
}

int main(int argc, char **argv)
{
    char cline[512];
    char *argvec[64];

    org_env = environ;

    for (;;) {
	cline[0] = _getdrive();
	cline[1] = ':';
	getcwd(cline+2, 256);
	strlwr(cline);
	printf("%s> ", cline);
	if (readline(stdin, cline) < 0)
	    continue;
	if (!make_tokens(cline, argvec))
	    continue;
	if (strstr(argvec[0], ".bat")) {
	    FILE *fd = fopen(cline, "rt");
	    if (!fd)
		continue;
	    while (readline(fd, cline) >= 0) {
		if (!make_tokens(cline, argvec))
		    continue;
		execute_command(argvec);
	    }
	    fclose(fd);
	}
	else
	    execute_command(argvec);
    }
    return 0;
}
