fpc/compiler/owar.pas
2000-01-07 01:14:18 +00:00

303 lines
7.3 KiB
ObjectPascal

{
$Id$
Copyright (c) 1998-2000 by Peter Vreman
Contains the stuff for writing .a files directly
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., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************
}
unit owar;
interface
uses
cobjects,owbase;
type
tarhdr=packed record
name : array[0..15] of char;
date : array[0..11] of char;
uid : array[0..5] of char;
gid : array[0..5] of char;
mode : array[0..7] of char;
size : array[0..9] of char;
fmag : array[0..1] of char;
end;
parobjectwriter=^tarobjectwriter;
tarobjectwriter=object(tobjectwriter)
constructor Init(const Aarfn:string);
destructor Done;virtual;
procedure create(const fn:string);virtual;
procedure close;virtual;
procedure writesym(sym:string);virtual;
procedure write(var b;len:longint);virtual;
private
arfn : string;
arhdr : tarhdr;
symreloc,
symstr,
lfnstr,
ardata,
objdata : PDynamicArray;
objfixup : longint;
objfn : string;
timestamp : string[12];
procedure createarhdr(fn:string;size:longint;const gid,uid,mode:string);
procedure writear;
end;
implementation
uses
verbose,
{$ifdef Delphi}
dmisc;
{$else Delphi}
dos;
{$endif Delphi}
const
{$ifdef TP}
symrelocbufsize = 32;
symstrbufsize = 256;
lfnstrbufsize = 256;
arbufsize = 256;
objbufsize = 256;
{$else}
symrelocbufsize = 1024;
symstrbufsize = 8192;
lfnstrbufsize = 4096;
arbufsize = 65536;
objbufsize = 16384;
{$endif}
{*****************************************************************************
Helpers
*****************************************************************************}
const
C1970=2440588;
D0=1461;
D1=146097;
D2=1721119;
Function Gregorian2Julian(DT:DateTime):LongInt;
Var
Century,XYear,Month : LongInt;
Begin
Month:=DT.Month;
If Month<=2 Then
Begin
Dec(DT.Year);
Inc(Month,12);
End;
Dec(Month,3);
Century:=(longint(DT.Year Div 100)*D1) shr 2;
XYear:=(longint(DT.Year Mod 100)*D0) shr 2;
Gregorian2Julian:=((((Month*153)+2) div 5)+DT.Day)+D2+XYear+Century;
End;
function DT2Unix(DT:DateTime):LongInt;
Begin
DT2Unix:=(Gregorian2Julian(DT)-C1970)*86400+(LongInt(DT.Hour)*3600)+(DT.Min*60)+DT.Sec;
end;
{*****************************************************************************
TArObjectWriter
*****************************************************************************}
constructor tarobjectwriter.init(const Aarfn:string);
var
time : datetime;
dummy : word;
begin
arfn:=Aarfn;
new(arData,init(1,arbufsize));
new(symreloc,init(4,symrelocbufsize));
new(symstr,init(1,symstrbufsize));
new(lfnstr,init(1,lfnstrbufsize));
{ create timestamp }
getdate(time.year,time.month,time.day,dummy);
gettime(time.hour,time.min,time.sec,dummy);
Str(DT2Unix(time),timestamp);
end;
destructor tarobjectwriter.done;
begin
if Errorcount=0 then
writear;
dispose(arData,done);
dispose(symreloc,done);
dispose(symstr,done);
dispose(lfnstr,done);
end;
procedure tarobjectwriter.createarhdr(fn:string;size:longint;const gid,uid,mode:string);
var
tmp : string[9];
begin
fillchar(arhdr,sizeof(tarhdr),' ');
{ create ar header }
fn:=fn+'/';
if length(fn)>16 then
begin
arhdr.name[0]:='/';
str(lfnstr^.usedsize,tmp);
move(tmp[1],arhdr.name[1],length(tmp));
fn:=fn+#10;
lfnstr^.write(fn[1],length(fn));
end
else
move(fn[1],arhdr.name,length(fn));
{ don't write a date if also no gid/uid/mode is specified }
if gid<>'' then
move(timestamp[1],arhdr.date,sizeof(timestamp));
str(size,tmp);
move(tmp[1],arhdr.size,length(tmp));
move(gid[1],arhdr.gid,length(gid));
move(uid[1],arhdr.uid,length(uid));
move(mode[1],arhdr.mode,length(mode));
arhdr.fmag:='`'#10;
end;
procedure tarobjectwriter.create(const fn:string);
begin
objfn:=fn;
objfixup:=ardata^.usedsize;
{ reset size }
new(objdata,init(1,objbufsize));
end;
procedure tarobjectwriter.close;
begin
objdata^.align(2);
{ fix the size in the header }
createarhdr(objfn,objdata^.usedsize,'42','42','644');
{ write the header }
ardata^.write(arhdr,sizeof(tarhdr));
{ write the data of this objfile }
ardata^.write(objdata^.data^,objdata^.usedsize);
{ free this object }
dispose(objdata,done);
end;
procedure tarobjectwriter.writesym(sym:string);
begin
sym:=sym+#0;
symreloc^.write(objfixup,1);
symstr^.write(sym[1],length(sym));
end;
procedure tarobjectwriter.write(var b;len:longint);
begin
objdata^.write(b,len);
end;
procedure tarobjectwriter.writear;
function lsb2msb(l:longint):longint;
type
bytearr=array[0..3] of byte;
var
l1 : longint;
begin
bytearr(l1)[0]:=bytearr(l)[3];
bytearr(l1)[1]:=bytearr(l)[2];
bytearr(l1)[2]:=bytearr(l)[1];
bytearr(l1)[3]:=bytearr(l)[0];
lsb2msb:=l1;
end;
const
armagic:array[1..8] of char='!<arch>'#10;
type
plongint=^longint;
var
arf : file;
fixup,
relocs,i : longint;
begin
assign(arf,arfn);
{$I-}
rewrite(arf,1);
{$I+}
if ioresult<>0 then
exit;
blockwrite(arf,armagic,sizeof(armagic));
{ align first, because we need the size for the fixups of the symbol reloc }
if lfnstr^.usedsize>0 then
lfnstr^.align(2);
if symreloc^.usedsize>0 then
begin
symstr^.align(2);
fixup:=12+sizeof(tarhdr)+symreloc^.usedsize+symstr^.usedsize;
if lfnstr^.usedsize>0 then
inc(fixup,lfnstr^.usedsize+sizeof(tarhdr));
relocs:=symreloc^.count;
for i:=0to relocs-1 do
plongint(@symreloc^.data[i*4])^:=lsb2msb(plongint(@symreloc^.data[i*4])^+fixup);
createarhdr('',4+symreloc^.usedsize+symstr^.usedsize,'0','0','0');
blockwrite(arf,arhdr,sizeof(tarhdr));
relocs:=lsb2msb(relocs);
blockwrite(arf,relocs,4);
blockwrite(arf,symreloc^.data^,symreloc^.usedsize);
blockwrite(arf,symstr^.data^,symstr^.usedsize);
end;
if lfnstr^.usedsize>0 then
begin
createarhdr('/',lfnstr^.usedsize,'','','');
blockwrite(arf,arhdr,sizeof(tarhdr));
blockwrite(arf,lfnstr^.data^,lfnstr^.usedsize);
end;
blockwrite(arf,ardata^.data^,ardata^.usedsize);
system.close(arf);
end;
end.
{
$Log$
Revision 1.5 2000-01-07 01:14:28 peter
* updated copyright to 2000
Revision 1.4 1999/07/18 10:19:59 florian
* made it compilable with Dlephi 4 again
+ fixed problem with large stack allocations on win32
Revision 1.3 1999/05/09 11:38:06 peter
* don't write .o and link if errors occure during assembling
Revision 1.2 1999/05/04 21:44:53 florian
* changes to compile it with Delphi 4.0
Revision 1.1 1999/05/01 13:24:26 peter
* merged nasm compiler
* old asm moved to oldasm/
Revision 1.1 1999/03/18 20:30:51 peter
+ .a writer
}