/* REXX */

/*
-----------------------------------------------------------------
  unpacker (v0.1) = public domain : free for any use

  AUTHOR: rugxulo _AT_ gmail

  TESTED: Regina 3.7, BRexx 2.1.9, r4 4.00, ooREXX 4.1.3

  BUG:    Can't use literal '*'+'/' pair in embedded data files.
-----------------------------------------------------------------
*/

/* --- UNPACKER BEGINS --- */

if arg() \= 0 then parse arg onlyfile . ; else onlyfile=''
parse source . . srcfile . ; lineno=0 ; writeln=0

bar = '===' ; prefix='/*' bar ; postfix = bar '*/'
headpost=' begins' postfix ; footpost=' ends' postfix
headlen=length(headpost) ; footlen=length(footpost)

if lines(srcfile)=1 then do while lines(srcfile) \= 0
  call grab
end
else do lines(srcfile)
  call grab
end

exit

grab:
  line=linein(srcfile) ; lineno=lineno+1
  if pos(headpost,line) \= 0 then do
    parse var line ' ' (bar) ' ' outfile (headpost) .
    if onlyfile='' then say outfile
    writeln=1
  end
  else if pos(footpost,line) \= 0 then writeln=0
  if pos(headpost,line)=0 & pos(footpost,line)=0 & writeln then ,
    if onlyfile='' | onlyfile=outfile then ,
      call lineout outfile, line
return

/* --- UNPACKER ENDS --- */

/*
------------------------------------------------------------
*** DATA BEGINS DATA BEGINS DATA BEGINS DATA BEGINS ***

/* these data files = public domain : free for any use */
------------------------------------------------------------

/* === inva86.bas begins === */
' $lang: "fblite" (smaller .EXE than "qb")

DEFINT A-Z : CONST incname="inv.inc"
DIM SHARED me AS STRING,src,inc,a86

DECLARE SUB WriteInc()
DECLARE SUB WriteA86()
DECLARE FUNCTION WriteJump%()
DECLARE FUNCTION WriteSeg%()

src=FREEFILE
IF ENVIRON$("INVADERS") <> "" THEN _
  OPEN ENVIRON$("INVADERS") FOR INPUT AS #src _
ELSE _
  OPEN "INVADERS.ASM" FOR INPUT AS #src

inc=FREEFILE : OPEN incname FOR OUTPUT AS #inc
a86=FREEFILE : OPEN "inv.a86" FOR OUTPUT AS #a86
DO UNTIL EOF(src)
  LINE INPUT #src,me
  WriteInc
  WriteA86
LOOP
CLOSE #a86,#inc,#src
SYSTEM ' goodbye!

SUB WriteInc
  IF LEFT$(me,1) = " " THEN EXIT SUB

  dz = 0 : db = INSTR(me," DB ")

  IF db <> 0 THEN
    dz = db : d$ = ":B"
  ELSE
    dw = INSTR(me," DW ")
    IF dw <> 0 THEN
      dz = dw : d$ = ":W"
    END IF
  END IF

  IF dz <> 0 THEN ? #inc,"EXTRN " ; RTRIM$(LEFT$(me,dz-1)) ; d$
END SUB

SUB WriteA86
  IF INSTR(me,"BEGIN:") THEN
    ? #a86,"include " ; incname : ? #a86,me
    EXIT SUB
  END IF

  IF RIGHT$(me,3) = "[0]" THEN
    ? #a86,LEFT$(me,LEN(me)-3)
    EXIT SUB
  END IF

  IF (NOT WriteJump) AND (NOT WriteSeg) THEN ? #a86,me
END SUB

FUNCTION WriteJump%
  WriteJump = FALSE

  IF LEFT$(me,1) = ";" THEN EXIT FUNCTION

  CONST noshort="#$%&,./123456789=>DGJMOPQRSTUVWXYZ[\]^_`abcdefy"
  STATIC jumpnum AS INTEGER

  j = INSTR(me,"JMP ")
  IF j <> 0 THEN
    jumpnum = jumpnum + 1
    IF INSTR(noshort,CHR$(jumpnum+ASC(" "))) THEN EXIT FUNCTION

    ? #a86,LEFT$(me,j-1) ; "JMP SHORT" ; MID$(me,j+3)
    WriteJump = NOT FALSE
  END IF
END FUNCTION

FUNCTION WriteSeg%
  WriteSeg = FALSE

  STATIC insertseg AS INTEGER

  IF INSTR(me,"RemoveNewInt9 ") THEN IF INSTR(me," PROC ") THEN _
    insertseg = NOT FALSE

  IF insertseg THEN
    IF INSTR(me,",Word") OR INSTR(me,"StoreAX") OR _
      RIGHT$(me,2) = ",0" OR RIGHT$(me,2) = ",1" THEN
        ? #a86,"cs:" ; me
        WriteSeg = NOT FALSE
    END IF
    IF INSTR(me,"40:") THEN MID$(me,INSTR(me,"40:"))="ds:"
  END IF

  IF INSTR(me,"CLC") THEN insertseg = FALSE
END FUNCTION

' <EOF>
/* === inva86.bas ends === */

/* === inva86.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55}{$M 4096,0,0}{$endif}

program inva86;
var line:string[135]; asmfile,incfile,a86file:text;
const ASMNAME='INVADERS.ASM'; INCNAME='inv.inc'; A86NAME='inv.a86';

function found(s:string):boolean; begin found := pos(s,line) <> 0 end;

function WriteJump: boolean;
const jumpnum:byte=0; jumpmsg='JMP ';
  noshort=[3..6,17..25,47..70,12,14,15,29,30,36,39,42,45,89];
var j:byte;
begin WriteJump := false;
  j := pos(jumpmsg,line);
  if (j <> 0) and (line[1] <> ';') then begin
    inc(jumpnum);
    if (jumpnum in noshort) then exit;
    insert('SHORT ',line,j + length(jumpmsg));
    writeln(a86file,line);
    WriteJump := true
  end
end; {WriteJump}

function WriteSeg: boolean;
var len,p:byte;
const insertseg:boolean=false; seg40='40:';
begin WriteSeg := false; len := length(line);
  if found('RemoveNewInt9 ') and found(' PROC ') then insertseg := true;
  if insertseg then begin
    if found(',Word') or found('StoreAX') or (copy(line,len-1,2)=',0') or
      (copy(line,len-1,2)=',1') then begin
        writeln(a86file,'cs:',line);
        WriteSeg := true
    end;
    p := pos(seg40,line);
    if p <> 0 then delete(line,p,length(seg40))
  end;
  if found('CLC') then insertseg := false
end; {WriteSeg}

procedure WriteInc;
var k:char; writeme:boolean;
begin writeme := false;
  if line[1] <> ' ' then
    if found(' DB ') then begin k := 'B'; writeme := true end
    else if found(' DW ') then begin k := 'W'; writeme := true end;
  if writeme then
    writeln(incfile,'EXTRN ',copy(line,1,(pos(' ',line)-1)),':',k)
end; {WriteInc}

procedure WriteA86;
var n:byte;
const bracketmsg='[0]';
begin
  if found('BEGIN:') then begin
    writeln(a86file,line,' include ',INCNAME);
    exit
  end;
  n := pos(bracketmsg,line);
  if n=length(line)-2 then begin
    delete(line,n,length(bracketmsg));
    writeln(a86file,line)
  end
  else if (not WriteJump) and (not WriteSeg) then writeln(a86file,line)
end; {WriteA86}

begin {main}
  if paramcount <> 0 then
    assign(asmfile,paramstr(1))
  else
    assign(asmfile,ASMNAME);
  reset(asmfile);

  assign(incfile,INCNAME); rewrite(incfile);
  assign(a86file,A86NAME); rewrite(a86file);
  while not eof(asmfile) do begin
    readln(asmfile,line);
    WriteInc; WriteA86
  end;
  close(a86file); close(incfile); close(asmfile)
end.
/* === inva86.pas ends === */

/* === inva86.c begins === */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INVINC "inv.inc"

typedef FILE* FilePtr;
typedef char* CharPtr;

char line[135]; FilePtr asmfile,incfile,a86file;

int WriteJump(void) {
int rc=0,n; CharPtr j; static unsigned short jumpnum=0;
  static char noshort[]="#$%&,./123456789=>DGJMOPQRSTUVWXYZ[\\]^_`abcdefy";

  if (((j=strstr(line,"JMP ")) != NULL) && (line[0] != ';')) {
    if (strchr(noshort,++jumpnum+' ') != NULL) return rc;

    n=(int)(j-line);
    fprintf(a86file,"%*.*sJMP SHORT  %s",n,n,line,(char*)(j+4));
    rc = !0;
  }

  return rc;
}

int WriteSeg(void) {
int rc=0; CharPtr f,s;

  if ((s=strstr(line,",Word")) != NULL) {
    fprintf(a86file,"cs:%s",line);
    rc = !0;
  }

  if ((strstr(line,"NewInt9Handler ")!=NULL)&&(strstr(line,"PROC ")!=NULL)){
    do {
      if ((s=strstr(line,"MOV ")) == NULL) fputs(line,a86file);
      else fprintf(a86file,"cs:%s",line);

      fgets(line,sizeof(line),asmfile);
    } while (strstr(line,"NotIntercept:") == NULL);
    fputs(line,a86file);
    rc = !0;
  }

  if (strstr(line,"NotIntercept:") != NULL) {
    fgets(line,sizeof(line),asmfile);

    do {
      if ((f=strstr(line,"40:")) != NULL) strncpy(f,"DS",2);

      if ((s=strstr(line,"StoreAX")) == NULL) fputs(line,a86file);
      else fprintf(a86file,"cs:%s",line);

      fgets(line,sizeof(line),asmfile);
    } while (strstr(line,"CLC") == NULL);

    fputs(line,a86file);
    rc = !0;
  }

  return rc;
}

void WriteInc(void) {
CharPtr db,dw,dz=0; char k; int n;

  if (line[0] == ' ') return;

  if ((db=strstr(line," DB ")) != 0) {
    dz=db; k='B';
  }
  else {
    if ((dw=strstr(line," DW ")) != 0) {
      dz=dw; k='W';
    }
  }

  if (dz != 0) {
    n=(int)(strchr(line,' ')-line);
    fprintf(incfile,"EXTRN %*.*s:%c\n",n,n,line,k);
  }
}

void WriteA86(void) {
CharPtr s; int n;

  if (strstr(line,"BEGIN:") != NULL) fputs("include " INVINC "\n",a86file);

  if ((s=strstr(line,"[0]")) != NULL) {

    if (line[strlen(line)-2] == '\r') {
      line[strlen(line)-2]='\n'; line[strlen(line)-1]='\0';
    }

    n=(int)(s-line);
    if (n == (int)strlen(line)-4) {
      fprintf(a86file,"%*.*s\n",n,n,line);
      return;
    }
  }

  if ((!WriteJump()) && (!WriteSeg())) fputs(line,a86file);
}

int main(int argc,char** argv) {

  if (argc > 1)
    asmfile=fopen(argv[1],"r");
  else
    asmfile=fopen("INVADERS.ASM","r");

  if (asmfile == NULL) {
    fputs("\nFile not found!\n",stderr);
    return EXIT_FAILURE;
  }

  incfile=fopen(INVINC,"w");
  a86file=fopen("inv.a86","w");

  do {
    fgets(line,sizeof(line),asmfile);
    if (feof(asmfile)) break;
    WriteInc(); WriteA86();
  } while (!feof(asmfile));

  fclose(a86file); fclose(incfile); fclose(asmfile);

  return EXIT_SUCCESS;
}

/* EOF */
/* === inva86.c ends === */


# --- extract.awk begins ---
#!/usr/bin/awk -f

/[b]egins ===/{
  fname=$3 ; print fname
  while (getline > 0) {
    if ($0 !~ / [e]nds ===/) {
      print > fname
    }
    else {
      close(fname)
      break
    }
  }
}
# --- extract.awk ends ---

------------------------------------------------------------
*** DATA ENDS DATA ENDS DATA ENDS DATA ENDS ***
------------------------------------------------------------
*/

/* EOF */
