/* 6502dasm.c - R6502 Dissassembly */
/* Version 1.0  Jan 12 1996*/
/* Copyright © 1996 Sean Riddle/Jess Askey */

/* the data files must be kept compatible across systems! */

/* usage: 6502disasm <file> [<data file>] */
/* output to stdout, so use redirection */

/* The optional data file contains 7 types of lines: */
/* o Remarks - these are lines beginning with a semi-colon (;) */
/*   they are completely ignored. */
/* o 1 ORG line - gives the origin of the code; this is the starting */
/*   address to be used for the disassembly. */
/* o COMMENT lines - used to add comments to the end of lines of the */
/*   disassembly. */
/* o COMMENTLINE lines - provide full-line comments to be included before */
/*   a given address in the disassembly. */
/* o DATA lines - mark sections as data.  These sections will not be */
/*   disassembled, but dumped as hex data instead. */
/* o ASCII lines - mark sections as text.  These sections will not be */
/*   disassembled, but printed as text instead. */

/* See sample data files (*.dat) for examples. */

/* current limitations: */
/* o number of LABEL, DATA/ASCII, COMMENT and COMMENTLINE lines determined */
/*   at compile-time - see MAXLABEL, MAXDATA, MAXCOMMENT and MAXCOMMLINE */
/* o all DATA/ASCII lines in data file must be sorted in ascending */
/*   address order */
/* o ditto for COMMENT and COMMENTLINE lines */
/* o if a DATA/ASCII area is preceded by what 6502dasm thinks is code */
/*   that continues into the DATA/ASCII area, the data will not be marked */
/*   as such, and an error will be printed.  If this is the case, mark the */
/*   line before the data as data also. */

/*   Compiled on IBM 386DX40-w-Borland C++ V4.0  */

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

/* a few of my datatypes (from Amiga) */
#define TRUE (1==1)
#define FALSE (!TRUE)
typedef short BOOL;                                    /* boolean quantity */
typedef unsigned char UBYTE;                    /* unsigned 8-bit quantity */

/* array sizes for labels, DATA/ASCII definitions and COMMENT/COMMENTLINE */
#define MAXLABEL 999
#define MAXDATA 999                           /* both DATA and ASCII lines */
#define MAXCOMMENT 999
#define MAXCOMMLINE 999

/* output listing spacing */
#define TABOPNAME 17
#define TABOPERAND 28
#define TABCOMM 45

#define OPNAMETAB (TABOPNAME-1)
#define OPERANDTAB (TABOPERAND-1)
#define COMMTAB (TABCOMM-1)

typedef struct {                                       /* opcode structure */
   UBYTE opcode;                                     /* 8-bit opcode value */
   UBYTE numoperands;
   char name[6];                                            /* opcode name */
   UBYTE mode;                                          /* addressing mode */
   UBYTE numcycles;                         /* number of cycles - not used */
} opcodeinfo;
   
/* 6502 ADDRESSING MODES */
#define ACCUM  0
#define IMM    1
#define ABS    2
#define ZP     3
#define ZPX    4
#define ZPY    5
#define ABSX   6
#define ABSY   7
#define IMP    8
#define REL    9
#define INDX   10
#define INDY   11
#define IND    12
#define NUMPG1OPS 151

int numops[1]={NUMPG1OPS};

char modenames[13][6]={
	"accum",
	"imm",
	"abs",
	"zp",
	"zp,x",
	"zp,y",
	"abs,x",
	"abs,y",
	"imp",
	"rel",
	"ind,x",
	"ind,y",
	"ind",
};

opcodeinfo pg1opcodes[NUMPG1OPS]={                           /* page 1 ops */
  { 0,0,"BRK",IMP,7},
  { 1,1,"ORA",INDX,6},
  { 5,1,"ORA",ZP,3},
  { 6,1,"ASL",ZP,5},
  { 8,0,"PHP",IMP,3},
  { 9,1,"ORA",IMM,2},
  { 10,0,"ASL",ACCUM,2},
  { 13,2,"ORA",ABS,4},
  { 14,2,"ASL",ABS,6},

  { 16,1,"BPL",REL,2},
  { 17,1,"ORA",INDY,5},
  { 21,1,"ORA",ZPX,4},
  { 22,1,"ASL",ZPX,6},
  { 24,0,"CLC",IMP,2},
  { 25,2,"ORA",ABSY,4},
  { 29,2,"ORA",ABSX,4},
  { 30,2,"ASL",ABSX,7},

  { 32,2,"JSR",ABS,6},
  { 33,1,"AND",INDX,6},
  { 36,1,"BIT",ZP,3},
  { 37,1,"AND",ZP,3},
  { 38,1,"ROL",ZP,5},
  { 40,0,"PLP",IMP,4},
  { 41,1,"AND",IMM,2},
  { 42,0,"ROL",ACCUM,2},
  { 44,2,"BIT",ABS,4},
  { 45,2,"AND",ABS,4},
  { 46,2,"ROL",ABS,6},

  { 48,1,"BMI",REL,2},
  { 49,1,"AND",INDY,5},
  { 53,1,"AND",ZPX,4},
  { 54,1,"ROL",ZPX,6},
  { 56,0,"SEC",IMP,2},
  { 57,2,"AND",ABSY,4},
  { 61,2,"AND",ABSX,4},
  { 62,2,"ROL",ABSX,7},

  { 64,0,"RTI",IMP,6},
  { 65,1,"EOR",INDX,6},
  { 69,1,"EOR",ZP,3},
  { 70,1,"LSR",ZP,5},
  { 72,0,"PHA",IMP,3},
  { 73,1,"EOR",IMM,2},
  { 74,0,"LSR",ACCUM,2},
  { 76,2,"JMP",ABS,3,},
  { 77,2,"EOR",ABS,4},
  { 78,2,"LSR",ABS,6},

  { 80,1,"BVC",REL,2},
  { 81,1,"EOR",INDY,5},
  { 85,1,"EOR",ZPX,4},
  { 86,1,"LSR",ZPX,6},
  { 88,0,"CLI",IMP,2},
  { 89,2,"EOR",ABSY,4},
  { 93,2,"EOR",ABSX,4},
  { 94,2,"LSR",ABSX,7},

  { 96,0,"RTS",IMP,6},
  { 97,1,"ADC",INDX,6},
  { 101,1,"ADC",ZP,3},
  { 102,1,"ROR",ZP,5},
  { 104,0,"PLA",IMP,4},
  { 105,1,"ADC",IMM,2},
  { 106,0,"ROT",ACCUM,2},
  { 108,2,"JMP",IND,5},
  { 109,2,"ADC",ABS,4},
  { 110,2,"ROR",ABS,6},

  { 112,1,"BVS",REL,2},
  { 113,1,"ADC",INDY,5},
  { 117,1,"ADC",ZPX,4},
  { 118,1,"ROR",ZPX,6},
  { 120,0,"SEI",IMP,2},
  { 121,2,"ADC",ABSY,4},
  { 125,2,"ADC",ABSX,4},
  { 126,2,"ROR",ABSX,7},

  { 129,1,"STA",INDX,6},
  { 132,1,"STY",ZP,3},
  { 133,1,"STA",ZP,3},
  { 134,1,"STX",ZP,3},
  { 136,0,"DEY",IMP,2},
  { 138,0,"TXA",IMP,2},
  { 140,2,"STY",ABS,4},
  { 141,2,"STA",ABS,4},
  { 142,2,"STX",ABS,4},

  { 144,1,"BCC",REL,2},
  { 145,1,"STA",INDY,6},
  { 148,1,"STY",ZPX,4},
  { 149,1,"STA",ZPX,4},
  { 150,1,"STX",ZPY,4},
  { 152,0,"TYA",IMP,2},
  { 153,2,"STA",ABSY,5},
  { 154,0,"TXS",IMP,2},
  { 157,2,"STA",ABSX,5},

  { 160,1,"LDY",IMM,2},
  { 161,1,"LDA",INDX,6},
  { 162,1,"LDX",IMM,2},
  { 164,1,"LDY",ZP,3},
  { 165,1,"LDA",ZP,3},
  { 166,1,"LDX",ZP,3},
  { 168,0,"TAY",IMP,2},
  { 169,1,"LDA",IMM,2},
  { 170,0,"TAX",IMP,2},
  { 172,2,"LDY",ABS,4},
  { 173,2,"LDA",ABS,4},
  { 174,2,"LDX",ABS,4},

  { 176,1,"BCS",REL,2},
  { 177,1,"LDA",INDY,5},
  { 180,1,"LDY",ZPX,4},
  { 181,1,"LDA",ZPX,4},
  { 182,1,"LDX",ZPY,4},
  { 184,0,"CLV",IMP,2},
  { 185,2,"LDA",ABSY,4},
  { 186,0,"TSX",IMP,2},
  { 188,2,"LDY",ABSX,4},
  { 189,2,"LDA",ABSX,4},
  { 190,2,"LDX",ABSY,4},

  { 192,1,"CPY",IMM,2},
  { 193,1,"CMP",INDX,6},
  { 196,1,"CPY",ZP,3},
  { 197,1,"CMP",ZP,3},
  { 198,1,"DEC",ZP,5},
  { 200,0,"INY",IMP,2},
  { 201,1,"CMP",IMM,2},
  { 202,0,"DEX",IMP,2},
  { 204,2,"CPY",ABS,4},
  { 205,2,"CMP",ABS,4},
  { 206,2,"DEC",ABS,6},

  { 208,1,"BNE",REL,2},
  { 209,1,"CMP",INDY,5},
  { 213,1,"CMP",ZPX,4},
  { 214,1,"DEC",ZPX,6},
  { 216,0,"CLD",IMP,2},
  { 217,2,"CMP",ABSY,4},
  { 221,2,"CMP",ABSX,4},
  { 222,2,"DEC",ABSX,7},

  { 224,1,"CPX",IMM,2},
  { 225,1,"SBC",INDX,6},
  { 228,1,"CPX",ZP,3},
  { 229,1,"SBC",ZP,3},
  { 230,1,"INC",ZP,5},
  { 232,0,"INX",IMP,2},
  { 233,1,"SBC",IMM,2},
  { 234,0,"NOP",IMP,2},
  { 236,2,"CPX",ABS,4},
  { 237,2,"SBC",ABS,4},
  { 238,2,"INC",ABS,6},

  { 240,1,"BEQ",REL,2},
  { 241,1,"SBC",INDY,5},
  { 245,1,"SBC",ZPX,4},
  { 246,1,"INC",ZPX,6},
  { 248,0,"SED",IMP,2},
  { 249,2,"SBC",ABSY,4},
  { 253,2,"SBC",ABSX,4},
  { 254,2,"INC",ABSX,7},

};

opcodeinfo *pgpointers[1]={pg1opcodes};

int count;                             /* current program counter for disasm */

/* getbyte() - get a byte from a file, and increment the byte counter */
int getbyte(FILE *fp) {
   int c;

   count++;
   c=getc(fp);
   return(c);
}

      
#define LABELSIZE 40
/* label structure */
struct lastruct {
   unsigned short lab;                                    /* label address */
   char label[LABELSIZE];                                    /* label text */
} *labarray=NULL;
int numlab=0;                                  /* number of labels defined */

#ifndef AMIGA
/* hmmm, these aren't ANSI */
/* stricmp() - compare two strings, case insensitive */
int stricmp(const char *s1, const char *s2) {
   for(;toupper(*s1)==toupper(*s2);++s1,++s2)
      if(*s1=='\0')
         return(0);
   return((toupper(*(unsigned char *)s1)<toupper(*(unsigned char *)s2))?-1:1);
}

/* strnicmp() - compare two strings, case insensitive, length limited */
int strnicmp(const char *s1, const char *s2, size_t n) {
   for(;0<n;++s1,++s2,--n)
      if(toupper(*s1)!=toupper(*s2))
         return((toupper(*(unsigned char *)s1)<
               toupper(*(unsigned char *)s2))?-1:1);
      else if(*s1=='\0')
         return(0);
   return(0);
}
#endif

char labtemp[30];                   /* global return for checklabs() - tsk */

/* checklabs() - check the defined labels from data file */
/* substitute label for address if found */
char *checklabs(int address,BOOL lab2,BOOL printdollar,BOOL X,BOOL Y) {
   int i;
	address&=0xffff;
   labtemp[0]='\0';
   for(i=0;i<numlab;i++)
      if(address==labarray[i].lab) {
         sprintf(labtemp,"%s",labarray[i].label);
         if(lab2)
            strcat(labtemp,":\n");
         i=numlab;
      }
   if(!strlen(labtemp)&&!lab2) {
		if(printdollar){
			sprintf(labtemp,"$%04hX",address);
		}
		else {
			sprintf(labtemp,"%04hX",address);
		}
		if(X) {
			strcat(labtemp,",X");
		}
		if(Y) {
			strcat(labtemp,",Y");
		}
	}
   return(labtemp);
}

/* printoperands() - print operands for the given opcode */
void printoperands(int opcode,UBYTE numoperands,UBYTE *operandarray,
		UBYTE mode,char *str) {
	int rel;
	char out2[80];
	BOOL printdollar=FALSE;            /* print a leading $? before address */
	BOOL zp=FALSE;                     /* print a 00?? before address       */
	BOOL X=FALSE;		 					  /* print a ,X after address          */
	BOOL Y=FALSE;							  /* print a ,Y after address          */
	BOOL skip=FALSE;

	switch(mode) {                              /* print before operands */
			case IMM:
				strcat(str,"#");
				break;
			case ZPY:
				Y=TRUE;
				zp=TRUE;
				break;
			case ZPX:
				X=TRUE;
			case ZP:
				zp=TRUE;
				break;
			case ABSX:
				X=TRUE;
				printdollar=TRUE;
				break;
			case ABSY:
				Y=TRUE;
			case ABS:
            printdollar=TRUE;
				break;
			case REL:                             /* 8-bit relative */
				rel=operandarray[0];
				strcat(str,"Branch->");
				sprintf(out2,checklabs((short)(count+((rel<128) ? rel : rel-256)),
					FALSE,TRUE,FALSE,FALSE));
				strcat(str,out2);
				skip=TRUE;
				break;
			case IMP:
				if(opcode==0x00)
					strcat(str,"BREAK");
				if(opcode==0x08)
					strcat(str,"Push P");
				if(opcode==0x18)
					strcat(str,"Clear Carry");
				if(opcode==0x28)
					strcat(str,"Pull P");
				if(opcode==0x38)
					strcat(str,"Set Carry");
				if(opcode==0x40)
					strcat(str,"Ret from Int");
				if(opcode==0x48)
					strcat(str,"Push Accum");
				if(opcode==0x58)
					strcat(str,"Enable IRQ");
				if(opcode==0x60)
					strcat(str,"Ret from Sub");
				if(opcode==0x68)
					strcat(str,"Pull Accum");
				if(opcode==0x78)
					strcat(str,"Disable IRQ");
				if(opcode==0x88)
					strcat(str,"Y=Y-1");
				if(opcode==0x8A)
					strcat(str,"X-->A");
				if(opcode==0x98)
					strcat(str,"Y-->A");
				if(opcode==0x9A)
					strcat(str,"X-->Stack");
				if(opcode==0xA8)
					strcat(str,"A-->Y");
				if(opcode==0xAA)
					strcat(str,"A-->X");
				if(opcode==0xB8)
					strcat(str,"Clear Overflow");
				if(opcode==0xBA)
					strcat(str,"Stack-->X");
				if(opcode==0xC8)
					strcat(str,"Y=Y+1");
				if(opcode==0xCA)
					strcat(str,"X=X-1");
				if(opcode==0xD8)
					strcat(str,"Unset Decimal");
				if(opcode==0xE8)
					strcat(str,"X=X+1");
				if(opcode==0xEA)
					strcat(str,"No Operation");
				if(opcode==0xF8)
					strcat(str,"Set Decimal");
			 default:
				break;
		}
		if(!skip){
			switch(numoperands) {
				case 2:
					strcat(str,checklabs((operandarray[1]<<8)+operandarray[0],
					FALSE,TRUE,X,Y));
					break;
				case 1: {
					if(zp) {
						sprintf(out2,"Zp RAM 00%02X",operandarray[0]);
						strcat(str,out2); }
					else {
						sprintf(out2,"%02X",operandarray[0]);
						strcat(str,out2);
					}
				}
					break;
				default:
					break;
			}
		}
}

#define DATA 0                                  /* type of data to display */
#define ASCII 1

/* DATA/ASCII structure definition */
struct dastruct {
   unsigned short start;                /* beginning address of DATA/ASCII */
   unsigned short end;                                   /* ending address */
   unsigned short per_line;                   /* values to print on a line */
   short type;                                          /* DATA or ASCII ? */
} *dataarray=NULL;

#define COMMENTSIZE 80
/* COMMENT/COMMENTLINE structure definition */
struct castruct {
   unsigned short comline;                         /* comment line address */
   char comment[COMMENTSIZE];                              /* comment text */
} *commarray=NULL,*commlinearray=NULL;

char out[512],out2[80];                             /* temp string buffers */

void readdatafile(char *filename,
      int *org,int *numlab,int *numdata,int *numcomm,int *numcommline) {
   char line2[256];
   char *line;
   FILE *fp;
   int dataline,data,data2,per_line,i,k;

	if(fp=fopen(filename,"r")) {                          /* read data file */
      while(fgets(line2,255,fp)) {
         while(strlen(line2)&&!isprint(line2[strlen(line2)-1])) /* strip cr */
            line2[strlen(line2)-1]='\0';
         for(i=0;i<strlen(line2);i++)
            if((line2[i]==';')||isalpha(line2[i])) {
               line= &(line2[i]);
               i=strlen(line2);
            }
         if(!strnicmp(line,"ORG ",4)) {
            if(*org==-1)
               sscanf(&line[4],"%X",org);
            else
               printf("More than one ORG line\n");
         } else if(!strnicmp(line,"LABEL ",6)) {
            if(*numlab<MAXLABEL) {
               sscanf(&line[6],"%X",&dataline);
               labarray[*numlab].lab=dataline;
               k=6;
               while(line[k]==' ')
                  k++;
               while(line[k]!=' ')
                  k++;
               while(line[k]==' ')
                  k++;
               strncpy(labarray[*numlab].label,&line[k],LABELSIZE);
               labarray[*numlab].label[LABELSIZE-1]=0;  /* just in case */
               for(i=0;i<*numlab;i++)
                  if(!strcmp(labarray[i].label,labarray[*numlab].label)) {
                     printf("duplicate label: %s\n",labarray[i].label);
                     break;
                  }
               if(i>=*numlab)   
                  (*numlab)++;
            } else
               printf("Too many labels\n");
         } else if(!strnicmp(line,"DATA ",5)) {
            if(*numdata<MAXDATA) {
               data2=0;
               sscanf(&line[5],"%X-%X",&data,&data2);
               k=5;
               while(line[k]==' ')
                  k++;
               while(line[k]!=' ')
                  k++;
               while(line[k]==' ')
                  k++;
               if (k < i)
                  sscanf(&(line[k]),"%d",&per_line);
               else
                  per_line = 0;
               if(data2<data)
                  data2=data;
               dataarray[*numdata].type=DATA;
               dataarray[*numdata].start=data;
               dataarray[*numdata].end=data2;
               dataarray[*numdata].per_line=per_line;
               if(((*numdata)&&(dataarray[*numdata-1].start<
                     dataarray[*numdata].start))||!*numdata)
                  (*numdata)++;
               else
                  printf("`%s'\nDATA out of order\n\n",line);
            } else
               printf("Too many DATA/ASCII lines\n");
         } else if(!strnicmp(line,"ASCII ",6)) {
            if(*numdata<MAXDATA) {
               data2=0;
               per_line=0;
               sscanf(&line[6],"%X-%X %d",&data,&data2,&per_line);
               if(data2<data)
                  data2=data;
               dataarray[*numdata].type=ASCII;
               dataarray[*numdata].start=data;
               dataarray[*numdata].end=data2;
               dataarray[*numdata].per_line=per_line;
               if(((*numdata)&&(dataarray[*numdata-1].start<
                     dataarray[*numdata].start))||!*numdata)
                  (*numdata)++;
               else if(*numdata)
                  printf("`%s'\nASCII out of order\n\n",line);
            } else
               printf("Too many DATA/ASCII lines\n");
			} else if(!strnicmp(line,"COMMENT ",8)) {
				if(*numcomm<MAXCOMMENT) {
               sscanf(&line[8],"%X",&dataline);
               commarray[*numcomm].comline=dataline;
                              
               k=8;
               while(line[k]==' ')
                  k++;
               while(line[k]!=' ')
                  k++;
               while(line[k]==' ')
                  k++;
               strncpy(commarray[*numcomm].comment,&line[k],COMMENTSIZE);
               commarray[*numcomm].comment[COMMENTSIZE-1]=0; /* in case */

               if(((*numcomm)&&(commarray[(*numcomm)-1].comline<=
                     commarray[*numcomm].comline))||!*numcomm)
                  (*numcomm)++;
               else
                  printf("`%s'\nCOMMENT out of order\n\n",line);
            } else
               printf("Too many COMMENT lines\n");
         } else if(!strnicmp(line,"COMMENTLINE ",12)) {
            if(*numcommline<MAXCOMMLINE) {
               sscanf(&line[12],"%X",&dataline);
               commlinearray[*numcommline].comline=dataline;
               k=12;
               while(line[k]==' ')
                  k++;
               while(line[k]!=' ')
                  k++;
               while(line[k]==' ')
                  k++;
               strncpy(commlinearray[*numcommline].comment,
                     &line[k],COMMENTSIZE);
               commlinearray[*numcommline].comment[COMMENTSIZE-1]=0;
               
               if(((*numcommline)&&(commlinearray[(*numcommline)-1].comline<=
                     commlinearray[*numcommline].comline))||!*numcommline)
                  (*numcommline)++;
               else
                  printf("`%s'\nCOMMENTLINE out of order\n\n",line);
            } else
               printf("Too many COMMENTLINE lines\n");
         } else if(line[0]==';')                    /* remark in data file */
				;
         else if(strlen(line))
            printf("`%s'\nError in file `%s'\n\n",line,filename);
      }
      fclose(fp);
   } else
		fprintf(stderr,"Can't open data file `%s'\n",filename);
}

void docomment(int line,int *curcomm,int numcomm,int numoperands) {
   int  sp;
   BOOL first_comment = TRUE;

   if(!numcomm)
      return;
   if(*curcomm<numcomm) {                 /* see if we've passed a comment */
      while(((line-1)>commarray[*curcomm].comline+numoperands)&&
            (*curcomm<numcomm)) {
         printf("Error: missed a comment at %X, line=%X\n",
               commarray[*curcomm].comline,line);
         (*curcomm)++;
      }

      while((((line-1)+numoperands)>=commarray[*curcomm].comline)||
            ((line==commarray[*curcomm].comline)&&(numoperands==1))||
            (((line-1)==commarray[*curcomm].comline)&&(numoperands==0))) {
         if(*curcomm>=numcomm)
				break;
			if(first_comment!=TRUE) {
				printf("%s\n",out);
				out[0]='\0';
			}
         for(sp=strlen(out);sp<COMMTAB;sp++)
            strcat(out," ");
         strcat(out,";");
         strcat(out,commarray[*curcomm].comment);
         (*curcomm)++;
			first_comment=FALSE;
      }
   }
}

void docommline(int line,int *curcommline,int numcommline) {
   BOOL didone=FALSE;
   
   if(!numcommline)
      return;
   if(*curcommline<numcommline) {     /* see if we've passed a comment line*/
      while(((line-1)>commlinearray[*curcommline].comline)&&
            (*curcommline<numcommline)) {
         printf("Error: missed a comment line at %X, line=%X\n",
               commlinearray[*curcommline].comline,line);
         (*curcommline)++;
      }

      while(((line-1)==commlinearray[*curcommline].comline)) {
         if(!didone)
            printf("\n");
         printf("*** %s\n",commlinearray[*curcommline].comment);
         (*curcommline)++;
         didone=TRUE;
      }

   }
}

BOOL newl=FALSE;
char wchars[15]={
   "<=-?!()',./&\":"
};


BOOL diddata=FALSE;

int dumpdata(int opcode,int *curdata,int numdata,FILE *fp,
      int *curcomm,int numcomm,int *curcommline,int numcommline) {
   int pnum,tnum;
   int numoperands;
   int k;
   int numchars=0;
   
   numoperands=2+dataarray[*curdata].end-count;
   pnum=dataarray[*curdata].per_line;       /* print up to pnum bytes data */
   if(dataarray[*curdata].type==DATA) {
      sprintf(out2,"%02X ",(UBYTE)opcode);
      strcat(out,out2);
      if((pnum<1)||(pnum>24))
         pnum=16;                       /* no more than 24 bytes hex data */
   } else {
	   out2[0]=opcode;
		out2[1]='\0';
		strcat(out,out2);
      if((pnum<1)||(pnum>70))
         pnum=32;                      /* no more than 70 bytes ASCII data */
   }
   newl=FALSE;
   tnum=(pnum>numoperands)?numoperands-2:pnum-1;
   for(k=0;k<numoperands-1;k++) {                        /* print the data */
      if((++numchars>=pnum)||newl) {
         if((tnum)||(pnum==1)) {
            docomment(count-tnum,curcomm,numcomm,tnum);
            docommline(count-tnum,curcommline,numcommline);
         }
         printf("%s\n",out);
         sprintf(out,"%04X: ",count);
         numchars=0;
         newl=FALSE;
      }
      if(dataarray[*curdata].type==DATA)
         sprintf(out2,"%02X ",getbyte(fp));                         /* hex */
      else {
				out2[0]=getbyte(fp);                                  /* ASCII */
				out2[1]='\0';
      }
      strcat(out,out2);
   }
   if(*curdata<numdata)
      (*curdata)++;
	diddata=TRUE;
	return(numoperands-2);
}

void freearrays(void) {
   if(labarray)
      free(labarray);
   if(dataarray)
      free(dataarray);
   if(commarray)
      free(commarray);
   if(commlinearray)
		free(commlinearray);
}

BOOL mallocarrays(void) {
   BOOL gotit=FALSE;
   
	if(labarray=(struct lastruct *)malloc(sizeof(struct lastruct)*MAXLABEL))
      if(dataarray=(struct dastruct *)
            malloc(sizeof(struct dastruct)*MAXDATA))
         if(commarray=(struct castruct *)
               malloc(sizeof(struct castruct)*MAXCOMMENT))
				if(commlinearray=(struct castruct *)
                  malloc(sizeof(struct castruct)*MAXCOMMLINE))
               gotit=TRUE;
   if(!gotit)
      freearrays();
   return(gotit);
}

void main(int argc,char *argv[]) {
   int i,j,k;
	int opcode;
   UBYTE operand[4];
   FILE *fp;
   int org=~0;

   int numoperands;
   int sp;
   int numcomm=0,numdata=0,numcommline=0;
	int curcomm=0,curdata=0,curcommline=0;

	
	if(argc>1) {
		if(!stricmp(argv[1],"list")) {              /* show all instructions */
         for(i=0;i<numops[0];i++)
				printf("opcode %02X %3s %10s IBytes-> %d,  cycles->%d\n",
						pg1opcodes[i].opcode,pg1opcodes[i].name,
						modenames[pg1opcodes[i].mode],pg1opcodes[i].numoperands,
						pg1opcodes[i].numcycles);
		}
		else {
         if(!mallocarrays()) {
            printf("Can't get memory for arrays\n");
            exit(20);
			}


			if(argc>2)
				readdatafile(argv[2],&org,&numlab,&numdata,&numcomm,&numcommline);
			if(org!=-1)                              /* int PC to ORG val or 0 */
            count=org;
         else
				count=0;

         for(k=0;k<numlab;k++)                       /* print labels first */
            printf("%s EQU $%04X\n",labarray[k].label,labarray[k].lab);
         if(numlab)
            printf("\n");
         printf("ORG $%04X\n",count);

			if(fp=fopen(argv[1],"rb")) {            /* open binary file */
            while((opcode=getbyte(fp))!=EOF) {
					docommline(count,&curcommline,numcommline);
					printf(checklabs(count-1,TRUE,FALSE,FALSE,FALSE)); /*if add lab*/
					sprintf(out,"%04X ",count-1);

					if(numdata) {
                  while(((count-1)>dataarray[curdata].end)&&
                        (curdata<numdata)) {
                     printf("Error: missed a data line, start=%X, end=%X\n",
                           dataarray[curdata].start,dataarray[curdata].end);
                     curdata++;
					}
				}
				if(numdata&&
                     ((count-1)>=dataarray[curdata].start)&&  /* data? */
                     ((count-1)<=dataarray[curdata].end)) {
                  numoperands=dumpdata(opcode,&curdata,numdata,fp,
                        &curcomm,numcomm,&curcommline,numcommline);
                  i=numops[0]+1;             /* skip decoding as an opcode */
               } else {                    /* not data - search for opcode */
						sprintf(out2,"%02X:",(UBYTE)opcode);
                  strcat(out,out2);
                  for(i=0;(i<numops[0])&&(pg1opcodes[i].opcode!=opcode);i++)
                     ;
               }
					if(i<numops[0]) {                           /* opcode found */
							numoperands=pg1opcodes[i].numoperands;
                     for(j=0;j<numoperands;j++) {
                        sprintf(out2,"%02X ",(operand[j]=getbyte(fp)));
                        strcat(out,out2);
							}
							for(sp=strlen(out);sp<OPNAMETAB;sp++)
                           strcat(out," ");
							sprintf(out2,"%s:%s",pg1opcodes[i].name,
								modenames[pg1opcodes[i].mode]);
							strcat(out,out2);
							for(sp=strlen(out);sp<OPERANDTAB;sp++)
								 strcat(out," ");
							printoperands(opcode,numoperands,operand,
									pg1opcodes[i].mode,out);
                  }
					else if(i==numops[0]) {            /* not found in page 1 */
                  for(sp=strlen(out);sp<OPNAMETAB;sp++)  
                     strcat(out," ");
                  strcat(out,"Illegal Opcode");
               }
               docomment(count-1-numoperands,&curcomm,numcomm,numoperands+1);
					if(diddata) {
						if(strlen(out)&&(out[strlen(out)-1]!='\n'))
                     strcat(out,"\n");
               }
					printf("%s\n",out);
					diddata=FALSE;
				}
            fclose(fp);
			} else
				fprintf(stderr,"Can't open file `%s'\n",argv[1]);
		}
   } else
      printf("Usage: `%s <file> [<datafile>]'\n",argv[0]);
   freearrays();
}
