/* For free support for VSIDE, please visit www.vsdsp-forum.com */

#include <vo_stdio.h>
#include <volink.h>     // Linker directives like DLLENTRY
#include <apploader.h>  // RunLibraryFunction etc
#include <consolestate.h>
#include <string.h>
#include <strings.h>
#include <vo_fat.h>
#include <ctype.h>
#include <kernel.h>
#include <sysmemory.h>

char tmpStr[256];
VO_FILE *f;


ioresult SetDirectory(register char *p, register u_int16 verbose) {
  ioresult retVal = S_OK;
  int currentDirectoryLen = strlen(currentDirectory);

#if 0
  printf("SetDirectory(%s, %d), currentDirectory=\"%s\"\n",
	 p, verbose, currentDirectory);
#endif

  if (!strcmp(p, "..") && (currentDirectoryLen > 2)) {
    char *p2 = &currentDirectory[currentDirectoryLen-1];
    *p2 = '\0';
    if (p2 = strrchr(currentDirectory, '/')) {
      p2[1] = '\0';
    } else {
      currentDirectory[2] = '\0';
    }
  } else if (strlen(p)==2 && p[1]==':') {
    DEVICE *newDisk;

    p[0] = toupper(p[0]);
    if (!isalpha(p[0])) {
      if (verbose) ListDevices();
    } else {
      newDisk = vo_pdevices[p[0]-'A']; 
      if (!newDisk) {
	if (verbose) {
	  printf("Disk %s not found. ", p);
	  ListDevices();
	}
	return S_ERROR;
      }
#if 0
      if (newDisk->Identify && (appFlags & APP_FLAG_ECHO) && verbose) {
	printf("%s %s\n", p, newDisk->Identify(newDisk, NULL, 0)); 
      }
#endif
      if (newDisk->fs != vo_filesystems[0]) {
	if (verbose) {
	  printf("Filesystem of device %s is not FAT.\n");
	}
	return S_ERROR;
      }
      strcpy(currentDirectory,p);
    }
  } else {
    f = fopen(currentDirectory, "s");
    if (!f || FatFindFirst(f, currentDirectory+2, tmpStr, sizeof(tmpStr)-1) != S_OK) {
      if (verbose) {
	printf("The current directory is not valid.");
      }
      retVal = S_ERROR;
    } else {
      do {
	if (f->ungetc_buffer & 0x0010) { /* Is directory */
	  int i;
#if 0
	  /* Short name */
	  char *newD = f->extraInfo;
#else
	  /* Long name */
	  char *newD = tmpStr;
#endif
	  if (!strcasecmp(p, tmpStr) || !strcasecmp(p, f->extraInfo)) {
	    /* Make space for potentially longer directory name than before. */
	    char *p = realloc(currentDirectory,
			      currentDirectoryLen+strlen(newD)+2);
#if 0
	    printf("curr=\"%s\" len=%d, newD=\"%s\"\n",
		   p, currentDirectoryLen, newD);
#endif
	    if (p) {
	      /* By copying extraInfo instead of s, we get the short name */
	      sprintf(p+currentDirectoryLen, "%s/", newD);
	      currentDirectory = p;
	    }
	    goto end_search;
	  }
	}
      } while (FatFindNext(f, tmpStr, sizeof(tmpStr)-1) == S_OK);
      if (verbose) {
	printf("Path not found\n");
      }
      retVal = S_ERROR;
  end_search:
      fclose(f);
    }
  }

  {
    /* Free space if possible. */
    char *p = realloc(currentDirectory, strlen(currentDirectory)+1);
    if (p) currentDirectory = p;
  }
  
  return retVal;
}



ioresult main(char *parameters) {
  u_int16 i;
  char *p = parameters;
  int nParam = RunProgram("ParamSpl", parameters);
  ioresult errCode = S_ERROR;
  s_int16 verbose = 1;
  char *oldDir = malloc(strlen(currentDirectory)+1);

  if (!oldDir) goto finally;
  
  strcpy(oldDir, currentDirectory);

  if (!nParam) {
    puts(currentDirectory);
    errCode = S_OK;
    goto finally;
  }

  for (i=0; i<nParam; i++) {
    if (!strcmp(p, "-h")) {
      printf("Usage: cd [-v|+v] [-h] dir\n"
	     "-v|+v\tTurn verbose on/off\n"
	     "-h\tShow this help\n"
	     "Note: cd without parameters shows the current directory\n"
	     "      cd :: lists all available devices\n");
      errCode = S_OK;
      goto finally;
    } else if (!strcmp(p, "-v")) {
      verbose = 1;
    } else if (!strcmp(p, "+v")) {
      verbose = 0;
    } else {
      char *nextDP = NULL;
      char drive[3] = "S:";

      /* If starts with drive definition */
      if (p[1] == ':') {
	drive[0] = p[0];
	p += 2;
	if (SetDirectory(drive, verbose)) {
	  goto finally;
	}
      }

      /* If directory starts with '/', go to main directory */
      if (p[0] == '/') {
	drive[0] = currentDirectory[0];
	p++;
	if (SetDirectory(drive, verbose)) {
	  goto finally;
	}
      }

      /* Go through each directory in the directory path. */
      do {
	if ((nextDP = strchr(p,'/'))) {
	  *nextDP = NULL;
	  nextDP++;
	}
	if (!*p || !strcmp(p, ".")) {
	  /* No-op */
	} else if (SetDirectory(p, verbose)) {
	  goto finally;
	}
	p = nextDP;
      } while (nextDP);
    }
    p += strlen(p)+1;
  }

  errCode = S_OK;
 finally:
  if (errCode) {
    if (oldDir) {
      strcpy(currentDirectory, oldDir);
    }
  }
  if (oldDir) {
    free(oldDir);
    oldDir = NULL;
  }

  return errCode;
}
