well some time ago I coded Win32 utility to convert MDOS 3.0 *.P
files (which are the same as BASIC tap files) into text. You need the keyword/command table for that. Here is the VCL/C++ code extracted from the tool of mine:
// all ZX ASCII codes from 165 to 255 are BASIC commands
const AnsiString zx_table[91]=
{
" RND "," INKEY$ "," PI "," FN "," POINT "," SCREEN$ "," ATTR "," AT "," TAB "," VAL$ "," CODE "," VAL "," LEN "," SIN "," COS "," TAN "," ASN "," ACS ",
" ATN "," LN "," EXP "," INT "," SOR "," SGN "," ABS "," PEEK "," IN "," USR "," STR$ "," CHR$ "," NOT "," BIN "," OR "," AND "," <="," >="," <>"," LINE ",
" THEN "," TO "," STEP "," DEF "," CAT "," FORMAT "," MOVE "," ERASE "," OPEN# "," CLOSE# "," MERGE "," VERIFY "," BEEP "," CIRCLE "," INK "," PAPER ",
" FLASH "," BRIGHT "," INVERSE "," OVER "," OUT "," LPRINT "," LLIST "," STOP "," READ "," DATA "," RESTORE "," NEW "," BORDER "," CONTINUE "," DIM ",
" REM "," FOR "," GOTO "," GOSUB "," INPUT "," LOAD "," LIST "," LET "," PAUSE "," NEXT "," POKE "," PRINT "," PLOT "," RUN "," SAVE "," RANDOMIZE ",
" IF "," CLS "," DRAW "," CLEAR "," RETURN "," COPY "
};
void editor::loadzxbas(AnsiString file)
{
txt="";
win_adr=1;
win_x0=0;
win_y0=0;
sbys=0;
_redraw=true;
_change=false;
int hnd,siz;
BYTE *dat;
hnd=FileOpen(file,fmOpenRead);
if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new char[siz];
if (dat==NULL) { FileClose(hnd); return; }
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
int i,l,a,_a,linenum;
AnsiString s;
DWORD a0,a1,a2,a3,a4;
for (hnd=0;hnd<siz;) // copy and count lines
{
if (hnd>=siz) break; // line number
a0=dat[hnd]; hnd++;
if (hnd>=siz) break;
a1=dat[hnd]; hnd++;
linenum=(a1+(a0<<8));
if (linenum<10000) txt+=" ";
if (linenum< 1000) txt+=" ";
if (linenum< 100) txt+=" ";
if (linenum< 10) txt+=" ";
txt+=linenum;
txt+=" ";
if (hnd>=siz) break; // line length
a0=dat[hnd]; hnd++;
if (hnd>=siz) break;
a1=dat[hnd]; hnd++;
l=(a0+(a1<<8));
for (s="",i=0;i<l;i++) // load line
{
if (hnd>=siz) break;
a=dat[hnd]; hnd++;
s+=char(a);
}
l=i;
if (linenum<=9999) // BASIC lines
for (a=0,i=1;i<=l;)
{
_a=a;
a=BYTE(s[i]); i++;
if (a>=165) txt+=zx_table[a-165];
else if (a>=32) txt+=char(a);
if (a==14) // number
{
if (i+5>l) break;
a0=BYTE(s[i]); i++;
a1=BYTE(s[i]); i++;
a2=BYTE(s[i]); i++;
a3=BYTE(s[i]); i++;
a4=BYTE(s[i]); i++;
if ((_a<'0')||(_a>'9'))
{
if (a0==0) // int
{
int x;
x=a2+(a3<<8);
if (a1) x=-x;
txt+=x;
}
else{ // float
txt+="/float/";
}
}
}
}
else{ // Data area
int x=0,n=8;
AnsiString t;
for (i=1;i<=l;)
{
a=BYTE(s[i]); i++;
if (x) txt+=",";
else { if (i>2) txt+=" "; txt+=" db "; t=" // "; }
if (a<16) txt+="0";
txt+=AnsiString().sprintf("%X",BYTE(a)); x++;
if ((a<32)||(a>164)) t+="."; else t+=char(BYTE(a));
if (x>=n) { txt+=t+"\n"; x=0; sbys++; }
}
if (x)
{
for (;x<n;x++) txt+=" ";
txt+=t+"\n"; x=0; sbys++;
}
}
txt+="\n"; sbys++;
}
delete dat;
}
//---------------------------------------------------------------------------
where editor::txt
is AnsiString
containing your decoded text. You can ignore the _redraw,_change
bools they are just for proper redraw and save of teh editor class. There are 2 things going on.
ASCII codes above 164
are the BASIC keywords/commands so you need to swap them with the string from the zx_table[]
numbers
ASCII code 14
marks number and needs to be properly decoded to string.
The AnsiString
is a VCL string variable type indexed from 1
. With all this you should have all you need to code/port this on your own to Linux ...
btw the tool of mine recognize x86 asm, Z80 asm and BASIC files with syntax highlight. Here a META thread related to its syntax highlight:
And here non class code with syntax highlight tables (from another tool of mine):
//---------------------------------------------------------------------------
//--- syntax ver: 1.02 ------------------------------------------------------
//---------------------------------------------------------------------------
#include "font_DG89.h"
//---------------------------------------------------------------------------
const _editor_syntax syntax_Z80_asm=
{
// keywords
{ "ADC","ADD","AND","BIT","CALL","CCF","CP","CPD","CPDR","CPI","CPIR","CPL","DAA",
"DEC","DI","DJNZ","EI","EX","EXX","HALT","IM0","IM1","IM2","IN","INC","IND","INDR",
"INI","INIR","JP","JR","LD","LDD","LDDR","LDI","LDIR","neg","NOP","OR","OTDR","OTIR",
"OUT","OUTD","OUTI","POP","PUSH","RES","ret","RETI","RETN","RL","RLA","RLC","RLCA",
"RLD","RR","RRA","RRA","RRC","RRCA","RRD","RST","SBC","SCF","SET","SLA","SLL","SRA",
"SRL","SUB","XOR",
"adc","add","and","bit","call","ccf","cp","cpd","cpdr","cpi","cpir","cpl","daa",
"dec","di","djnz","ei","ex","exx","halt","im0","im1","im2","in","inc","ind","indr",
"ini","inir","jp","jr","ld","ldd","lddr","ldi","ldir","neg","nop","or","otdr","otir",
"out","outd","outi","pop","push","res","ret","reti","retn","rl","rla","rlc","rlca",
"rld","rr","rra","rra","rrc","rrca","rrd","rst","sbc","scf","set","sla","sll","sra",
"srl","sub","xor",""
},
// brackets
{ "(",")","[","]","{","}","PUSH","POP","push","pop","" },
// operators
{ "+","-","*","/","%","&","|","^","!",":",",","" },
// remblck
{ "" },
// remline
{ "rem","REM" },
// preproc
{ "" },
// wordspc
{ "" },
};
//---------------------------------------------------------------------------
const _editor_syntax syntax_Z80_bas=
{
// keywords
{ "RND","INKEY$","PI","FN","POINT","SCREEN$","ATTR","AT","TAB","VAL$","CODE","VAL","LEN","SIN","COS","TAN","ASN","ACS",
"ATN","LN","EXP","INT","SOR","SGN","ABS","PEEK","IN","USR","STR$","CHR$","NOT","BIN","OR","AND","<=",">=","<>","LINE",
"THEN","TO","STEP","DEF","CAT","FORMAT","MOVE","ERASE","OPEN#","CLOSE#","MERGE","VERIFY","BEEP","CIRCLE","INK","PAPER",
"FLASH","BRIGHT","INVERSE","OVER","OUT","LPRINT","LLIST","STOP","READ","DATA","RESTORE","NEW","BORDER","CONTINUE","DIM",
"REM","FOR","GOTO","GOSUB","INPUT","LOAD","LIST","LET","PAUSE","NEXT","POKE","PRINT","PLOT","RUN","SAVE","RANDOMIZE",
"IF","CLS","DRAW","CLEAR","RETURN","COPY",
/*
"rnd","inkey$","pi","fn","point","screen$","attr","at","tab","val$","code","val","len","sin","cos","tan","asn","acs",
"atn","ln","exp","int","sor","sgn","abs","peek","in","usr","str$","chr$","not","bin","or","and","<=",">=","<>","line",
"then","to","step","def","cat","format","move","erase","open#","close#","merge","verify","beep","circle","ink","paper",
"flash","bright","inverse","over","out","lprint","llist","stop","read","data","restore","new","border","continue","dim",
"rem","for","goto","gosub","input","load","list","let","pause","next","poke","print","plot","run","save","randomize",
"if","cls","draw","clear","return","copy",
*/
"" },
// brackets
{ "(",")","[","]","" },
// operators
{ "+","-","*","/","%","&","|","^","!","<=",">=","<>","=",":",",",";","" },
// remblck
{ "" },
// remline
{ ";","" },
// preproc
{ "" },
// wordspc
{ "" },
};
//---------------------------------------------------------------------------
// all ZX ASCII codes from 165 to 255 are BASIC commands
const AnsiString zx_table[91]=
{
"RND ","INKEY$ ","PI ","FN ","POINT ","SCREEN$ ","ATTR ","AT ","TAB ","VAL$ ","CODE ","VAL ","LEN ","SIN ","COS ","TAN ","ASN ","ACS ",
"ATN ","LN ","EXP ","INT ","SOR ","SGN ","ABS ","PEEK ","IN ","USR ","STR$ ","CHR$ ","NOT ","BIN ","OR ","AND ","<=",">=","<>","LINE ",
"THEN ","TO ","STEP ","DEF ","CAT ","FORMAT ","MOVE ","ERASE ","OPEN# ","CLOSE# ","MERGE ","VERIFY ","BEEP ","CIRCLE ","INK ","PAPER ",
"FLASH ","BRIGHT ","INVERSE ","OVER ","OUT ","LPRINT ","LLIST ","STOP ","READ ","DATA ","RESTORE ","NEW ","BORDER ","CONTINUE ","DIM ",
"REM ","FOR ","GOTO ","GOSUB ","INPUT ","LOAD ","LIST ","LET ","PAUSE ","NEXT ","POKE ","PRINT ","PLOT ","RUN ","SAVE ","RANDOMIZE ",
"IF ","CLS ","DRAW ","CLEAR ","RETURN ","COPY "
};
//---------------------------------------------------------------------------
void Z80_load_asm(editor &dst,AnsiString file)
{
dst.load(file);
dst.set_font(&font_DG89,1,2);
dst.tab=8;
dst.syntax =(_editor_syntax*)&syntax_Z80_asm;
dst.syntax_asm=(_editor_syntax*)&syntax_Z80_asm;
dst.scann();
}
//---------------------------------------------------------------------------
void Z80_load_bas(editor &dst,AnsiString file)
{
dst.loadtext("");
int hnd,siz;
BYTE *dat;
hnd=FileOpen(file,fmOpenRead);
if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new char[siz];
if (dat==NULL) { FileClose(hnd); return; }
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
int i,l,a,_a,linenum;
AnsiString s;
DWORD a0,a1,a2,a3,a4;
for (hnd=0;hnd<siz;) // copy and count lines
{
if (hnd>=siz) break; // line number
a0=dat[hnd]; hnd++;
if (hnd>=siz) break;
a1=dat[hnd]; hnd++;
linenum=(a1+(a0<<8));
if (linenum<10000) dst.txt+=" ";
if (linenum< 1000) dst.txt+=" ";
if (linenum< 100) dst.txt+=" ";
if (linenum< 10) dst.txt+=" ";
dst.txt+=linenum;
dst.txt+=" ";
if (hnd>=siz) break; // line length
a0=dat[hnd]; hnd++;
if (hnd>=siz) break;
a1=dat[hnd]; hnd++;
l=(a0+(a1<<8));
for (s="",i=0;i<l;i++) // load line
{
if (hnd>=siz) break;
a=dat[hnd]; hnd++;
s+=char(a);
}
l=i;
if (linenum<=9999) // BASIC lines
for (a=0,i=1;i<=l;)
{
_a=a;
a=BYTE(s[i]); i++;
if (a>=165)
{
if ((dst.txt!="")&&(dst.txt[dst.txt.Length()]!=' ')) dst.txt+=" ";
dst.txt+=zx_table[a-165];
}
else if (a>=32) dst.txt+=char(a);
if (a==14) // number
{
if (i+5>l) break;
a0=BYTE(s[i]); i++;
a1=BYTE(s[i]); i++;
a2=BYTE(s[i]); i++;
a3=BYTE(s[i]); i++;
a4=BYTE(s[i]); i++;
if ((_a<'0')||(_a>'9'))
{
if (a0==0) // int
{
int x;
x=a2+(a3<<8);
if (a1) x=-x;
dst.txt+=x;
}
else{ // float
dst.txt+="/float/";
}
}
}
}
else{ // Data area
int x=0,n=8;
AnsiString t;
for (i=1;i<=l;)
{
a=BYTE(s[i]); i++;
if (x) dst.txt+=",";
else { if (i>2) dst.txt+=" "; dst.txt+=" db "; t=" // "; }
if (a<16) dst.txt+="0";
dst.txt+=AnsiString().sprintf("0%Xh",BYTE(a)); x++;
if ((a<32)||(a>164)) t+="."; else t+=char(BYTE(a));
if (x>=n) { dst.txt+=t+dst.endl; x=0; }
}
if (x)
{
for (;x<n;x++) dst.txt+=" ";
dst.txt+=t+dst.endl; x=0;
}
}
dst.txt+=dst.endl;
}
delete dat;
dst.set_font(&font_DG89,1,2);
dst.syntax =(_editor_syntax*)&syntax_Z80_bas;
dst.syntax_asm=(_editor_syntax*)&syntax_Z80_asm;
dst.scann();
}
//---------------------------------------------------------------------------
void Z80_load_txt(editor &dst,AnsiString file)
{
dst.loadtext("");
int hnd,siz;
BYTE *dat;
hnd=FileOpen(file,fmOpenRead);
if (hnd<0) return;
siz=FileSeek(hnd,0,2);
FileSeek(hnd,0,0);
dat=new char[siz];
if (dat==NULL) { FileClose(hnd); return; }
siz=FileRead(hnd,dat,siz);
FileClose(hnd);
int x=0;
BYTE a;
for (hnd=0;hnd<siz;) // copy and count lines
{
BYTE a=dat[hnd]; hnd++;
if (a==128) a='e';
else if (a==130) a='s';
else if (a==131) a='c';
else if (a==133) a='y';
else if (a==134) a='a';
else if (a==135) a='i';
else if (a==136) a='u';
else if (a==137) a='o';
else if (a==138) a='o';
else if (a==139) a='d';
else if (a==143) a='z';
// else if (a>127) a=a;
dst.txt+=char(a);
x++; if (x>=64) { dst.txt+=dst.endl; x=0; }
}
delete dat;
dst.set_font(&font_DG89,1,2);
dst.syntax =(_editor_syntax*)NULL;
dst.syntax_asm=(_editor_syntax*)NULL;
dst.scann();
}
//---------------------------------------------------------------------------
void Z80_load(editor &dst,AnsiString file)
{
AnsiString ext=ExtractFileExt(file).LowerCase();
dst.syntax =(_editor_syntax*)NULL;
dst.syntax_asm=(_editor_syntax*)NULL;
if (ext==".asm") Z80_load_asm(dst,file);
else if (ext==".p" ) Z80_load_bas(dst,file);
else Z80_load_txt(dst,file);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
xxd
the data? I'm having trouble reversing theod
.