/*

  P-Code interpreter (to run the apple pascal system)
  Copyright (C) 2000 Mario Klebsch

  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.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


  $Log: svolio.c,v $
  Revision 1.5  2001/05/26 15:13:29  mario
  Diverse kleine Fehler behoben, fehlende #includes, Labels ohne Statement
  dahinter, ...

  Revision 1.4  2001/05/21 19:06:48  mario
  Mode-Parameter bei den Disk-IO-Routinen entfernt

  Revision 1.3  2001/05/20 20:35:22  mario
  svolio ruft die Disk-I/O-Routinen jetzt direkt auf.

  Revision 1.2  2001/05/20 13:12:02  mario
  CVS-Idents und Logs eingefügt


*/

#ident "$Id: svolio.c,v 1.5 2001/05/26 15:13:29 mario Exp $";

#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>

#include "psystem.h"
#include "Memory.h"
#include "Diskio.h"

word Syscom;
word IoResult=0;

int List=0;
int Text=0;
int ExtList=0;

char *Month[16]={ "???", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
		  "Aug", "Sep", "Oct", "Nov", "Dec", "???", "???", "???"};

char *FileTypes[8]= {"Svol", "Bad ", "Code", "Text", 
		     "Info", "Data", "Graf", "Foto" };

void warning(char *Msg, ...)
{
  va_list ap;
  char	Buffer[512];
  va_start(ap, Msg);
  vsnprintf(Buffer, sizeof(Buffer), Msg, ap);
  va_end(ap);
  fprintf(stderr,"warning: %s\n", Buffer);
}

void XeqError(word err)
{
  fprintf(stderr,"XeqError: %d\n", err);
  exit(-1);
}

void IoError(word err)
{
  IoResult=err;
}

void DoList(word Unit)
{
  int i;
  int len;
  word Entry;
  word w;
  word NumBlocks;
  word NumFiles;
  word FreeBlocks;
  word MaxFree;
  word LastBlock;
  word Free;

  DiskRead(Unit, 0x100, 0, 2048, 2);
  if (IoResult)
    {
      fprintf(stderr,"DoList: Directory read error\n");
      exit(1);
    }

  if (MemRd(WordIndexed(0x100,  8))&0xff00)
    SwapBytes=!SwapBytes;

  Entry=0x100;
  NumBlocks=MemRd(WordIndexed(Entry,  7));
  LastBlock=MemRd(WordIndexed(Entry,  1));
  NumFiles=MemRd(WordIndexed(Entry,  8));
  FreeBlocks=0;
  MaxFree=0;

  if (ExtList)
    {
      Entry=0x100;
      for (len=0; len<MemRdByte(WordIndexed(Entry, 3),0); len++)
	{
	  char ch=MemRdByte(WordIndexed(Entry, 3),1+len);
	  if (isupper(ch))
	    ch=tolower(ch);
	  putchar(ch);
	}
      putchar(':');
      putchar('\n');
    }
  
  for (i=0;i<NumFiles;i++)
    {
      Entry=WordIndexed(0x100, 13+13*i);

      if (ExtList)
	if (MemRd(WordIndexed(Entry,  0))>LastBlock)
	  {
	    Free=MemRd(WordIndexed(Entry,  0))-LastBlock;
	    printf("< unused >     %5d           %5d\n", Free, LastBlock);
	    FreeBlocks += Free;
	    if (Free>MaxFree)
	      MaxFree=Free;
	  }
      LastBlock=MemRd(WordIndexed(Entry,  1));

      for (len=0; len<MemRdByte(WordIndexed(Entry, 3),0); len++)
	{
	  char ch=MemRdByte(WordIndexed(Entry, 3),1+len);
	  if (isupper(ch))
	    ch=tolower(ch);
	  putchar(ch);
	}

      if (ExtList)
	{
	  for (; len<15; len++)
	    putchar(' ');
      
	  w=MemRd(WordIndexed(Entry, 12));
	  printf("%5d %2d-%3s-%02d %5d %5d %4sfile",
		 MemRd(WordIndexed(Entry, 1)) - MemRd(WordIndexed(Entry, 0)),
		 (w>>4)&0x1f, Month[w&0x0f], w>>9,
		 MemRd(WordIndexed(Entry,  0)),
		 MemRd(WordIndexed(Entry, 11)),
		 FileTypes[MemRd(WordIndexed(Entry, 2))&0x07]);
	}
      putchar('\n');
    }

  if (ExtList)
    {
      if (NumBlocks>LastBlock)
	{
	  Free=NumBlocks-LastBlock;
	  printf("< unused >     %5d           %5d\n", Free, LastBlock);
	  FreeBlocks += Free;
	  if (Free>MaxFree)
	    MaxFree=Free;
	}
      printf("%d files, %d blocks used, %d unused, %d in largest\n",
	     NumFiles, NumBlocks-FreeBlocks, FreeBlocks, MaxFree);
    }
}

word LookupFile(word Unit, const char *Name, word *Offset,
		word *Len, word *Last)
{
  int i;
  DiskRead(Unit, 0x100, 0, 2048, 2);
  if (IoResult)
    return(0);

  if (MemRd(WordIndexed(0x100,  8))&0xff00)
    SwapBytes=!SwapBytes;

  for (i=0;i<MemRd(WordIndexed(0x100, 8));i++)
    {
      word Entry=WordIndexed(0x100, 13+13*i);
      int len;
      for (len=0; len<MemRdByte(WordIndexed(Entry, 3),0); len++)
	if (toupper(MemRdByte(WordIndexed(Entry, 3),1+len)) !=
	    toupper(Name[len]))
	  goto next;
      if (Name[len])
	continue;
	
      *Offset=MemRd(WordIndexed(Entry,0));
      *Len=MemRd(WordIndexed(Entry,1));
      *Last=MemRd(WordIndexed(Entry,11));

      return(1);
    next:
      ;
    }
  return(0);
}

int main(int argc, char *argv[])
{
  int i;

  Syscom=WordIndexed(0xfffe, -SYSCOM_SIZE);

  while ((i=getopt(argc, argv, "elt"))!=EOF)
    switch(i)
      {
      case 'e':
	ExtList=1;
	List=1;
	break;
      case 'l':
	List=1;
	break;
      case 't':
	Text=1;
	break;
      }

  if (optind<argc)
    DiskMount(4, argv[optind++], ReadOnly);
  else
    {
      fprintf(stderr,"%s: Needs filename argument\n", argv[0]);
      exit(1);
    }

  if (List)
    {
      DoList(4);
      exit(0);
    }
  if (optind<argc)
    {
      word Offset, End, Last;
      char *name=argv[optind++];
      if (!LookupFile(4, name, &Offset, &End, &Last))
	{
	  fprintf(stderr, "%s: File not found\n", name);
	  exit(1);
	}

      if (Text)
	Offset +=2;

      while (Offset<End)
	{
	  int Size=(End-Offset-1)*512+Last;
	  if (Size>1024)
	    Size=1024;
	  DiskRead(4, 0x100, 0, Size, Offset);
	  for (i=0; i<Size; i++)
	    {
	      char ch=MemRdByte(0x100,i);
	      if (Text)
		{
		  if (ch==0x10)
		    {
		      i++;
		      for (ch=MemRdByte(0x100,i); ch>0x20; ch--)
			write(1," ", 1);
		    }
		  else if (ch==0)
		    break;
		  else
		    {
		      if (ch==0x0d)
			ch='\n';
		      write(1, &ch, 1);
		    }
		}
	      else
		write(1, &ch, 1);
	    }
	  Offset+=2;
	}
    }
  else
    {
      fprintf(stderr,"%s: Needs filename argument\n", argv[0]);
      exit(1);
    }
  exit(0);
}
