/*
 
Freely Distributable MC56800 Simulator Package
 
Copyright (c) 1997-1998 The University of Texas
All Rights Reserved.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
The GNU Public License is available in the file LICENSE, or you
can write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA, or you can find it on the
World Wide Web at http://www.fsf.org.
 
Author: Brian Evans and Anna Yuan
Version: @(#)utsim.c	1.7	07/02/98
 
Department of Electrical and Computer Engineering
The University of Texas, Austin, TX 78712-1084
*/

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "utsim.h"

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

static char CommandNotSupported[] = "The '%s' command is not supported.\n";

char* VersionIdentification =
"The University of Texas at Austin MC56800 Command-Line Interface Version "
UT_VERSION_STRING
"\n"
"Copyright (c) 1997-1998 The University of Texas.  All Rights Reserved.\n"
"Released as freely distributable software under the GNU license.\n"
"Authored by Anna Yuan and Brian Evans.  Based on the "
MC_VERSION_STRING
"\n"
"version of the CLAS568 Tools Copyright (C) 1995-1998 Motorola Inc.\n";
 
/*
Read a string from a stream and make sure that the string
is terminted with a newline character.
 
Author: Brian L. Evans, UT Austin
*/
static char* readStringFromStream(char* buffer, FILE* streamptr) 
{
  buffer[0] = 0;
  if ( ! feof(streamptr) ) {
    int slen;
    fgets(buffer, 256, streamptr);
    buffer[256 - 1] = 0;
    slen = strlen(buffer);
    if ( buffer[--slen] == '\n' )
      buffer[slen] = 0;
  }
  return buffer;
}

/*
Check for a safe path name for the Web-based version.
We don't allow users to write to directories above the
one they are currently in.
*/
static int safePathName(char* pathname) {
  int safeFlag = TRUE;
  if ( pathname == 0 ) safeFlag = FALSE;
  else if ( *pathname == 0 ) safeFlag = FALSE;
  else if ( *pathname == '/' ) safeFlag = FALSE;
  else if ( strchr(pathname, ':') ) safeFlag = FALSE;
  else if ( strstr(pathname, "..") ) safeFlag = FALSE;
  else if ( strchr(pathname, '~') ) safeFlag = FALSE;
  return safeFlag;
}

/*
Find the pathname of the file to be saved.
The syntax for the redirect and save commands is:

command arg1 ... argN pathname [-a|-o|-c]
*/
static char* findSavePathName(char* input) {
  int length = strlen(input);
  char* strptr = &input[length - 1];

  /* Remove trailing space */
  while ( ( strptr > input ) && ( isspace(*strptr) ) ) strptr--;

  /* Look for trailing option of -a, -o, or -c */
  if ( strptr > (input + 2)) {
    if ( ( *(strptr - 1) == '-' ) && ( isspace(*(strptr - 2)) ) ) {
      char lastChar = tolower(*strptr);
      if ( lastChar == 'a' || lastChar == 'o' || lastChar == 'c' ) {
	strptr -= 2;
	while ( ( strptr > input ) && ( isspace(*strptr) ) ) strptr--;
      }
    }
  }

  /* Skip the characters in the pathname */
  while ( ( strptr > input ) && !isspace(*strptr) ) strptr--;

  return (strptr + 1);
}

char *ut_get_command(char *cmdstr, int* processCommandPtr) {
    char* input = 0;
    *processCommandPtr = TRUE;

    /* prompt user for input */
    printf("\n%s", SIM_PROMPT);
    fflush(stdout);

    /* read user's input into cmdstr */
    input = readStringFromStream(cmdstr, stdin);
 
    /* trim the leading and trailing space */
    while ( *input && isspace(*input) ) input++;
    if ( *input ) {
	int length = strlen(input);
	char* endptr = &input[ length - 1];
	while ( (endptr >= input) && isspace(*endptr) ) endptr--;
	*(endptr + 1) = 0;
    }

    if ( *input == 0 ) {
	*input = 'd';
    }
    else if ( strcmp(input, "helplist") == 0 ) {
	*processCommandPtr = FALSE;
	printf ("commands={ asm break change copy device disassemble display down evaluate finish frame go help helplist history input list load log more next output path quit radix redirect reset save step streams system trace type unlock until up version view wait watch where }\n");
	fflush(stdout);
    }
    else if ( strncmp(input, "version", 2) == 0 ) {
	*processCommandPtr = FALSE;
	printf(VersionIdentification);
	fflush(stdout);
    } 
    else if ( *input == 'p' ) {
	*processCommandPtr = FALSE;                      /* insecure command */
	fprintf(stderr, CommandNotSupported, "path");
	fflush(stderr);
    }
    else if ( *input == 'a' ) {
	*processCommandPtr = FALSE;                  /* FIXME: implement asm */
	fprintf(stderr, CommandNotSupported, "asm");
	fflush(stderr);
    }
    else if ( ( strncmp(input, "change", 2) == 0 ) ||
	      ( strcmp(input, "c") == 0 ) ||
	      ( *input == 'c' && isspace(*(input + 1)) ) ) {
	*processCommandPtr = FALSE;               /* FIXME: implement change */
	fprintf(stderr, CommandNotSupported, "change");
	fflush(stderr);
    }
    else if ( strncmp(input, "finish", 2) == 0 ) {
	*processCommandPtr = FALSE;               /* FIXME: implement finish */
	fprintf(stderr, CommandNotSupported, "finish");
	fflush(stderr);
    }
    else if ( strncmp(input, "system", 2) == 0 ) {
	*processCommandPtr = FALSE;                      /* insecure command */
	fprintf(stderr, CommandNotSupported, "system");
	fflush(stderr);
    }
    else if ( strncmp(input, "redirect", 2) == 0 ) {
	*processCommandPtr = FALSE;                      /* insecure command */
	fprintf(stderr, CommandNotSupported, "redirect");
	fflush(stderr);
    }
    else if ( ( strncmp(input, "save", 2) == 0 ) ||
	      ( strcmp(input, "s") == 0 ) ||
	      ( *input == 's' && isspace(*(input + 1)) ) ||          /* save */
	      ( *input == 'o' ) ) {                                /* output */
	char* pathName = findSavePathName(input);
	*processCommandPtr = safePathName(pathName);
	if (! *processCommandPtr) {
	    fprintf(stderr,
		    "You have typed an unsafe pathname '%s'.\n"
		    "You can only save files to the current "
		    "directory and sub-directories.\n",
		    pathName);
	    fflush(stderr);
	}
    }
    return(input);
}

/*
Functions: format_command, format_string, and ut_simw_wscr

Implement a version of the Motorola simulator write screen function
simw_wscr so that output from that function would be displayed.  The
simw_wscr is disabled because simw_wscr assumes a type of terminal
which is undesirable for stream-based Web tools.  When one upgrades
to a new version of the CLAS tools, a call ut_simw_wscr should be
placed at the beginning of the definition of simw_wscr in scrmgr.c.
Also, you will need to include utsim.h at the beginning of scrmgr.c
to define the prototype for ut_simw_wscr.
*/
static char* format_command (char *ptr) {
  int c = 0;
  char *buf = (char *) malloc (strlen(ptr)+1);

  while (*ptr != '\0') {
    if (*ptr != '{' ) {
      if (*ptr != '}') buf[c++] = *ptr;
    }
    else {
      buf[c++]='\n';
    }
    ptr++;
  }
  buf[c] = 0;

  return buf;
}

static char* format_string (char *ptr) {
  int c = 0;
  unsigned char endWordFlag = 1;
  char *buf = (char *) malloc (strlen(ptr)+1);
 
  while (*ptr != '\0') {
    if (*ptr!='{' && *ptr!='}') {
      if (*ptr > 0x3c) {
	if(endWordFlag) {
	  buf[c++]='\n';
	  endWordFlag=0;
	}
	buf[c++]=*ptr;
      }
      else if (*ptr > 0x20) {
	if (endWordFlag) {
	  buf[c++]=' ';
	  endWordFlag=0;
	}
	buf[c++]=*ptr;
      }
      else {
	endWordFlag=1;
      }
    }
    ptr++;
  }
  buf[c] = 0;
  return buf;
}

void ut_simw_wscr(char* bufptr) {
  char* chk = strchr (bufptr, '=');
  if ( chk != NULL ) {
    char* ptr = format_string(bufptr);
    printf(ptr);
    fflush(stdout);
    free(ptr);
  }
  else {
    char* ptr = format_command(bufptr);
    printf(ptr);
    fflush(stdout);
    free(ptr);
  }
}
