/* REXX */

/*
-----------------------------------------------------------------
  unpacker (v0.1h) = 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 unmatched '*'+'/' in embedded data files.
-----------------------------------------------------------------
*/

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

allexclude='inv1.pas inv2.pas inv3.pas inv5.pas overlays.txt'

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

if host='UNIX' then exclude=allexclude ''
else exclude=allexclude ''

if translate(only)='/ALL' then do ; only='' ; exclude='' ; end

bar = '===' ; prefix='/*' bar ; postfix = reverse(prefix)
headpost=' begins' postfix ; footpost=' ends' postfix

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 (prefix) ' ' outfile (headpost) .
    if only='' then
      if wordpos(outfile,exclude)=0 then say outfile
      else say '...skipping...' outfile
    writeln=1
  end
  else if pos(footpost,line) \= 0 then writeln=0
  if pos(headpost,line)=0 & pos(footpost,line)=0 & writeln then do
    if (only='' & wordpos(outfile,exclude)=0) | only=outfile then ,
      call outline
  end
  else if pos(footpost,line) \= 0 & only=outfile then exit
return

outline:
  /* line=changeonce('{!TAB!}',line,'9'x) */
  call lineout outfile, line
return

changeonce: procedure
  parse arg before, str, after
  ofs=pos(before,str)
  if ofs \= 0 then do
    str=delstr(str,ofs,length(before))
    str=insert(after,str,ofs-1,length(after))
  end
return str

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

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

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

/* === lines.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$I-}

unit lines; {public domain, nenies proprajho, free for any use}

interface

type
  line = object
    linedata:string;
    p,p2:byte;
    function  getc(b:byte):char;
    procedure putc(b:byte;c:char);
    function  {length} len:byte;
    function  {copy}   cpy(ofs,num:integer):string;
    function  {pos}    find(s:string):byte;
    procedure {insert} ins(s:string;n:integer);
    procedure {delete} del(ofs,num:integer);
    function  found(s:string):boolean;
    function  foundstart(s:string):boolean;
    function  foundend(s:string):boolean;
    procedure delend(s:string);
    procedure finddel(s:string);
    procedure sub(no,yes:string);
  end;

implementation

  function line.getc(b:byte):char;
  begin getc := linedata[b]
  end;

  procedure line.putc(b:byte;c:char);
  begin linedata[b] := c
  end;

  function {length} line.len:byte;
  begin len := length(linedata)
  end;

  function {copy} line.cpy(ofs,num:integer):string;
  begin cpy := copy(linedata,ofs,num)
  end;

  function {pos} line.find(s:string):byte;
  begin find := pos(s,linedata)
  end;

  procedure {insert} line.ins(s:string;n:integer);
  begin insert(s,linedata,n)
  end;

  procedure {delete} line.del(ofs,num:integer);
  begin delete(linedata,ofs,num)
  end;

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

  function line.foundstart(s:string):boolean;
  begin foundstart := cpy(1,length(s)) = s end;

  function line.foundend(s:string):boolean;
  begin foundend := cpy(len-length(s)+1,length(s)) = s end;

  procedure line.delend(s:string);
  begin if foundend(s) then del(len-length(s)+1,length(s))
  end;

  procedure line.finddel(s:string);
  begin p := find(s); if p <> 0 then del(p,length(s))
  end;
  
  procedure line.sub(no,yes:string);
  begin p := find(no); if p<>0 then begin del(p,length(no)); ins(yes,p) end
  end;
  
end.
/* === lines.pas ends === */

/* === asmfiles.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$I+}

unit asmfiles; {public domain, nenies proprajho, free for any use}

interface

uses lines;

type
  asmfile = object (line)
    infile,outfile:text;
    function readline:boolean;
    procedure writeline;
    procedure writeout(s:string);
    constructor init(name:string);
    destructor done;
  end;

implementation

  function asmfile.readline:boolean;
  begin
    if eof(infile) then
      readline := false
    else begin
      readln(infile,linedata);
      readline := true
    end
  end;

  procedure asmfile.writeline;
  begin writeln(outfile,linedata)
  end;

  procedure asmfile.writeout(s:string);
  begin writeln(outfile,s)
  end;

  constructor asmfile.init(name:string);
  begin
    if paramcount > 1 then assign(infile,paramstr(2))
    else assign(infile,'INVADERS.ASM');
    assign(outfile,name);
    reset(infile); rewrite(outfile)
  end;

  destructor asmfile.done;
  begin close(outfile); close(infile)
  end;

end.
/* === asmfiles.pas ends === */

/* === asmfixes.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55} {$ifdef OVERLAY} {$O+,F+} {$endif} {$endif}

unit asmfixes; {public domain, nenies proprajho, free for any use}

interface

uses asmfiles;

type
  charset = set of char;

  asmfixer = object (asmfile)
    procedure fixproc;
    procedure incdec(wordset:charset;leftbrak:boolean);
    procedure fixop1(wordset:charset;leftbrak:boolean);
    procedure fixop2(wordset:charset;leftbrak:boolean);
    procedure fixbrakdig;
    function  brakdig:boolean;
    procedure insertseg;
  end;

const
  alphanum:charset = ['a'..'z','A'..'Z','0'..'9'];

implementation

  procedure asmfixer.fixproc;
  begin if found(' PROC ') then ins(':;',find(' '))
  end;

  procedure asmfixer.incdec(wordset:charset;leftbrak:boolean);
  begin p := find('INC '); if p=0 then p := find('DEC ');
    if p <> 0 then begin inc(p,length('??C '));
      while getc(p)=' ' do inc(p);
      if getc(p) <> '[' then begin p2 := p;
        repeat inc(p2) until (p2=len) or (getc(p2)=' ') or
          (not (getc(p2) in wordset));

        if (getc(p2)=' ') or (getc(p2)='[') then dec(p2);

        if ((p2-p+1) > length('DX')) then begin
          ins(']',p2+1);
          if leftbrak then
            ins('[',p)
          else
            ins('s_' + cpy(p,p2-p+1) + '[',p)
        end
      end
    end
  end;

  procedure asmfixer.fixop1(wordset:charset;leftbrak:boolean);
  begin p2 := find(',');
    if (p2 <> 0) and (getc(p2-1) <> ']') then begin dec(p2); p := p2;

      repeat dec(p) until (getc(p)=' ') or
        (not (getc(p) in wordset));
      inc(p);

      if ((p2-p+1) > length('DX')) and (getc(p) <> '[') and
        (getc(p) in ['A'..'Z']) then begin
          ins(']',find(','));
          if leftbrak then
            ins('[',p)
          else
            ins('s_' + cpy(p,p2-p+1) + '[',p)
      end
    end
  end;

  procedure asmfixer.fixop2(wordset:charset;leftbrak:boolean);
  begin p := find(','); p2 := find(';');
    if (p <> 0) and ((p2=0) or (p2 > p)) and (getc(p) <> '[') then begin
      inc(p); p2 := p;

      while (p2 < len) and (getc(p2) <> ' ') and
        (getc(p2) in wordset) do
          inc(p2);
      if (getc(p2)=' ') or (getc(p2)='[') then dec(p2);

      if (p2 > p) and (p2-p+1 > length('DX')) and (getc(p) in ['A'..'Z'])
        then begin
          ins(']',p2+1);
          if leftbrak then
            ins('[',p)
          else
            ins('s_' + cpy(p,p2-p+1) + '[',p)
      end
    end
  end;

  procedure asmfixer.fixbrakdig;
  begin p := find('],');
    if (p >= 4) and (getc(p-2)='[') and (getc(p-1) in ['0'..'9']) then begin
      putc(p-2,'_'); del(p,1)
    end
  end;

  function asmfixer.brakdig:boolean;
  begin
    brakdig := (p <> 0) and (getc(p-2)='_') and (getc(p-1) in ['0'..'9'])
  end;

  procedure asmfixer.insertseg;
  const segoverride:boolean=false;
  begin
    if found('RemoveNewInt9:') then segoverride := true;
    if segoverride and not found('[0') then sub('[','[cs:');
    if found('CLC') then segoverride := false;
  end;

end.
/* === asmfixes.pas ends === */

/* === a86jumps.inc begins === */
  procedure jmpshort;
  var j:byte;
  const jumpnum:byte=0; jumpmsg='JMP ';
{$ifdef NOSETS} noshort='#$%&,./123456789=>DGJMOPQRSTUVWXYZ[\]^_`abcdefy';
{$else} noshort=[3..6,17..25,47..70,12,14,15,29,30,36,39,42,45,89]; {$endif}
  begin j := find(jumpmsg);
    if j <> 0 then begin
      inc(jumpnum);
{$ifdef NOSETS} if pos(chr(jumpnum+ord(' ')),noshort) = 0
{$else} if not (jumpnum in noshort)
{$endif} then ins('SHORT ',j + length(jumpmsg))
    end
  end;
/* === a86jumps.inc ends === */

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

unit inva86; {public domain, nenies proprajho, free for any use}

interface

uses asmfiles;

type
  a86obj = object (asmfile)
    incfile:text;
    procedure adjust;
    constructor init;
    destructor done;
  end;

implementation

procedure a86obj.adjust;

  procedure seginsert;
  const override:boolean=false;
  begin
    if found('RemoveNewInt9') and found(' PROC') then override := true;
    if override then begin
      if found(',Word') or found('StoreAX') or foundend(',0')
        or foundend(',1') then
          writeout('cs:');
      finddel('40:')
    end;
    if found('CLC') then override := false
  end;

{$ifndef NOJMPSHORT} {$I a86jumps.inc} {$endif}

begin 
  if getc(1) <> ';' then begin
    delend('[0]');
    if (getc(1) <> ' ') and (found(' DB ') or found(' DW ')) then begin
      p := find(' '); p2 := p; while getc(p2)=' ' do inc(p2);
      writeln(incfile,'EXTRN ',cpy(1,p-1),':',getc(p2+1))
    end;
    {$ifndef NOJMPSHORT} jmpshort; {$endif}
    seginsert
  end;

  writeline
end;

constructor a86obj.init;
const incname='inv.inc';
  procedure main;
  begin
    writeout('include ' + incname);
    while readline do adjust
  end;
begin asmfile.init('inv.a86');
  assign(incfile,incname); rewrite(incfile); main
end;

destructor a86obj.done;
begin asmfile.done; close(incfile)
end;

end.
/* === inva86.pas ends === */

/* === invjwasm.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$I+}

unit invjwasm; {public domain, nenies proprajho, free for any use}

interface

uses asmfiles;

type
  jwasmobj = object (asmfile)
    procedure adjust;
    constructor init;
    destructor done;
  end;

implementation

procedure jwasmobj.adjust;
begin 
  if getc(1) <> ';' then begin
    sub('40:','DS:');
    if found('LEA ') then begin
      sub(',',',OFFSET ');
      sub('LEA ','MOV ')
    end;
    if foundstart('Exit:') or foundstart('StartGame:') or
      foundstart('RedrawBunkers:') then
        sub(':','::') {needed in default v6 mode, so "-Zm" doesn't need it}
  end;

  writeline
end;

constructor jwasmobj.init;
begin asmfile.init('inv-jwas.asm'); while readline do adjust
end;

destructor jwasmobj.done;
begin asmfile.done
end;

end.
/* === invjwasm.pas ends === */

/* === invwasm.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55} {$ifdef OVERLAY} {$O+,F+} {$endif} {$endif}
{$I+}

unit invwasm; {public domain, nenies proprajho, free for any use}

interface

uses asmfixes;

type
  wasmobj = object (asmfixer)
    incfile:text;
    procedure adjust;
    constructor init;
    destructor done;
  end;

implementation

procedure wasmobj.adjust;
begin
  if (getc(1)=';') or found(':C') or found('S:[') or found('Ptr') then begin
    writeline; exit
  end;

  if found('LEA ') then begin
    sub('LEA ','MOV '); ins('OFFSET ',find(',')+1)
  end;
  sub('40:','DS:');

  if found(',Of') or found(',OF') or found('DS:') then begin
    writeline; exit
  end;

  sub(' DD ',' DW 0,');
  if (found(' DB ') or found(' DW ')) and (getc(1) <> ' ') then begin
    p := find(' '); p2 := p; while getc(p2)=' ' do inc(p2);
    writeln(incfile,'s_',cpy(1,p-1),' equ ',getc(p2+1));
    writeline; exit
  end;

  p := find(',');
  if (p <> 0) and (getc(p-1)=']') and (getc(p-3)='[') and
    (getc(p-2) in ['0'..'9']) then
      ins(',',p-3);

  if found('+BX') then begin finddel('['); finddel(']') end;
  fixop1(alphanum+['+'],false);
  fixop2(alphanum+['+'],false);
  incdec(alphanum+['+'],false);
  sub('+BX[','['); sub(',[','[');

  writeline
end;

constructor wasmobj.init;
const incname='inv-wat.inc';
  procedure main;
  begin
    writeout('B equ byte ptr'); writeout('W equ word ptr');
    writeout('include ' + incname);
    while readline do adjust
  end;
begin asmfixer.init('inv-wat.asm');
  assign(incfile,incname); rewrite(incfile); main
end;

destructor wasmobj.done;
begin asmfixer.done; close(incfile)
end;

end.
/* === invwasm.pas ends === */

/* === invfasm.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55} {$ifdef OVERLAY} {$O+,F+} {$endif} {$endif}

unit invfasm; {public domain, nenies proprajho, free for any use}

interface

uses asmfixes;

type
  fasmobj = object (asmfixer)
    procedure adjust;
    constructor init;
    destructor done;
  end;

implementation

procedure fasmobj.adjust;
begin
  if (getc(1)=';') or found(' DB ') or found(' DW ') or found('LEA ') then
    begin writeline; exit end;

  if found('CODE_SEG') or found('END') then exit;

  finddel('[0]');

  if not found(',O') then begin
    sub(' DD ',' DW 0,'); sub('ES:[','[ES:');
    finddel('40:'); finddel('Word Ptr ');
    fixproc; fixbrakdig;
    fixop1(alphanum+['_'],true); fixop2(alphanum+['_'],true);
    p := find(']'); if brakdig then putc(p-2,'+');
    incdec(alphanum,true);
    sub('][','+');
    insertseg
  end;

  writeline
end;

constructor fasmobj.init;
  procedure main;
  begin
    writeout('OFFSET equ'); writeout('Offset equ'); writeout('LEA equ MOV');
    while readline do adjust
  end;
begin asmfixer.init('inv-fasm.asm'); main
end;

destructor fasmobj.done;
begin asmfixer.done
end;

end.
/* === invfasm.pas ends === */

/* === invnasm.pas begins === */
{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55} {$ifdef OVERLAY} {$O+,F+} {$endif} {$endif}
{$I+}

unit invnasm; {public domain, nenies proprajho, free for any use}

interface

uses asmfixes;

type
  nasmobj = object (asmfixer)
    incfile:text;
    procedure adjust;
    constructor init;
    destructor done;
  end;

implementation

procedure nasmobj.adjust;
begin
  if (getc(1)=';') or found('LEA ') then begin writeline; exit end;

  sub(' DD ',' DW 0,');
  if (found(' DB ') or found(' DW ')) and (getc(1) <> ' ') then begin
    p := find(' '); p2 := p; while getc(p2)=' ' do inc(p2);
    writeln(incfile,'%define s_',cpy(1,p-1),' ',getc(p2+1));
    writeline; exit
  end;

  if found('CODE_SEG') or found('END') then exit;

  finddel('[0]');

  if not found(',O') {,O[fF][fF][sS][eE][tT]} then begin
    sub('ES:[','[ES:'); finddel('40:'); finddel('Word Ptr ');
    fixproc; fixbrakdig;
    if found('+BX') then begin finddel('['); finddel(']') end;
    fixop1(alphanum+['_','+'],false);
    fixop2(alphanum+['_','+'],false);
    p := find('['); if brakdig then del(p-2,2);
    p := find(']'); if brakdig then putc(p-2,'+');
    incdec(alphanum+['+'],false);
    sub('+BX[','['); sub('[]','+'); sub('][','+');
    insertseg
  end;

  writeline
end;

constructor nasmobj.init;
const incname='inv-nasm.inc';
  procedure main;
  begin
    writeout('%idefine offset'); writeout('%define LEA MOV');
    writeout('%define B byte'); writeout('%define W word');
    writeout('%include "' + incname + '"');
    while readline do adjust
  end;
begin asmfixer.init('inv-nasm.asm');
  assign(incfile,incname); rewrite(incfile); main
end;

destructor nasmobj.done;
begin asmfixer.done; close(incfile)
end;

end.
/* === invnasm.pas ends === */

/* === inv.pas begins === */
{new/dispose on object ptrs saves 4 kb of memory; overlay saves 3 kb}

{$ifdef FPC}{$mode tp}{$endif}
{$ifdef DEBUG}{$R+,S+}{$else}{$R-,S-}{$endif}
{$ifdef VER55}{$M 4096,0,655360}{$ifdef OVERLAY}{$O+,F+}{$endif}{$endif}

program inv; {public domain, nenies proprajho, free for any use}
uses
  {$ifdef VER55}{$ifdef OVERLAY}overlay,{$endif}{$endif}
  invnasm,invfasm,invwasm,inva86,invjwasm;
var nasm:^nasmobj; fasm:^fasmobj; wasm:^wasmobj;
    a86:^a86obj; jwasm:^jwasmobj;

{$ifdef VER55} {$ifdef OVERLAY}
{$O asmfixes} {$O invfasm} {$O invnasm} {$O invwasm}
{$endif} {$endif}

procedure mem;
{$ifdef VER55} begin writeln('memavail = ',memavail)
{$else} var nop:byte; begin nop := $90
{$endif}
end;

procedure run;
begin
  if      paramstr(1) = 'jwasm' then begin
    new(jwasm,init); mem; dispose(jwasm,done); exit
    end
  else if paramstr(1) = 'a86'   then begin
    new(a86,init); mem; dispose(a86,done); exit
  end;

{$ifdef VER55} {$ifdef OVERLAY}
  ovrinit('INV.OVR');
  if ovrresult <> ovrok then begin writeln('.OVR not found!'); halt(1) end;
{$endif} {$endif}

  if      paramstr(1) = 'nasm' then begin
    new(nasm,init); mem; dispose(nasm,done)
    end
  else if paramstr(1) = 'fasm' then begin
    new(fasm,init); mem; dispose(fasm,done)
    end
  else if paramstr(1) = 'wasm' then begin
    new(wasm,init); mem; dispose(wasm,done)
  end
end; {run}

begin {main}
  if paramcount=0 then begin
    writeln('Usage: INV [nasm | fasm | wasm | a86 | jwasm]');
    halt(255) {change to "else" if you don't care about errorlevel}
  end;
  mem; run; mem
end.
/* === inv.pas ends === */

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

program inv1; {public domain, nenies proprajho, free for any use}
{$ifdef FASM}
  uses invfasm;
  var one:fasmobj;
{$else}
  {$ifdef NASM}
    uses invnasm;
    var one:nasmobj;
  {$else}
    {$ifdef WASM}
      uses invwasm;
      var one:wasmobj;
    {$else}
      {$ifdef A86}
        uses inva86;
        var one:a86obj;
      {$else}
        uses invjwasm;
        var one:jwasmobj;
      {$endif}
    {$endif}
  {$endif}
{$endif}

begin {main}
  one.init; one.done
end.
/* === inv1.pas ends === */

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

program inv2; {public domain, nenies proprajho, free for any use}
{$ifdef NASMFASM}
  uses invnasm,invfasm;
  const onestr='nasm'; twostr='fasm';
  var one:nasmobj; two:fasmobj;
{$else}
  uses inva86,invjwasm;
  const onestr='a86'; twostr='jwasm';
  var one:a86obj; two:jwasmobj;
{$endif}

begin {main}
  if paramcount=0 then begin
    writeln('Usage: INV [',onestr,' | ',twostr,']'); halt(255)
  end;

  if      paramstr(1) = onestr then begin one.init; one.done end
  else if paramstr(1) = twostr then begin two.init; two.done end
end.
/* === inv2.pas ends === */

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

program inv3; {public domain, nenies proprajho, free for any use}
uses invnasm,invfasm,invwasm;
var nasm:nasmobj; fasm:fasmobj; wasm:wasmobj;

begin {main}
  if paramcount=0 then begin
    writeln('Usage: INV [nasm | fasm | wasm]'); halt(255)
  end;

  if paramstr(1)      = 'nasm' then begin nasm.init; nasm.done end
  else if paramstr(1) = 'fasm' then begin fasm.init; fasm.done end
  else if paramstr(1) = 'wasm' then begin wasm.init; wasm.done end
end.
/* === inv3.pas ends === */

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

program inv5; {public domain, nenies proprajho, free for any use}
uses
  invnasm,invfasm,invwasm,inva86,invjwasm;
var
  nasm:nasmobj; fasm:fasmobj; wasm:wasmobj; a86:a86obj; jwasm:jwasmobj;

begin {main}
  if paramcount=0 then begin
    writeln('Usage: INV [nasm | fasm | wasm | a86 | jwasm]'); halt(255)
  end;

  if      paramstr(1) = 'jwasm' then begin jwasm.init; jwasm.done end
  else if paramstr(1) = 'a86'   then begin a86.init;   a86.done   end
  else if paramstr(1) = 'nasm'  then begin nasm.init;  nasm.done  end
  else if paramstr(1) = 'fasm'  then begin fasm.init;  fasm.done  end
  else if paramstr(1) = 'wasm'  then begin wasm.init;  wasm.done  end
end.
/* === inv5.pas ends === */

/* === overlays.txt begins === */
                                INVOOP

My OOP version (ad-hoc text converter) is:

   9       .PAS files total
        8  TP units (modules)
        1  main .PAS file to import them all

  15       kilobytes of total sources
      611  lines (including blanks and comments)

   5       assemblers supported (converted text output)

----------------------------------------------------------------------
INV.PAS         (main)

LINES,ASMFILES  (units used by all)

ASMFIXES        (unit only used for FASM,NASM,WASM)

INVA86,INVJWASM,INVFASM,INVNASM,INVWASM
                (individual units, one for each assembler supported)
----------------------------------------------------------------------

Overlays have negligible benefit here, especially since it's
compiler-specific (Turbo Pascal 5.5 is proprietary, albeit freeware).

The normal way is more portable, so I only need to change the main
.PAS manually and adjust how many objects I want to import and use.

All five assemblers:
  INV.EXE = 14,128 bytes (14   kb) -- all (NASM,FASM,WASM,A86,JWASM)
  (UPX'd) =  5,580 bytes ( 5.5 kb)

NASM, FASM, and WASM (similar, all use AsmFixes):
  INV.EXE = 12,208 bytes (12   kb) -- NASM, FASM, WASM
  (UPX'd) =  5,120 bytes ( 5   kb)

Both NASM and FASM:
  INV.EXE = 10,528 bytes (10.5 kb) -- NASM, FASM
  (UPX'd) =  4,828 bytes ( 5   kb)

Only NASM:
  INV.EXE =  9,168 bytes ( 9   kb) -- NASM only
  (UPX'd) =  4,454 bytes ( 4.5 kb)

Only WASM:
  INV.EXE =  8,400 bytes ( 8.5 kb) -- WASM only
  (UPX'd) =  4,202 bytes ( 4.5 kb)

Only FASM:
  INV.EXE =  8,352 bytes ( 8.5 kb) -- FASM only
  (UPX'd) =  4,207 bytes ( 4.5 kb)

Both A86 and JWasm (simplest, don't use AsmFixes):
  INV.EXE =  6,640 bytes ( 6.5 kb) -- A86, JWasm
  (UPX'd) =  3,942 bytes ( 4   kb)

Only A86:
  INV.EXE =  5,488 bytes ( 5.5 kb) -- A86 only
  (UPX'd) =  3,512 bytes ( 3.5 kb)

Only JWasm:
  INV.EXE =  4,752 bytes ( 4.5 kb) -- JWasm only
  (UPX'd) =  3,291 bytes ( 3.5 kb)

So we range from 14 kb to 9 kb to 5 kb, uncompressed: obvious savings
(for different functionality). Compression helps but also doesn't show
the full savings. (2 kb savings is less impressive than 10 kb.)

It could be argued that, for this program, such size savings are
useless overall, which is true! But, at least you get a choice on
what objects to support (for true reusability and minimalism, using
only what's needed). Of course, output size from other TP-compatible
compilers will vary.

Can it be smaller? With overlays, yes. Technically, it will still
partially work even if the .OVR isn't found. For instance, A86 and
JWasm (objects) don't need the AsmFixes unit, which is the largest
unit.

So, while it saves little RAM (not even 2 kb??) here when using
overlays, it does at least allow some slightly better modularity.
(625,664 vs. 604,400 free means I'm only using about 21 kb RAM total
anyways.) Barely.

Although UPX doesn't compress the overlay, you can even copy the
overlay to the main .EXE, but I see no benefit for that here.
(If it was mandatory for all usage, okay. Otherwise? Nah.)

Long story short, far calls are mandatory. But we only need to put
some, not all, of our units into an overlay. The worst offenders are
everything except Lines, AsmFiles, and the simplest objects (InvA86,
InvJWasm). Neither of those two needs AsmFixes.

Using overlays:
  INV.EXE =  9,616 bytes ( 9.5 kb)
  (UPX'd) =  5,888 bytes ( 6   kb)

  INV.OVR =  6,365 bytes
  (total) = 12,253 bytes (12   kb)

But, as mentioned, you don't direly need INV.OVR if you're only trying
to use A86 or JWasm. So you can safely delete it. Not quite a .DLL,
but it's still maybe easier to replace that one part rather than
rebuild the whole thing from scratch and redistribute entirely.

P.S. Units built for overlays will still be linkable for non-overlaid
     programs (but forcibly using far calls?? slightly slower??).
     So those *.TPU don't technically have to be recompiled, but ....

Summary:  Should overlays be used?

Pros:
  + saves memory (but only 2 kb here)
  + uncompressed (9.5 kb, partial support only) is smaller
    than full (14 kb)
  + smaller and easier to replace .OVR rather than the whole thing

Cons:
  - two separate files are harder to keep track of
  - can't compress .OVR with UPX
  - UPX'd full version is smaller than UPX'd partial
    (negligible benefit)

Still, overlays would be good for other uses. But here? Not so much.

<EOF>
/* === overlays.txt ends === */


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

/[b]egins ===/{
  fname=$3

  if (fname !~ /^inv[1235].pas$|^overlays.txt$/) {
    print fname
    while (getline > 0) {
      if ($0 !~ / [e]nds ===/) {
  #     sub("{!TAB!}","\t")
        print > fname
      }
      else {
        close(fname)
        break
      }
    }
  } else print "...skipping... " fname
}
# --- extract.awk ends ---

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

/* EOF */
