Initial (manual) import
This commit is contained in:
1 parent
f39611c506
commit
895fe109de
661 files changed
+245862
No files matched your search
@@ -0,0 +1,611 @@
|
||||
U0 ATABlkSel(CBlkDev *bd,I64 blk,I64 cnt)
|
||||
{
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE) { //48 Bit LBA?
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk.u8[3]);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[4]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[5]);
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
} else { //28 Bit LBA
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4|blk.u8[3]);
|
||||
}
|
||||
}
|
||||
|
||||
Bool ATAWaitNotBUSY(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
I64 i;
|
||||
do {
|
||||
for (i=0;i<3;i++)
|
||||
if (!(InU8(bd->base0+ATAR0_STAT)&ATAS_BSY))
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATAWaitDRQ(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
I64 i;
|
||||
do {
|
||||
for (i=0;i<3;i++)
|
||||
if (InU8(bd->base0+ATAR0_STAT)&ATAS_DRQ)
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATANop(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_CMD,ATA_NOP);
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
}
|
||||
|
||||
U0 ATACmd(CBlkDev *bd,U8 cmd)
|
||||
{
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_CMD,cmd);
|
||||
bd->last_time=tS;
|
||||
PortNop;
|
||||
}
|
||||
|
||||
Bool ATAGetRes(CBlkDev *bd,F64 timeout,U8 *buf,I64 cnt,
|
||||
I64 _avail,Bool one_read)
|
||||
{
|
||||
I64 avail,overflow;
|
||||
bd->flags&=~BDF_LAST_WAS_WRITE;
|
||||
MemSet(buf,0,cnt);
|
||||
while (cnt>0) {
|
||||
if (!ATAWaitDRQ(bd,timeout))
|
||||
return FALSE;
|
||||
if (_avail)
|
||||
avail=_avail;
|
||||
else
|
||||
avail=InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL);
|
||||
if (avail) {
|
||||
if (avail>cnt) {
|
||||
overflow=avail-cnt;
|
||||
avail=cnt;
|
||||
} else
|
||||
overflow=0;
|
||||
if (avail&2)
|
||||
RepInU16(buf,avail>>1,bd->base0+ATAR0_DATA);
|
||||
else
|
||||
RepInU32(buf,avail>>2,bd->base0+ATAR0_DATA);
|
||||
cnt-=avail;
|
||||
buf+=avail;
|
||||
while (overflow>0) {
|
||||
InU16(bd->base0+ATAR0_DATA);
|
||||
overflow-=2;
|
||||
if (0<timeout<tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (one_read)
|
||||
break;
|
||||
} else
|
||||
Yield;
|
||||
}
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
}
|
||||
|
||||
Bool ATAPIWritePktWord(CBlkDev *bd,F64 timeout,...)
|
||||
{
|
||||
I64 i;
|
||||
for (i=0;i<argc;i++) {
|
||||
if (!ATAWaitDRQ(bd,timeout))
|
||||
return FALSE;
|
||||
OutU16(bd->base0+ATAR0_DATA,EndianU16(argv[i]));
|
||||
bd->last_time=tS;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool ATAPISetMaxSpeed(CBlkDev *bd)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0xBB00,0xFFFF,0xFFFF,0,0,0);
|
||||
return ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAPISeek(CBlkDev *bd,I64 native_blk)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x2B00,native_blk>>16,native_blk,0,0,0);
|
||||
return ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start)
|
||||
{
|
||||
I64 i;
|
||||
if (start)
|
||||
i=0x100;
|
||||
else
|
||||
i=0;
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
//Start/Stop
|
||||
if (ATAPIWritePktWord(bd,timeout,0x1B00,0,i,0,0,0))
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 ATAGetDevId(CBlkDev *bd,F64 timeout,Bool keep_id_record)
|
||||
{
|
||||
I64 res=BDT_NULL;
|
||||
U16 *id_record=NULL;
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_ID_DEV);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
if (InU8(bd->base0+ATAR0_STAT)&ATAS_ERR)
|
||||
res=BDT_ATAPI;
|
||||
else {
|
||||
id_record=ACAlloc(512);
|
||||
if (ATAGetRes(bd,timeout,id_record,512,512,FALSE))
|
||||
res=BDT_ATA;
|
||||
else {
|
||||
Free(id_record);
|
||||
id_record=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keep_id_record) {
|
||||
Free(bd->dev_id_record);
|
||||
bd->dev_id_record=id_record;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 ATAReadNativeMax(CBlkDev *bd,F64 timeout)
|
||||
{//Returns zero on err
|
||||
I64 res=0;
|
||||
Bool okay=TRUE;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_DEV_RST);
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
} else {
|
||||
while (InU8(bd->base0+ATAR0_STAT) & ATAS_BSY) {
|
||||
if (bd->flags&BDF_LAST_WAS_WRITE)
|
||||
OutU16(bd->base0+ATAR0_DATA,0);
|
||||
else
|
||||
InU16(bd->base0+ATAR0_DATA);
|
||||
Yield;
|
||||
if (0<timeout<tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (ATAGetDevId(bd,timeout,TRUE)==BDT_NULL)
|
||||
okay=FALSE;
|
||||
else
|
||||
BEqu(&bd->flags,BDf_EXT_SIZE,Bt(&bd->dev_id_record[86],10));
|
||||
}
|
||||
if (okay) {
|
||||
if (bd->flags & BDF_EXT_SIZE && bd->base1) {
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
ATACmd(bd,ATA_READ_NATIVE_MAX_EXT);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
|
||||
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x80);
|
||||
res.u8[3]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[4]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[5]=InU8(bd->base0+ATAR0_HCYL);
|
||||
|
||||
if (res>>24==res&0xFFFFFF) {//Kludge to make QEMU work
|
||||
bd->flags&=~BDF_EXT_SIZE;
|
||||
res&=0xFFFFFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_READ_NATIVE_MAX);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
|
||||
res.u8[3]=InU8(bd->base0+ATAR0_SEL) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bd->max_blk=res;
|
||||
}
|
||||
|
||||
I64 ATAPIReadCapacity(CBlkDev *bd,I64 *_blk_size=NULL)
|
||||
{//Supposedly this can return a res +/- 75 sects.
|
||||
//Error might just be for music.
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
U32 buf[2];
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,8);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x2500,0,0,0,0,0);
|
||||
if (!ATAGetRes(bd,0,buf,8,0,TRUE))
|
||||
buf[0]=buf[1]=0;
|
||||
} else
|
||||
buf[0]=buf[1]=0;
|
||||
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
if (_blk_size) *_blk_size=EndianU32(buf[1]);
|
||||
return EndianU32(buf[0]);
|
||||
}
|
||||
|
||||
CATAPITrack *ATAPIReadTrackInfo(CBlkDev *bd,I64 blk)
|
||||
{
|
||||
CATAPITrack *res=CAlloc(sizeof(CATAPITrack));
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,sizeof(CATAPITrack)&0xFF);
|
||||
OutU8(bd->base0+ATAR0_HCYL,sizeof(CATAPITrack)>>8);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x5200,blk.u16[1],blk.u16[0],
|
||||
(sizeof(CATAPITrack)&0xFF00)>>8,(sizeof(CATAPITrack)&0x00FF)<<8,0);
|
||||
if (!ATAGetRes(bd,0,res,sizeof(CATAPITrack),0,TRUE)) {
|
||||
Free(res);
|
||||
res=NULL;
|
||||
}
|
||||
} else {
|
||||
Free(res);
|
||||
res=NULL;
|
||||
}
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool ATAInit(CBlkDev *bd)
|
||||
{
|
||||
Bool unlock=BlkDevLock(bd),okay=FALSE;
|
||||
|
||||
if (bd->type==BDT_ATAPI)
|
||||
bd->flags&=~BDF_EXT_SIZE;
|
||||
else
|
||||
bd->flags|=BDF_EXT_SIZE;
|
||||
|
||||
if (ATAReadNativeMax(bd,tS+0.1)) {
|
||||
ATABlkSel(bd,bd->max_blk,0);
|
||||
if (bd->flags&BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_SET_MAX_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_SET_MAX);
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
okay=TRUE;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
if (ATAPIStartStop(bd,0,TRUE)) {
|
||||
if(!ATAPISetMaxSpeed(bd))
|
||||
okay=FALSE;
|
||||
} else
|
||||
okay=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
return okay;
|
||||
}
|
||||
|
||||
Bool ATAPIWaitReady(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
do {
|
||||
if (!ATAWaitNotBUSY(bd,timeout) ||
|
||||
!ATANop(bd,timeout) ||
|
||||
!ATAPIStartStop(bd,timeout,TRUE))
|
||||
return FALSE;
|
||||
if (InU8(bd->base0+ATAR0_STAT) & ATAS_DRDY &&
|
||||
!InU8(bd->base0+ATAR0_FEAT));
|
||||
return TRUE;
|
||||
ATAInit(bd);
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 retries=3;
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
|
||||
retry:
|
||||
ATABlkSel(bd,blk,cnt);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_READ_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_READ_MULTI);
|
||||
if (!ATAGetRes(bd,tS+1.0,buf,cnt*bd->blk_size,BLK_SIZE,FALSE)) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
|
||||
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
I64 ATAProbe(I64 base0,I64 base1,I64 unit)
|
||||
{
|
||||
CBlkDev bd;
|
||||
MemSet(&bd,0,sizeof(CBlkDev));
|
||||
bd.type=BDT_ATAPI;
|
||||
bd.base0=base0;
|
||||
bd.base1=base1;
|
||||
bd.unit=unit;
|
||||
bd.blk_size=DVD_BLK_SIZE;
|
||||
return ATAGetDevId(&bd,tS+0.1,FALSE);
|
||||
}
|
||||
|
||||
Bool ATAPIReadBlks2(CBlkDev *bd,F64 timeout,U8 *buf,
|
||||
I64 native_blk, I64 cnt,Bool lock)
|
||||
{
|
||||
Bool res=FALSE,unlock;
|
||||
if (cnt<=0)
|
||||
return FALSE;
|
||||
if (lock)
|
||||
unlock=BlkDevLock(bd);
|
||||
if (ATAPIWaitReady(bd,timeout)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
if (ATAPIWritePktWord(bd,timeout,0xA800,
|
||||
native_blk.u16[1],native_blk,cnt.u16[1],cnt,0) &&
|
||||
ATAGetRes(bd,timeout,buf,cnt*bd->blk_size,0,FALSE)) {
|
||||
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
|
||||
res=TRUE;
|
||||
}
|
||||
}
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (lock && unlock) BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 ATAPIReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
CDrv *dv=Let2Drv(bd->first_drv_let);
|
||||
I64 retry,spc=bd->blk_size>>BLK_SIZE_BITS,n,blk2,
|
||||
l2=bd->max_reads<<1+spc<<1;
|
||||
U8 *dvd_buf=MAlloc(l2<<BLK_SIZE_BITS);
|
||||
if (cnt>0) {
|
||||
if (blk<=bd->max_reads)
|
||||
blk2=0;
|
||||
else
|
||||
blk2=FloorU64(blk-bd->max_reads,spc);
|
||||
if (blk2+l2>dv->size+dv->drv_offset)
|
||||
l2=dv->size+dv->drv_offset-blk2;
|
||||
n=(l2+spc-1)/spc;
|
||||
|
||||
retry=4;
|
||||
while (--retry)
|
||||
if (ATAPIReadBlks2(bd,tS+7.0+0.004*n,dvd_buf,blk2/spc,n,TRUE))
|
||||
//n is 0x800 if max_reads. Up to 8 additional seconds
|
||||
break;
|
||||
if (!retry)
|
||||
ATAPIReadBlks2(bd,0,dvd_buf,blk2/spc,n,TRUE);
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,dvd_buf,blk2,n*spc);
|
||||
MemCpy(buf,dvd_buf+(blk-blk2)<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
|
||||
}
|
||||
Free(dvd_buf);
|
||||
}
|
||||
|
||||
Bool ATARBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 n;
|
||||
CBlkDev *bd=dv->bd;
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>bd->max_reads)
|
||||
n=bd->max_reads;
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAPIReadBlks(bd,buf,blk,n);
|
||||
else
|
||||
ATAReadBlks(bd,buf,blk,n);
|
||||
buf+=n<<BLK_SIZE_BITS;
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{//For low level disk access.
|
||||
//Use WBlks() instead.
|
||||
I64 i,U32s_avail,sects_avail,retries=3;
|
||||
F64 timeout;
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
retry:
|
||||
ATABlkSel(bd,blk,cnt);
|
||||
if (bd->flags&BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_WRITE_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_WRITE_MULTI);
|
||||
bd->flags|=BDF_LAST_WAS_WRITE;
|
||||
while (cnt>0) {
|
||||
timeout=tS+1.0;
|
||||
while (TRUE) {
|
||||
i=InU8(bd->base0+ATAR0_STAT);
|
||||
if (!(i & ATAS_DRDY)||!(i & ATAS_DRQ)) {
|
||||
Yield;
|
||||
} else
|
||||
break;
|
||||
if (/* i&ATAS_ERR||*/ tS>timeout) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
}
|
||||
sects_avail=1;
|
||||
U32s_avail=sects_avail<<BLK_SIZE_BITS>>2;
|
||||
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
|
||||
buf+=U32s_avail<<2;
|
||||
cnt-=sects_avail;
|
||||
retries=3;
|
||||
}
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
Bool ATAPISync(CBlkDev *bd)
|
||||
{
|
||||
Bool okay=TRUE;
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
else {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x3500,0,0,0,0,0);
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
U0 ATAPIClose(CBlkDev *bd,I64 close_field=0x200,I64 track=0)
|
||||
{//0x200 CD/DVD part 1
|
||||
// 0x300 DVD part 2
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x5B00,close_field,track,0,0,0);
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
U0 ATAPIWriteBlks(CBlkDev *bd,U8 *buf, I64 native_blk, I64 cnt)
|
||||
{
|
||||
I64 U32s_avail;
|
||||
U8 *buf2;
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
ATAPISeek(bd,native_blk);
|
||||
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_CMD,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x0400,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
|
||||
bd->flags|=BDF_LAST_WAS_WRITE;
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
|
||||
ATAPISeek(bd,native_blk);
|
||||
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0xAA00,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
|
||||
buf2=buf+bd->blk_size*cnt;
|
||||
while (buf<buf2) {
|
||||
ATAWaitDRQ(bd,0);
|
||||
U32s_avail=(InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL))>>2;
|
||||
if (buf+U32s_avail<<2>buf2)
|
||||
U32s_avail=(buf2-buf)>>2;
|
||||
if (U32s_avail) {
|
||||
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
|
||||
buf+=U32s_avail<<2;
|
||||
blkdev.write_cnt+=U32s_avail>>(BLK_SIZE_BITS-2);
|
||||
}
|
||||
}
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAWBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 n,spc;
|
||||
CBlkDev *bd=dv->bd;
|
||||
Bool unlock;
|
||||
spc=bd->blk_size>>BLK_SIZE_BITS;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
unlock=BlkDevLock(bd);
|
||||
ATAPIWaitReady(bd,0);
|
||||
}
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>bd->max_writes)
|
||||
n=bd->max_writes;
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);
|
||||
else
|
||||
ATAWriteBlks(bd,buf,blk,n);
|
||||
buf+=n<<BLK_SIZE_BITS;
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
blkdev.write_cnt+=n;
|
||||
}
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
ATAPISync(bd);
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
Bool BootDVDProbe(CBlkDev *bd)
|
||||
{
|
||||
U8 *img=CAlloc(DVD_BLK_SIZE);
|
||||
I64 i;
|
||||
Bool res=FALSE;
|
||||
"Port: %04X,%04X Unit: %02X ",bd->base0,bd->base1,bd->unit;
|
||||
if (ATAProbe(bd->base0,bd->base1,bd->unit)==BDT_ATAPI) {
|
||||
" ATAPI";
|
||||
if (ATAPIStartStop(bd,tS+5.0,TRUE)) {
|
||||
" Started";
|
||||
for (i=0;i<2;i++) {//Retry
|
||||
if (ATAPIReadBlks2(bd,tS+7.0,img,sys_boot_blk,1,FALSE)) {
|
||||
if ((img+sys_boot_src.u16[1]<<BLK_SIZE_BITS)(CKernel *)
|
||||
->compile_time==sys_compile_time) {
|
||||
" Found\n";
|
||||
return TRUE;
|
||||
} else
|
||||
" Read";
|
||||
} else
|
||||
" NoRead";
|
||||
}
|
||||
}
|
||||
}
|
||||
" Nope\n";
|
||||
Free(img);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool BootDVDProbeAll(CBlkDev *bd)
|
||||
{
|
||||
I64 d1,d2,i,j,k;
|
||||
|
||||
bd->base1=0;
|
||||
for (k=0;k<256;k++) {
|
||||
i=-1;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x010100+k,++i);
|
||||
if (j<0)
|
||||
break;
|
||||
"Subcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
|
||||
if (d1&1 && d2&1) {
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
|
||||
if (d1&1 && d2&1) {
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d1=0x1F0;
|
||||
d2=0x3F6;
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
d1=0x170;
|
||||
d2=0x376;
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 ATARepEntry(I64 base0,I64 base1,I64 unit,U8 *msg,
|
||||
CATARep **_head,I64 *num_hints)
|
||||
{
|
||||
I64 type;
|
||||
base0&=-8;
|
||||
base1&=-4;
|
||||
CATARep *tmpha;
|
||||
if (type=ATAProbe(base0,base1,unit)) {
|
||||
*num_hints+=1;
|
||||
"\n$$PURPLE$$ $$BT+X,\"%d\",LM=\"%d\\n\"$$$$FG$$$$LM,4$$",*num_hints,*num_hints;
|
||||
if (type==BDT_ATA)
|
||||
"$$RED$$Hard Drive $$LTBLUE$$ATA ";
|
||||
else
|
||||
"$$RED$$CD/DVD Drive $$LTBLUE$$ATAPI ";
|
||||
"%s$$FG$$\n",msg;
|
||||
if (base0==blkdev.ins_base0 && unit==blkdev.ins_unit)
|
||||
"$$PURPLE$$(Drive originally installed from.)$$FG$$\n";
|
||||
"Base0:0x%04X Base1:0x%04X Unit:%d$$LM,0$$\n",
|
||||
base0,base1,unit;
|
||||
if (_head) {
|
||||
tmpha=CAlloc(sizeof(CATARep));
|
||||
tmpha->next=*_head;
|
||||
*_head=tmpha;
|
||||
tmpha->num=*num_hints;
|
||||
tmpha->type=type;
|
||||
tmpha->base0=base0;
|
||||
tmpha->base1=base1;
|
||||
tmpha->unit=unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bool ATARepExitAllApplications()
|
||||
{
|
||||
"\nWe're going to probe hardware.\n"
|
||||
"$$RED$$Exit all other applications.$$FG$$\n"
|
||||
"Press '$$PURPLE$$p$$FG$$' to probe or '$$PURPLE$$s$$FG$$' to skip.\n";
|
||||
if (ToUpper(GetChar(,FALSE))=='S')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public I64 ATARep(Bool pmt=TRUE,Bool just_ide=FALSE,CATARep **_head=NULL)
|
||||
{//Report possible ATA devices by probing. Hard disks and CD/DVDs.
|
||||
I64 d1,d2,i,j,k,cnt=0,unlock_flags=0,num_hints=0;
|
||||
#assert BLKDEVS_NUM<=64
|
||||
if (_head) *_head=NULL;
|
||||
|
||||
if (pmt && ATARepExitAllApplications)
|
||||
return 0;
|
||||
|
||||
for (i=0;i<BLKDEVS_NUM;i++)
|
||||
if (blkdev.blkdevs[i].bd_signature==BD_SIGNATURE_VAL)
|
||||
BEqu(&unlock_flags,i,
|
||||
BlkDevLock(&blkdev.blkdevs[i]));
|
||||
|
||||
if (!just_ide)
|
||||
for (k=0;k<256;k++) {
|
||||
i=-1;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x010100+k,++i);
|
||||
if (j<0)
|
||||
break;
|
||||
|
||||
"\nSubcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
|
||||
cnt++;
|
||||
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
|
||||
if (d1&1 && d2&1) {
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
} else {
|
||||
d1=0x1F0; d2=0x3F6;
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
}
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
|
||||
if (d1&1 && d2&1) {
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
} else {
|
||||
d1=0x170; d2=0x376;
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cnt) {
|
||||
d1=0x1F0; d2=0x3F6;
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
|
||||
d1=0x170; d2=0x376;
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
}
|
||||
'\n\n';
|
||||
for (i=0;i<BLKDEVS_NUM;i++)
|
||||
if (Bt(&unlock_flags,i))
|
||||
BlkDevUnlock(&blkdev.blkdevs[i]);
|
||||
return num_hints;
|
||||
}
|
||||
|
||||
CATARep *ATARepFind(CATARep *haystack_head,I64 needle_num)
|
||||
{
|
||||
while (haystack_head) {
|
||||
if (haystack_head->num==needle_num)
|
||||
return haystack_head;
|
||||
haystack_head=haystack_head->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CATARep *ATAIDDrvs(CATARep *head,CATARep **_ata_drv,CATARep **_atapi_drv)
|
||||
{//This is for when trying to sort-out main hard drives and CD/DVD drives.
|
||||
CATARep *res=NULL,*tmpha=head,*ata_drv=NULL,*atapi_drv=NULL;
|
||||
CBlkDev *bd;
|
||||
Bool was_silent=Silent,ins_found=FALSE;
|
||||
bd=Let2BlkDev(':',FALSE);
|
||||
Silent(was_silent);
|
||||
while (tmpha) {
|
||||
if (!res && bd && bd->type==tmpha->type) {
|
||||
if (bd->type==BDT_ATAPI &&
|
||||
bd->base0==tmpha->base0 && bd->unit==tmpha->unit)
|
||||
res=atapi_drv=tmpha;
|
||||
else if (bd->type==BDT_ATA && bd->base0==tmpha->base0 &&
|
||||
bd->base1==tmpha->base1 && bd->unit==tmpha->unit)
|
||||
res=ata_drv=tmpha;
|
||||
}
|
||||
if (!res || res->type!=tmpha->type) {
|
||||
if (tmpha->type==BDT_ATA) {
|
||||
if (!ata_drv || tmpha->unit<ata_drv->unit ||
|
||||
tmpha->unit==ata_drv->unit && tmpha->num<ata_drv->num)
|
||||
ata_drv=tmpha;
|
||||
} else if (tmpha->type==BDT_ATAPI) {
|
||||
if (!atapi_drv || !ins_found && (tmpha->unit<atapi_drv->unit ||
|
||||
tmpha->unit==atapi_drv->unit && tmpha->num<atapi_drv->num))
|
||||
atapi_drv=tmpha;
|
||||
}
|
||||
}
|
||||
if (tmpha->type==BDT_ATAPI && bd && bd->type==BDT_ATA &&
|
||||
tmpha->base0==blkdev.ins_base0 && tmpha->unit==blkdev.ins_unit) {
|
||||
if (!ins_found) {
|
||||
atapi_drv=tmpha;
|
||||
ins_found=TRUE;
|
||||
}
|
||||
}
|
||||
tmpha=tmpha->next;
|
||||
}
|
||||
if (_ata_drv) *_ata_drv =ata_drv;
|
||||
if (_atapi_drv) *_atapi_drv=atapi_drv;
|
||||
return res;
|
||||
}
|
||||
|
||||
CBlkDev *ATAMount(U8 first_drv_let,I64 type,I64 base0,I64 base1,I64 unit)
|
||||
{
|
||||
CBlkDev *res;
|
||||
if (0<=first_drv_let-'A'<DRVS_NUM && (type==BDT_ATA || type==BDT_ATAPI) &&
|
||||
0<=unit<=1) {
|
||||
res=BlkDevNextFreeSlot(first_drv_let,type);
|
||||
res->unit=unit;
|
||||
res->base0=base0;
|
||||
res->base1=base1;
|
||||
if (BlkDevAdd(res,,FALSE,FALSE))
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 AutoMountIDE()
|
||||
{//Try to mount hard drive and CD/DVD, automatically. (Kernel.Cfg option).
|
||||
//It uses 'C' and 'T' as first drive letters or whatever you set
|
||||
//in config when compiling Kernel.BIN.
|
||||
I64 res=0;
|
||||
CATARep *head=NULL,*ata_drv=NULL,*atapi_drv=NULL,*tmpha;
|
||||
ATARep(FALSE,TRUE,&head);
|
||||
ATAIDDrvs(head,&ata_drv,&atapi_drv);
|
||||
if (ata_drv && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
|
||||
ata_drv->base0,ata_drv->base1,ata_drv->unit))
|
||||
res++;
|
||||
if (atapi_drv && ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
|
||||
atapi_drv->base0,atapi_drv->base1,atapi_drv->unit))
|
||||
res++;
|
||||
tmpha=head;
|
||||
while (tmpha) {
|
||||
if (tmpha!=ata_drv && tmpha!=atapi_drv) {
|
||||
if (tmpha->type==BDT_ATA && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
|
||||
tmpha->base0,tmpha->base1,tmpha->unit))
|
||||
res++;
|
||||
else if (tmpha->type==BDT_ATAPI &&
|
||||
ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
|
||||
tmpha->base0,tmpha->base1,tmpha->unit))
|
||||
res++;
|
||||
}
|
||||
tmpha=tmpha->next;
|
||||
}
|
||||
LinkedLstDel(head);
|
||||
blkdev.auto_mount_ide_cnt=res;
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
U0 BlkDevLockFwdingSet(CBlkDev *bd)
|
||||
{ //If two blkdevs on same controller, use just one lock
|
||||
CBlkDev *bd1;
|
||||
I64 i;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
bd->lock_fwding=Let2BlkDev(*bd->file_dsk_name);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
for (i=0;i<BLKDEVS_NUM;i++) {
|
||||
bd1=&blkdev.blkdevs[i];
|
||||
if (bd1->bd_signature==BD_SIGNATURE_VAL && bd!=bd1 &&
|
||||
(bd1->type==BDT_ATAPI || bd1->type==BDT_ATA) &&
|
||||
bd1->base0==bd->base0) {
|
||||
bd->lock_fwding=bd1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
|
||||
Bool whole_drv,Bool make_free)
|
||||
{//It will mount just one partition of prt_num>=0.
|
||||
//When repartitioing whole drive, whole_drv=TRUE.
|
||||
I64 i,j,ext_base,offset,res=0,num=0;
|
||||
CDrv *dv;
|
||||
CRedSeaBoot br;
|
||||
CMasterBoot mbr;
|
||||
|
||||
bd->bd_signature=BD_SIGNATURE_VAL;
|
||||
if (make_free)
|
||||
dv=DrvMakeFreeSlot(bd->first_drv_let);
|
||||
else
|
||||
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let));
|
||||
dv->bd=bd;
|
||||
dv->drv_offset=bd->drv_offset;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
//This is to force creation of a RAM
|
||||
//drive during boot, so it is probably
|
||||
//MAlloced to the same addr and can
|
||||
//be assumed to be already formatted.
|
||||
//If this line is removed, RAM Drives
|
||||
//will be alloced on a just-in-time
|
||||
//basis.
|
||||
if (BlkDevInit(bd))
|
||||
res++;
|
||||
else
|
||||
dv->dv_signature=0;
|
||||
break;
|
||||
case BDT_ATA:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL; //Temporarily validate
|
||||
if (!BlkDevInit(bd))
|
||||
dv->dv_signature=0; //Revoke validation
|
||||
else {
|
||||
dv->dv_signature=0; //Revoke validation
|
||||
if (whole_drv) {
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
//The following read is a test read.
|
||||
//if it hangs, the drive is not supported.
|
||||
ATAReadBlks(bd,&mbr,0,1);
|
||||
break;
|
||||
}
|
||||
offset=0;
|
||||
ext_base=INVALID_CLUSTER;
|
||||
while (prt_num<0 || num<=prt_num) {
|
||||
ATAReadBlks(bd,&mbr,offset,1);
|
||||
if (mbr.signature!=0xAA55)
|
||||
break;
|
||||
j=-1;
|
||||
for (i=0;i<4 && (prt_num<0 || num<=prt_num);i++) {
|
||||
if (mbr.p[i].type) {
|
||||
if (make_free)
|
||||
dv=DrvMakeFreeSlot(bd->first_drv_let+res);
|
||||
else
|
||||
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let+res));
|
||||
dv->bd=bd;
|
||||
dv->drv_offset=mbr.p[i].offset+offset;
|
||||
dv->size =mbr.p[i].size;
|
||||
switch (mbr.p[i].type) {
|
||||
case MBR_PT_REDSEA:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaInit(dv);
|
||||
break;
|
||||
case MBR_PT_FAT32a:
|
||||
case MBR_PT_FAT32b:
|
||||
case MBR_PT_FAT32c:
|
||||
case MBR_PT_FAT32d:
|
||||
case MBR_PT_FAT32e:
|
||||
case MBR_PT_FAT32f:
|
||||
ATAReadBlks(bd,&br,dv->drv_offset,1);
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
if (br.signature==MBR_PT_REDSEA) {
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaInit(dv);
|
||||
} else {
|
||||
dv->fs_type=FSt_FAT32;
|
||||
FAT32Init(dv);
|
||||
}
|
||||
break;
|
||||
case MBR_PT_NTFS:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_NTFS;
|
||||
break;
|
||||
case 5:
|
||||
case 15:
|
||||
j=i;
|
||||
break;
|
||||
default:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_UNKNOWN;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (Let2BlkDevType(bd->first_drv_let+res)!=bd->type)
|
||||
break;
|
||||
if (j<0)
|
||||
break;
|
||||
if (!mbr.p[j].offset)
|
||||
break;
|
||||
if (ext_base==INVALID_CLUSTER) {
|
||||
offset=mbr.p[j].offset;
|
||||
ext_base=offset;
|
||||
} else
|
||||
offset=mbr.p[j].offset+ext_base;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_ISO9660; //Start with this
|
||||
dv->size=0;
|
||||
break;
|
||||
}
|
||||
if (res)
|
||||
BlkDevLockFwdingSet(bd);
|
||||
else
|
||||
BlkDevDel(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool DrvEnable(U8 drv_let,Bool val)
|
||||
{//Can unmount or remount, but not mount the first time.
|
||||
CDrv *dv;
|
||||
if (dv=Let2Drv(drv_let,FALSE))
|
||||
return !LBEqu(&dv->fs_type,FStf_DISABLE,!val);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 SysGetI64()
|
||||
{
|
||||
U8 st[STR_LEN];
|
||||
GetS(st,STR_LEN,FALSE);
|
||||
return Str2I64(st,16);
|
||||
}
|
||||
|
||||
Bool GetBaseUnit(CBlkDev *bd)
|
||||
{
|
||||
I64 ch;
|
||||
Bool probe;
|
||||
#exe {
|
||||
if (kernel_cfg->opts[CFG_DONT_PROBE])
|
||||
StreamPrint("probe=FALSE;");
|
||||
else
|
||||
StreamPrint("probe=TRUE;");
|
||||
};
|
||||
if (!probe || !BootDVDProbeAll(bd)) {
|
||||
"\nDon't worry. This is not a product\n"
|
||||
"registration. TempleOS just needs the\n"
|
||||
"I/O port numbers for the CD/DVD.\n"
|
||||
"\nRetry the ports above or check Windows\n"
|
||||
"system information under I/O ports for\n"
|
||||
"'IDE', 'ATA' or 'SATA'.\n"
|
||||
"In Linux, use 'lspci -v' for ports.\n"
|
||||
"\n\nEnter 4-digit hex I/O Port number.\n"
|
||||
"CD/DVD I/O Port Base0: 0x";
|
||||
bd->base0=SysGetI64;
|
||||
bd->base1=0;
|
||||
bd->unit =0;
|
||||
if (bd->base0) {
|
||||
"\nUnit (0 or 1): ";
|
||||
do ch=GetChar(,FALSE);
|
||||
while (!('0'<=ch<='1'));
|
||||
'' ch;
|
||||
bd->unit=ch-'0';
|
||||
blkdev.dvd_boot_is_good=BootDVDProbe(bd);
|
||||
return TRUE;
|
||||
} else {
|
||||
blkdev.dvd_boot_is_good=FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 BlkDevsInitAll()
|
||||
{
|
||||
CBlkDev *bd;
|
||||
I64 i;
|
||||
blkdev.blkdevs=CAlloc(sizeof(CBlkDev)*BLKDEVS_NUM);
|
||||
blkdev.drvs=CAlloc(sizeof(CDrv)*DRVS_NUM);
|
||||
for (i=0;i<DRVS_NUM;i++)
|
||||
blkdev.let_to_drv[i]=&blkdev.drvs[i];
|
||||
#exe {
|
||||
if (kernel_cfg->opts[CFG_AUTO_MOUNT_IDE])
|
||||
StreamPrint("AutoMountIDE;");
|
||||
StreamPrint("#exe {Option(OPTf_WARN_PAREN,OFF);}");
|
||||
StreamDoc(kernel_cfg->add_dev);
|
||||
StreamPrint("#exe {Option(OPTf_WARN_PAREN,ON);}");
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#define ZERO_BUF_SIZE 2048
|
||||
U0 WZeroBlks(CDrv *dv,I64 blk,I64 cnt)
|
||||
{//Fill blk cnt with zeros in Drv.
|
||||
I64 n;
|
||||
U8 *z=CAlloc(ZERO_BUF_SIZE<<BLK_SIZE_BITS);
|
||||
Bool show_progress;
|
||||
if (cnt>ZERO_BUF_SIZE && dv->bd->type!=BDT_RAM) {
|
||||
progress1=0; progress1_max=cnt;
|
||||
StrCpy(progress1_desc,"Zeroing");
|
||||
show_progress=TRUE;
|
||||
} else
|
||||
show_progress=FALSE;
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>ZERO_BUF_SIZE)
|
||||
n=ZERO_BUF_SIZE;
|
||||
WBlks(dv,z,blk,n);
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
if (show_progress)
|
||||
progress1+=n;
|
||||
Yield; //Prevent locking
|
||||
}
|
||||
Free(z);
|
||||
if (show_progress) {
|
||||
*progress1_desc=0;
|
||||
progress1=progress1_max=0;
|
||||
}
|
||||
}
|
||||
|
||||
Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{//Read blk cnt from Drv to buf.
|
||||
Bool res=TRUE,unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (cnt<=0) return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (dv->drv_offset && blk<dv->drv_offset ||
|
||||
blk+cnt>dv->drv_offset+dv->size)
|
||||
throw('Drv');
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
RCache(dv,&buf,&blk,&cnt);
|
||||
if (cnt>0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(buf,bd->RAM_dsk+blk<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FRBlks(bd->file_dsk,buf,blk,cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res=ATARBlks(dv,buf,blk,cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time=tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,buf,blk,cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{//Write blk cnt from buf to Drv.
|
||||
Bool res=TRUE,unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (cnt<=0) return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (bd->flags&BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
|
||||
throw('BlkDev');
|
||||
if (dv->drv_offset && blk<dv->drv_offset ||
|
||||
blk+cnt>dv->drv_offset+dv->size)
|
||||
throw('Drv');
|
||||
if (cnt>0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(bd->RAM_dsk+blk<<BLK_SIZE_BITS,buf,cnt<<BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FWBlks(bd->file_dsk,buf,blk,cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res=ATAWBlks(dv,buf,blk,cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time=tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,buf,blk,cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
Bool BlkDevLock(CBlkDev *bd)
|
||||
{//Make this task have exclusive access to BlkDev.
|
||||
BlkDevChk(bd);
|
||||
while (bd->lock_fwding)
|
||||
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
|
||||
if (!Bt(&bd->locked_flags,BDlf_LOCKED) || bd->owning_task!=Fs) {
|
||||
while (LBts(&bd->locked_flags,BDlf_LOCKED))
|
||||
Yield;
|
||||
bd->owning_task=Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE)
|
||||
{//Release exclusive lock on access to BlkDev.
|
||||
BlkDevChk(bd);
|
||||
while (bd->lock_fwding)
|
||||
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
|
||||
if (Bt(&bd->locked_flags,BDlf_LOCKED) && bd->owning_task==Fs) {
|
||||
if (rst)
|
||||
bd->flags&=~(BDF_INITIALIZED|BDF_INIT_IN_PROGRESS);
|
||||
bd->owning_task=NULL;
|
||||
LBtr(&bd->locked_flags,BDlf_LOCKED);
|
||||
Yield; //Prevent deadlock
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool BlkDevInit(CBlkDev *bd)
|
||||
{
|
||||
CDirEntry de;
|
||||
U8 buf[STR_LEN];
|
||||
CDrv *dv=Let2Drv(bd->first_drv_let);
|
||||
Bool res=FALSE;
|
||||
if (!LBts(&bd->flags,BDf_INITIALIZED)) {
|
||||
bd->flags|=BDF_INIT_IN_PROGRESS;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
if (!bd->RAM_dsk) {
|
||||
bd->RAM_dsk=AMAlloc((bd->max_blk+1)<<BLK_SIZE_BITS);
|
||||
bd->max_blk=MSize(bd->RAM_dsk)>>BLK_SIZE_BITS-1;
|
||||
}
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
if (RedSeaValidate(bd->first_drv_let))
|
||||
RedSeaInit(dv);
|
||||
else
|
||||
RedSeaFmt(bd->first_drv_let);
|
||||
res=TRUE;
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
if (FileFind(bd->file_dsk_name,&de,FUF_JUST_FILES)) {
|
||||
bd->max_blk=de.size>>BLK_SIZE_BITS-1;
|
||||
try bd->file_dsk=FOpen(bd->file_dsk_name,"rc",bd->max_blk+1);
|
||||
catch {
|
||||
if (Fs->except_ch=='File')
|
||||
PrintErr("Not Contiguous. Move file to filename.ISO.C.\n");
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
if (bd->file_dsk) {
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
if (RedSeaValidate(bd->first_drv_let)) {
|
||||
RedSeaInit(dv);
|
||||
res=TRUE;
|
||||
} else
|
||||
PrintErr("Not RedSea\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
if (!bd->file_dsk_name) {
|
||||
StrPrint(buf,"%C:/Drv%C.ISO.C",
|
||||
blkdev.boot_drv_let,bd->first_drv_let);
|
||||
bd->file_dsk_name=AStrNew(buf);
|
||||
}
|
||||
if (bd->max_blk<7)
|
||||
bd->max_blk=7;
|
||||
bd->file_dsk=FOpen(bd->file_dsk_name,"wc",bd->max_blk+1);
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
RedSeaFmt(bd->first_drv_let);
|
||||
CallExtStr("RedSeaISO9660",bd->file_dsk_name,bd->first_drv_let);
|
||||
res=TRUE;
|
||||
break;
|
||||
case BDT_ATA:
|
||||
bd->max_reads=128;
|
||||
bd->max_writes=1;
|
||||
res=ATAInit(bd);
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
//0xFFFF*4 is too big for my taste
|
||||
bd->max_reads=0x800*4;
|
||||
//max of maybe a quarter of disk cache
|
||||
if (bd->max_reads>blkdev.cache_size/BLK_SIZE/4)
|
||||
bd->max_reads=blkdev.cache_size/BLK_SIZE/4 & ~3;
|
||||
if (bd->max_reads<128)
|
||||
bd->max_reads=128;
|
||||
bd->max_writes=0xFFFF*4;
|
||||
if (res=ATAInit(bd))
|
||||
dv->size=bd->max_blk+1;
|
||||
break;
|
||||
}
|
||||
if (res && bd->flags & BDF_READ_CACHE)
|
||||
DskCacheInvalidate(dv);
|
||||
bd->flags&=~BDF_INIT_IN_PROGRESS;
|
||||
} else
|
||||
res=TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 BlkDevsRelease()
|
||||
{//When task dies, release all owned BlkDevs.
|
||||
I64 i;
|
||||
CBlkDev *bd;
|
||||
for (i=0;i<BLKDEVS_NUM;i++) {
|
||||
bd=&blkdev.blkdevs[i];
|
||||
if (bd->owning_task==Fs && bd->bd_signature==BD_SIGNATURE_VAL)
|
||||
BlkDevUnlock(bd,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type)
|
||||
{//Locate free slot for new BlkDev, like during $LK,"Mount",A="MN:Mount"$().
|
||||
I64 i=0;
|
||||
CBlkDev *res;
|
||||
if (Let2BlkDevType(first_drv_let)!=type)
|
||||
throw('BlkDev');
|
||||
do {
|
||||
res=&blkdev.blkdevs[i];
|
||||
if (res->bd_signature!=BD_SIGNATURE_VAL) {
|
||||
MemSet(res,0,sizeof(CBlkDev));
|
||||
res->first_drv_let=first_drv_let;
|
||||
res->type=type;
|
||||
res->flags=BDF_READ_CACHE;
|
||||
res->blk_size=BLK_SIZE;
|
||||
res->max_blk=0xEFFFFFFF;
|
||||
switch (type) {
|
||||
case BDT_RAM:
|
||||
res->flags&=~BDF_READ_CACHE;
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
res->flags|=BDF_READ_ONLY;
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
res->flags|=BDF_REMOVABLE|BDF_READ_ONLY;
|
||||
res->blk_size=DVD_BLK_SIZE;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} while (++i<BLKDEVS_NUM);
|
||||
throw('BlkDev');
|
||||
return NULL; //never gets here
|
||||
}
|
||||
|
||||
U0 BlkDevDel(CBlkDev *bd)
|
||||
{//Delete BlkDev
|
||||
DrvBlkDevDel(bd);
|
||||
FClose(bd->file_dsk);
|
||||
Free(bd->file_dsk_name);
|
||||
Free(bd->dev_id_record);
|
||||
MemSet(bd,0,sizeof(CBlkDev));
|
||||
}
|
||||
|
||||
CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE)
|
||||
{//Check for valid BlkDev. Throw exception.
|
||||
if (!bd || bd->bd_signature!=BD_SIGNATURE_VAL ||
|
||||
!(BDT_NULL<bd->type<BDT_TYPES_NUM)) {
|
||||
if (except)
|
||||
throw('BlkDev');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return bd;
|
||||
}
|
||||
|
||||
CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE)
|
||||
{//Drv letter to BlkDev ptr.
|
||||
CDrv *dv;
|
||||
if (dv=Let2Drv(drv_let,except))
|
||||
return BlkDevChk(dv->bd,except);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
//ISO1 is ISO9660
|
||||
//ISO2 is ISO13490
|
||||
//ISO3 is ISO13346
|
||||
|
||||
Bool ISOInit(CDrv *dv,I64 blk)
|
||||
{
|
||||
CBlkDev *bd=dv->bd;
|
||||
I64 spc=bd->blk_size>>BLK_SIZE_BITS,i=blk/spc,drv_offset=0;
|
||||
CISO1PriDesc *iso=MAlloc(bd->blk_size);
|
||||
CISO1DirEntry *de;
|
||||
Bool unlock,res=FALSE;
|
||||
U8 buf[8];
|
||||
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
dv->fs_type=FSt_ISO9660;
|
||||
dv->spc=spc;
|
||||
dv->data_area=dv->root_cluster=dv->drv_offset=bd->drv_offset=dv->size=0;
|
||||
while (TRUE) {
|
||||
dv->size=MaxI64(dv->size,(i+1)*spc);
|
||||
RBlks(dv,iso,i*spc,spc);
|
||||
buf[0](U32)=iso->id[0](U32);
|
||||
buf[4](U16)=iso->id[4](U8);
|
||||
switch (LstMatch(buf,"CD001\0CDW02\0BEA01\0BOOT2\0NSR02\0NSR03\0TEA01\0",
|
||||
LMF_EXACT)) {
|
||||
case 0:
|
||||
switch (iso->type) {
|
||||
case ISO1T_BOOT_RECORD:
|
||||
drv_offset+=(2*DVD_BLK_SIZE+DVD_BLK_SIZE)/BLK_SIZE;
|
||||
break;
|
||||
case ISO1T_SUPPLEMENTARY_DESC:
|
||||
de=&iso->root_dir_record;
|
||||
dv->size=iso->vol_space_size.little*bd->blk_size>>BLK_SIZE_BITS;
|
||||
if (!StrCmp(iso->publisher_id,"TempleOS RedSea")) {
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
bd->drv_offset=dv->drv_offset=19<<2+drv_offset;
|
||||
bd->max_blk=dv->size-1;
|
||||
dv->size-=bd->drv_offset;
|
||||
RedSeaInit(dv);
|
||||
} else
|
||||
dv->root_cluster=de->loc.little;
|
||||
res=TRUE;
|
||||
goto di_done;
|
||||
case ISO1T_TERMINATOR:
|
||||
throw('Drv');
|
||||
}
|
||||
break;
|
||||
default: //Its normal for ISO13346 to read NULL blk as terminator
|
||||
PrintErr("File System Not Supported\n");
|
||||
throw('Drv');
|
||||
}
|
||||
i++;
|
||||
}
|
||||
di_done:
|
||||
Free(iso);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch {
|
||||
dv->fs_type=FSt_ISO9660;
|
||||
dv->spc=spc;
|
||||
dv->drv_offset=bd->drv_offset=dv->data_area=dv->root_cluster=0;
|
||||
Free(iso);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 DVDImageRead(U8 dvd_drv_let,U8 *out_name)
|
||||
{//Read entire CD/DVD image into ISO file.
|
||||
CDrv *dv=Let2Drv(dvd_drv_let);
|
||||
CBlkDev *bd=dv->bd;
|
||||
U8 *buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS),
|
||||
*out_name2=DftExt(out_name,"ISO");
|
||||
CFile *f=FOpen(out_name2,"w");
|
||||
I64 n,spc=bd->blk_size>>BLK_SIZE_BITS,blk=0,cnt,retry;
|
||||
BlkDevInit(bd);
|
||||
if (bd->type!=BDT_ATAPI)
|
||||
throw('BlkDev');
|
||||
if (!out_name)
|
||||
out_name=blkdev.dft_iso_filename;
|
||||
cnt=CeilU64(dv->size,spc);
|
||||
while (cnt>0) {
|
||||
if (cnt>COPY_BUF_BLKS)
|
||||
n=COPY_BUF_BLKS;
|
||||
else
|
||||
n=cnt;
|
||||
if (n>bd->max_reads)
|
||||
n=bd->max_reads;
|
||||
|
||||
retry=4;
|
||||
while (--retry)
|
||||
if (ATAPIReadBlks2(bd,tS+7.0+0.004*n/spc,buf,blk/spc,n/spc,TRUE))
|
||||
//n is 0x800 if max_reads. Up to 8 additional seconds
|
||||
break;
|
||||
|
||||
if (!retry)
|
||||
ATAPIReadBlks2(bd,0,buf,blk/spc,n/spc,TRUE);
|
||||
|
||||
FWBlks(f,buf,blk,n);
|
||||
cnt-=n;
|
||||
blk+=n;
|
||||
}
|
||||
FClose(f);
|
||||
Free(buf);
|
||||
Free(out_name2);
|
||||
}
|
||||
|
||||
class CDualBuf
|
||||
{
|
||||
U8 *buf0,*buf1;
|
||||
I64 in_buf,out_buf,cnt;
|
||||
U8 *filename;
|
||||
CBlkDev *dvd_bd;
|
||||
};
|
||||
|
||||
U0 DVDImageWriteTask(CDualBuf *d)
|
||||
{
|
||||
U8 *buf;
|
||||
I64 n,blk=0,cnt=d->cnt;
|
||||
CFile *f;
|
||||
if (FileAttr(d->filename)&RS_ATTR_CONTIGUOUS)
|
||||
f=FOpen(d->filename,"rc");
|
||||
else
|
||||
f=FOpen(d->filename,"r");
|
||||
while (cnt>0) {
|
||||
if (cnt>COPY_BUF_BLKS)
|
||||
n=COPY_BUF_BLKS;
|
||||
else
|
||||
n=cnt;
|
||||
if (n>d->dvd_bd->max_writes)
|
||||
n=d->dvd_bd->max_writes;
|
||||
if (d->in_buf&1)
|
||||
buf=d->buf1;
|
||||
else
|
||||
buf=d->buf0;
|
||||
while (d->in_buf>d->out_buf+1)
|
||||
Yield;
|
||||
FRBlks(f,buf,blk,n);
|
||||
d->in_buf++;
|
||||
cnt-=n;
|
||||
blk+=n;
|
||||
}
|
||||
FClose(f);
|
||||
}
|
||||
|
||||
U0 DVDImageWrite(U8 dvd_drv_let,U8 *in_name=NULL,I64 media_type=MT_DVD)
|
||||
{//Write CD/DVD ISO file to disk.
|
||||
CDualBuf *d=CAlloc(sizeof(CDualBuf));
|
||||
U8 *buf,*in_name2,*in_name3;
|
||||
I64 i,n,spc,blk=0,cnt;
|
||||
CDrv *dv=Let2Drv(dvd_drv_let);
|
||||
CBlkDev *bd=dv->bd,*bd2;
|
||||
CTask *task;
|
||||
CFile *f;
|
||||
|
||||
if (!in_name)
|
||||
in_name=blkdev.dft_iso_filename;
|
||||
in_name3=DftExt(in_name,"ISO");
|
||||
in_name2=FileNameAbs(in_name3);
|
||||
f=FOpen(in_name2,"r");
|
||||
if (!f) {
|
||||
Free(d);
|
||||
return;
|
||||
}
|
||||
cnt=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
FClose(f);
|
||||
if (bd->type!=BDT_ATAPI)
|
||||
throw('BlkDev');
|
||||
bd2=Let2BlkDev(*in_name2);
|
||||
while (bd2->lock_fwding)
|
||||
bd2=bd2->lock_fwding; //If two blkdevs on same controller, use one lock
|
||||
if ((bd2->type==BDT_ATA || bd2->type==BDT_ATAPI) &&
|
||||
bd2->base0==bd->base0) {
|
||||
PrintErr("Can't burn CD/DVD on same ATA controller as file.\n\n");
|
||||
throw('BlkDev');
|
||||
}
|
||||
|
||||
bd->flags|=BDF_READ_ONLY_OVERRIDE;
|
||||
BlkDevInit(bd);
|
||||
spc=bd->blk_size>>BLK_SIZE_BITS;
|
||||
if (dv->size<cnt)
|
||||
dv->size=cnt;
|
||||
|
||||
d->filename=in_name2;
|
||||
d->dvd_bd=bd;
|
||||
d->buf0=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
|
||||
d->buf1=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
|
||||
d->cnt=cnt;
|
||||
|
||||
task=Spawn(&DVDImageWriteTask,d,"Write CD/DVD");
|
||||
while (d->in_buf<=d->out_buf)
|
||||
Yield;
|
||||
|
||||
BlkDevLock(bd);
|
||||
ATAPIWaitReady(bd,0);
|
||||
|
||||
progress1=0; progress1_max=cnt;
|
||||
StrCpy(progress1_desc,"Writing");
|
||||
while (cnt>0) {
|
||||
if (cnt>COPY_BUF_BLKS)
|
||||
n=COPY_BUF_BLKS;
|
||||
else
|
||||
n=cnt;
|
||||
if (n>bd->max_writes)
|
||||
n=bd->max_writes;
|
||||
if (d->out_buf&1)
|
||||
buf=d->buf1;
|
||||
else
|
||||
buf=d->buf0;
|
||||
while (d->in_buf<=d->out_buf)
|
||||
Yield;
|
||||
ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);
|
||||
d->out_buf++;
|
||||
cnt-=n;
|
||||
blk+=n;
|
||||
progress1+=n;
|
||||
}
|
||||
ATAPISync(bd);
|
||||
|
||||
progress1=0; progress1_max=2;
|
||||
StrCpy(progress1_desc,"Closing");
|
||||
for (i=0;i<2;i++) {
|
||||
ATAPIClose(bd,0x100,i); //Close tracks
|
||||
progress1++;
|
||||
}
|
||||
|
||||
ATAPISync(bd);
|
||||
|
||||
ATAPIClose(bd,0x200); //close disk
|
||||
ATAPISync(bd);
|
||||
if (media_type==MT_DVD) {
|
||||
ATAPIClose(bd,0x300);
|
||||
ATAPISync(bd);
|
||||
}
|
||||
|
||||
*progress1_desc=0;
|
||||
progress1=progress1_max=0;
|
||||
|
||||
bd->flags&=~BDF_READ_ONLY_OVERRIDE;
|
||||
BlkDevUnlock(bd);
|
||||
Free(d->buf0);
|
||||
Free(d->buf1);
|
||||
Free(in_name2);
|
||||
Free(in_name3);
|
||||
Free(d);
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
I64 FSize(CFile *f)
|
||||
{//Report size of opened file in bytes.
|
||||
if (f)
|
||||
return f->de.size;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0)
|
||||
{//Allows flags "r","w","w+". "c" for contiguous.
|
||||
//(It uses $LK,"StrOcc",A="MN:StrOcc"$() for 'w', 'r', '+', 'c')
|
||||
CFile *f=CAlloc(sizeof(CFile));
|
||||
CDirContext *dirc;
|
||||
U8 *full_name;
|
||||
Bool contiguous=StrOcc(flags,'c');
|
||||
|
||||
f->cluster=INVALID_CLUSTER;
|
||||
f->fblk_num=0;
|
||||
if (cnt>0)
|
||||
f->max_blk=cnt-1;
|
||||
else
|
||||
f->max_blk=I64_MAX;
|
||||
f->file_cluster_num=INVALID_CLUSTER;
|
||||
full_name=FileNameAbs(filename);
|
||||
f->dv=Let2Drv(*full_name);
|
||||
if (f->dv->fs_type==FSt_REDSEA)
|
||||
contiguous=TRUE;
|
||||
if (contiguous) {
|
||||
f->flags|=FF_CONTIGUOUS;
|
||||
if (f->dv->fs_type!=FSt_REDSEA &&
|
||||
!(FileAttr(filename) & RS_ATTR_CONTIGUOUS))
|
||||
throw('File');
|
||||
}
|
||||
f->cluster_buf=CAlloc(f->dv->spc<<BLK_SIZE_BITS);
|
||||
if (StrOcc(flags,'w')) {
|
||||
f->flags=f->flags|FF_WRITE|FF_NEEDS_WRITE;
|
||||
if (StrOcc(flags,'+')) {
|
||||
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
|
||||
Free(full_name);
|
||||
if (contiguous)
|
||||
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
|
||||
return f;
|
||||
}
|
||||
} else
|
||||
Del(full_name,,,FALSE);
|
||||
f->de.full_name=full_name;
|
||||
f->flags|=FF_NEW_FILE;
|
||||
if (dirc=DirContextNew(full_name)) {
|
||||
StrCpy(f->de.name,dirc->mask);
|
||||
if (cnt>0) {//We pre-alloc the whole thing.
|
||||
f->de.cluster=ClustersAlloc(f->dv,0,
|
||||
(cnt+f->dv->spc-1)/f->dv->spc,contiguous);
|
||||
f->de.size=cnt<<BLK_SIZE_BITS;
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
|
||||
f->flags&=~FF_NEW_FILE;
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
return f;
|
||||
}
|
||||
} else {
|
||||
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
|
||||
Free(full_name);
|
||||
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
Free(f->cluster_buf);
|
||||
Free(full_name);
|
||||
Free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 FClose(CFile *f)
|
||||
{//Close CFile, updating directory.
|
||||
CDirContext *dirc;
|
||||
if (f) {
|
||||
if (f->flags & FF_BUF_DIRTY) {
|
||||
WClusters(f->dv,f->cluster_buf,f->cluster,1);
|
||||
f->flags&=~FF_BUF_DIRTY;
|
||||
}
|
||||
if (f->flags & FF_NEEDS_WRITE) {
|
||||
if (dirc=DirContextNew(f->de.full_name)) {
|
||||
if (!(f->flags & FF_USE_OLD_DATETIME))
|
||||
f->de.datetime=Now;
|
||||
if (f->flags & FF_NEW_FILE)
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
|
||||
else
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,FALSE);
|
||||
DirContextDel(dirc);
|
||||
} else
|
||||
throw('File');
|
||||
}
|
||||
Free(f->cluster_buf);
|
||||
Free(f->de.full_name);
|
||||
Free(f);
|
||||
}
|
||||
}
|
||||
|
||||
I64 FSetCluster(CFile *f,I64 c,I64 blk,Bool read)
|
||||
{
|
||||
CDrv *dv=f->dv;
|
||||
I64 i;
|
||||
if (f->cluster!=c) {
|
||||
if (f->flags & FF_BUF_DIRTY) {
|
||||
i=dv->spc;
|
||||
if (f->max_blk!=I64_MAX) {
|
||||
i=f->max_blk+1-f->file_cluster_num*dv->spc;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
}
|
||||
WClustersBlks(dv,f->cluster_buf,f->cluster,i);
|
||||
f->flags=f->flags & ~FF_BUF_DIRTY;
|
||||
}
|
||||
f->cluster=c;
|
||||
f->file_cluster_num=blk/dv->spc;
|
||||
if (read) {
|
||||
i=dv->spc;
|
||||
if (f->max_blk!=I64_MAX) {
|
||||
i=f->max_blk+1-f->file_cluster_num*dv->spc;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
}
|
||||
c=RClustersBlks(dv,f->cluster_buf,c,i);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
|
||||
{//Read [nth,n+cnt) blks of file.
|
||||
CDrv *dv=f->dv;
|
||||
I64 spc=dv->spc,i,j,c=f->de.cluster;
|
||||
if (!f || !dv) return FALSE;
|
||||
if (blk==FFB_NEXT_BLK)
|
||||
blk=f->fblk_num;
|
||||
if (blk+cnt-1>f->max_blk)
|
||||
return FALSE;
|
||||
if (cnt<=0) return TRUE;
|
||||
|
||||
if (f->flags & FF_CONTIGUOUS) {
|
||||
RBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
|
||||
blk+=cnt;
|
||||
} else {
|
||||
i=blk/spc;
|
||||
if (0<=f->file_cluster_num<=i) {
|
||||
c=f->cluster;
|
||||
i-=f->file_cluster_num;
|
||||
}
|
||||
if (i>0)
|
||||
c=ClusterNumNext(dv,c,i);
|
||||
|
||||
if (i=blk%spc) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
if (cnt<spc-i)
|
||||
j=cnt;
|
||||
else
|
||||
j=spc-i;
|
||||
MemCpy(buf,f->cluster_buf+i<<BLK_SIZE_BITS,j<<BLK_SIZE_BITS);
|
||||
buf+=j<<BLK_SIZE_BITS;
|
||||
cnt-=j;
|
||||
blk+=j;
|
||||
}
|
||||
while (cnt>=spc) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(buf,f->cluster_buf,spc<<BLK_SIZE_BITS);
|
||||
buf+=spc<<BLK_SIZE_BITS;
|
||||
cnt-=spc;
|
||||
blk+=spc;
|
||||
}
|
||||
if (cnt>0) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(buf,f->cluster_buf,cnt<<BLK_SIZE_BITS);
|
||||
buf+=cnt<<BLK_SIZE_BITS;
|
||||
blk+=cnt;
|
||||
}
|
||||
}
|
||||
f->fblk_num=blk;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
|
||||
{//Write [nth,n+cnt) blks of file.
|
||||
CDrv *dv=f->dv;
|
||||
I64 spc=dv->spc,i,j,c=f->de.cluster,c1;
|
||||
if (!f || !dv) return FALSE;
|
||||
if (blk==FFB_NEXT_BLK)
|
||||
blk=f->fblk_num;
|
||||
if (blk+cnt-1>f->max_blk)
|
||||
return FALSE;
|
||||
if (!(f->flags & FF_WRITE))
|
||||
return FALSE;
|
||||
if (cnt<=0) return TRUE;
|
||||
if (f->flags & FF_CONTIGUOUS) {
|
||||
WBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
|
||||
blk+=cnt;
|
||||
} else {
|
||||
if (!c) {
|
||||
c=ClustersAlloc(dv,0,1,FALSE);
|
||||
f->file_cluster_num=0;
|
||||
f->cluster=c;
|
||||
f->de.cluster=c;
|
||||
f->flags|=FF_NEEDS_WRITE|FF_NEW_FILE;
|
||||
}
|
||||
i=blk/spc;
|
||||
if (0<=f->file_cluster_num<=i) {
|
||||
c=f->cluster;
|
||||
i-=f->file_cluster_num;
|
||||
}
|
||||
while (i>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER) {
|
||||
c=ClustersAlloc(dv,c1,i,FALSE);
|
||||
if (i>1)
|
||||
c=ClusterNumNext(dv,c,i-1);
|
||||
break;
|
||||
} else
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i=blk%spc) {
|
||||
FSetCluster(f,c,blk,TRUE);
|
||||
if (cnt<spc-i)
|
||||
j=cnt;
|
||||
else
|
||||
j=spc-i;
|
||||
MemCpy(f->cluster_buf+BLK_SIZE*i,buf,j<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=j<<BLK_SIZE_BITS;
|
||||
cnt-=j;
|
||||
blk+=j;
|
||||
if (cnt>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER)
|
||||
c=ClustersAlloc(dv,c1,1,FALSE);
|
||||
}
|
||||
}
|
||||
while (cnt>=spc) {
|
||||
FSetCluster(f,c,blk,FALSE);
|
||||
MemCpy(f->cluster_buf,buf,spc<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=spc<<BLK_SIZE_BITS;
|
||||
cnt-=spc;
|
||||
blk+=spc;
|
||||
if (cnt>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER)
|
||||
c=ClustersAlloc(dv,c1,1,FALSE);
|
||||
}
|
||||
}
|
||||
if (cnt>0) {
|
||||
FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(f->cluster_buf,buf,cnt<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=cnt<<BLK_SIZE_BITS;
|
||||
blk+=cnt;
|
||||
}
|
||||
if (f->de.size<blk<<BLK_SIZE_BITS)
|
||||
f->de.size=blk<<BLK_SIZE_BITS;
|
||||
}
|
||||
f->fblk_num=blk;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
U0 DskCacheInit(I64 size_in_U8s)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
I64 i,cnt;
|
||||
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
Free(blkdev.cache_ctrl);
|
||||
Free(blkdev.cache_base);
|
||||
Free(blkdev.cache_hash_table);
|
||||
if (size_in_U8s<0x2000) {
|
||||
blkdev.cache_ctrl=NULL;
|
||||
blkdev.cache_base=NULL;
|
||||
blkdev.cache_hash_table=NULL;
|
||||
} else {
|
||||
blkdev.cache_ctrl=ACAlloc(offset(CCacheBlk.body));
|
||||
blkdev.cache_base=AMAlloc(size_in_U8s);
|
||||
QueInit(blkdev.cache_ctrl);
|
||||
|
||||
cnt=MSize(blkdev.cache_base)/sizeof(CCacheBlk);
|
||||
blkdev.cache_size=cnt*BLK_SIZE;
|
||||
for (i=0;i<cnt;i++) {
|
||||
tmpc=blkdev.cache_base+i;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
tmpc->dv=NULL;
|
||||
tmpc->blk=0;
|
||||
}
|
||||
|
||||
blkdev.cache_hash_table=AMAlloc(DSK_CACHE_HASH_SIZE*sizeof(U8 *)*2);
|
||||
for (i=0;i<DSK_CACHE_HASH_SIZE;i++) {
|
||||
tmpc=blkdev.cache_hash_table(U8 *)+i*sizeof(U8 *)*2
|
||||
-offset(CCacheBlk.next_hash);
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
}
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
|
||||
I64 DskCacheHash(I64 blk)
|
||||
{
|
||||
I64 i=blk & (DSK_CACHE_HASH_SIZE-1);
|
||||
return blkdev.cache_hash_table(U8 *)+i<<4-offset(CCacheBlk.next_hash);
|
||||
}
|
||||
|
||||
U0 DskCacheQueRem(CCacheBlk *tmpc)
|
||||
{
|
||||
QueRem(tmpc);
|
||||
tmpc->next_hash->last_hash=tmpc->last_hash;
|
||||
tmpc->last_hash->next_hash=tmpc->next_hash;
|
||||
}
|
||||
|
||||
U0 DskCacheQueIns(CCacheBlk *tmpc)
|
||||
{
|
||||
CCacheBlk *tmp_n,*tmp_l;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
tmp_l=DskCacheHash(tmpc->blk);
|
||||
tmp_n=tmp_l->next_hash;
|
||||
tmpc->last_hash=tmp_l;
|
||||
tmpc->next_hash=tmp_n;
|
||||
tmp_l->next_hash=tmp_n->last_hash=tmpc;
|
||||
}
|
||||
|
||||
CCacheBlk *DskCacheFind(CDrv *dv,I64 blk)
|
||||
{
|
||||
CCacheBlk *tmpc,*tmpc1=DskCacheHash(blk);
|
||||
tmpc=tmpc1->next_hash;
|
||||
while (tmpc!=tmpc1) {
|
||||
if (tmpc->dv==dv && tmpc->blk==blk)
|
||||
return tmpc;
|
||||
tmpc=tmpc->next_hash;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 DskCacheAdd(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
while (cnt-->0) {
|
||||
if (!(tmpc=DskCacheFind(dv,blk)))
|
||||
tmpc=blkdev.cache_ctrl->next_lru;
|
||||
DskCacheQueRem(tmpc);
|
||||
MemCpy(&tmpc->body,buf,BLK_SIZE);
|
||||
tmpc->dv=dv;
|
||||
tmpc->blk=blk;
|
||||
DskCacheQueIns(tmpc);
|
||||
blk++;
|
||||
buf+=BLK_SIZE;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DskCacheInvalidate2(CDrv *dv)
|
||||
{
|
||||
CCacheBlk *tmpc,*tmpc1;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
tmpc=blkdev.cache_ctrl->last_lru;
|
||||
while (tmpc!=blkdev.cache_ctrl) {
|
||||
tmpc1=tmpc->last_lru;
|
||||
if (tmpc->dv==dv) {
|
||||
DskCacheQueRem(tmpc);
|
||||
tmpc->dv=NULL;
|
||||
tmpc->blk=0;
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
}
|
||||
tmpc=tmpc1;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
|
||||
U0 RCache(CDrv *dv,U8 **_buf, I64 *_blk, I64 *_cnt)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
//fetch leading blks from cache
|
||||
while (*_cnt>0) {
|
||||
if (tmpc=DskCacheFind(dv,*_blk)) {
|
||||
MemCpy(*_buf,&tmpc->body,BLK_SIZE);
|
||||
*_cnt-=1;
|
||||
*_buf+=BLK_SIZE;
|
||||
*_blk+=1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
//fetch trailing blks from cache
|
||||
while (*_cnt>0) {
|
||||
if (tmpc=DskCacheFind(dv,*_blk+*_cnt-1)) {
|
||||
MemCpy(*_buf+(*_cnt-1)<<BLK_SIZE_BITS,&tmpc->body,BLK_SIZE);
|
||||
*_cnt-=1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
I64 ClusterNumNext(CDrv *dv,I64 c,I64 cnt=1)
|
||||
{//Return next cnt'th cluster in chain.
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (cnt<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_ISO9660:
|
||||
case FSt_REDSEA:
|
||||
c+=cnt;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (cnt-->0 && 0<c<0x0FFFFFF8) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
c=dv->cur_fat_blk[c & (BLK_SIZE/4-1)];
|
||||
}
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
c=INVALID_CLUSTER;
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 Cluster2Blk(CDrv *dv,I64 c)
|
||||
{//Drv cluster num to blk num.
|
||||
DrvChk(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return c;
|
||||
case FSt_ISO9660:
|
||||
case FSt_FAT32:
|
||||
return dv->data_area+c*dv->spc;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
}
|
||||
|
||||
I64 RClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
|
||||
{//Accepts blk count, so padding on last cluster is not read.
|
||||
I64 i;
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (blks<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_ISO9660:
|
||||
RBlks(dv,buf,dv->data_area+c*dv->spc,blks);
|
||||
c+=(blks+dv->spc-1)/dv->spc;
|
||||
break;
|
||||
case FSt_REDSEA:
|
||||
RBlks(dv,buf,c,blks);
|
||||
c+=blks;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (blks && 0<c<0x0FFFFFF8) {
|
||||
i=blks;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
RBlks(dv,buf,dv->data_area+c*dv->spc,i);
|
||||
buf+=i<<BLK_SIZE_BITS;
|
||||
c=ClusterNumNext(dv,c,1);
|
||||
blks-=i;
|
||||
}
|
||||
if (blks)
|
||||
throw('Drv');
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 RClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
|
||||
{//Read cluster cnt from drv to buf.
|
||||
return RClustersBlks(dv,buf,c,cnt*dv->spc);
|
||||
}
|
||||
|
||||
I64 WClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
|
||||
{//Accepts blk count, so padding on last cluster is not written.
|
||||
I64 i;
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (blks<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
WBlks(dv,buf,c,blks);
|
||||
c=0;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (blks) {
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
throw('Drv');
|
||||
i=blks;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
WBlks(dv,buf,dv->data_area+c*dv->spc,i);
|
||||
buf+=i<<BLK_SIZE_BITS;
|
||||
c=ClusterNumNext(dv,c);
|
||||
blks-=i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 WClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
|
||||
{//Write cluster cnt from buf to drv.
|
||||
return WClustersBlks(dv,buf,c,cnt*dv->spc);
|
||||
}
|
||||
|
||||
I64 ClustersAlloc(CDrv *dv,I64 c=0,I64 cnt=1,Bool contiguous=FALSE)
|
||||
{//Alloc cluster cnt into chain.
|
||||
//c=0 means first cluster in chain
|
||||
DrvChk(dv);
|
||||
if (cnt<=0) return c;
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return RedSeaAllocClusters(dv,cnt);
|
||||
case FSt_FAT32:
|
||||
if (contiguous) {
|
||||
if (c) throw('File');
|
||||
return FAT32AllocContiguousClusters(dv,cnt);
|
||||
} else
|
||||
return FAT32AllocClusters(dv,c,cnt);
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
Bool CopySingleZ(U8 *f1,U8 *f2) //Just one file
|
||||
{
|
||||
U8 *file_buf=NULL;
|
||||
I64 size,attr=0,c;
|
||||
CDirEntry de;
|
||||
if (FileFind(f1,&de,FUF_JUST_FILES)) {
|
||||
Free(de.full_name);
|
||||
file_buf=FileRead(f1,&size,&attr);
|
||||
attr=FileAttr(f2,attr);
|
||||
if (file_buf) {
|
||||
"Copying %s to %s\n",f1,f2;
|
||||
c=FileWrite(f2,file_buf,size,de.datetime,attr);
|
||||
Free(file_buf);
|
||||
return ToBool(c);
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define COPY_BUF_BLKS 0x80
|
||||
Bool CopySingle(U8 *f1,U8 *f2) //Just one file
|
||||
{
|
||||
U8 *absf1=FileNameAbs(f1),*absf2=FileNameAbs(f2),*buf;
|
||||
I64 cnt,n,size,attr1=FileAttr(f1),attr2=FileAttr(f2),i,j;
|
||||
CFile *in_file=NULL,*out_file=NULL;
|
||||
if (!StrCmp(absf1,absf2)) {//onto self?
|
||||
Free(absf1);
|
||||
Free(absf2);
|
||||
return FALSE;
|
||||
}
|
||||
Free(absf1);
|
||||
Free(absf2);
|
||||
if (attr1!=attr2)
|
||||
return CopySingleZ(f1,f2);
|
||||
buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
|
||||
if (attr1 & RS_ATTR_CONTIGUOUS)
|
||||
in_file=FOpen(f1,"rc");
|
||||
else
|
||||
in_file=FOpen(f1,"r");
|
||||
if (in_file) {
|
||||
size=FSize(in_file);
|
||||
cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
if (attr2 & RS_ATTR_CONTIGUOUS)
|
||||
out_file=FOpen(f2,"wc",cnt);
|
||||
else
|
||||
out_file=FOpen(f2,"w",cnt);
|
||||
if (out_file) {
|
||||
"Copying %s to %s\n",f1,f2;
|
||||
j=size;
|
||||
while (cnt>0) {
|
||||
if (cnt>COPY_BUF_BLKS) {
|
||||
n=COPY_BUF_BLKS;
|
||||
i=n<<BLK_SIZE_BITS;
|
||||
} else {
|
||||
n=cnt;
|
||||
i=j;
|
||||
}
|
||||
FRBlks(in_file, buf,FFB_NEXT_BLK,n);
|
||||
FWBlks(out_file,buf,FFB_NEXT_BLK,n);
|
||||
cnt-=n;
|
||||
j-=n<<BLK_SIZE_BITS;
|
||||
}
|
||||
out_file->flags|=FF_USE_OLD_DATETIME;
|
||||
out_file->de.datetime=in_file->de.datetime;
|
||||
out_file->de.size=size;
|
||||
out_file->de.attr=FileAttr(f2,in_file->de.attr);
|
||||
FClose(out_file);
|
||||
FClose(in_file);
|
||||
Free(buf);
|
||||
return TRUE;
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
FClose(in_file);
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
Free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
|
||||
Bool del_dir=FALSE,Bool print_msg=TRUE)
|
||||
{//Delete files.
|
||||
I64 res=0;
|
||||
CDirContext *dirc;
|
||||
if (dirc=DirContextNew(files_find_mask,make_mask)) {
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
|
||||
0,del_dir,print_msg);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
|
||||
0,del_dir,print_msg);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
Bool DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain=TRUE)
|
||||
{//Makes a directory entry in the directory from a $LK,"CDirEntry",A="MN:CDirEntry"$ node.
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return RedSeaDirNew(dv,cur_dir,tmpde,free_old_chain);
|
||||
case FSt_FAT32:
|
||||
return FAT32DirNew(dv,cur_dir,tmpde,free_old_chain);
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
return FALSE;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirEntryDel(CDirEntry *tmpde)
|
||||
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
|
||||
//Does not change the directory on disk.
|
||||
if (tmpde) {
|
||||
Free(tmpde->full_name);
|
||||
Free(tmpde);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirEntryDel2(CDirEntry *tmpde)
|
||||
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
|
||||
//Does not change the directory on disk.
|
||||
if (tmpde) {
|
||||
Free(tmpde->full_name);
|
||||
Free(tmpde->user_data);
|
||||
Free(tmpde);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirTreeDel(CDirEntry *tmpde)
|
||||
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
|
||||
//Does not change the directory on disk.
|
||||
CDirEntry *tmpde2;
|
||||
while (tmpde) {
|
||||
tmpde2=tmpde->next;
|
||||
if (tmpde->sub)
|
||||
DirTreeDel(tmpde->sub);
|
||||
DirEntryDel(tmpde);
|
||||
tmpde=tmpde2;
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirTreeDel2(CDirEntry *tmpde)
|
||||
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
|
||||
//Does not change the directory on disk.
|
||||
CDirEntry *tmpde2;
|
||||
while (tmpde) {
|
||||
tmpde2=tmpde->next;
|
||||
if (tmpde->sub)
|
||||
DirTreeDel2(tmpde->sub);
|
||||
DirEntryDel2(tmpde);
|
||||
tmpde=tmpde2;
|
||||
}
|
||||
}
|
||||
|
||||
I64 DirEntryCompareName(CDirEntry *e1,CDirEntry *e2)
|
||||
{
|
||||
U8 buf1[CDIR_FILENAME_LEN],buf2[CDIR_FILENAME_LEN],
|
||||
buf3[CDIR_FILENAME_LEN],buf4[CDIR_FILENAME_LEN];
|
||||
I64 d1=0,d2=0;
|
||||
if (e1->attr & RS_ATTR_DIR)
|
||||
d1=1;
|
||||
if (e2->attr & RS_ATTR_DIR)
|
||||
d2=1;
|
||||
if (d1!=d2)
|
||||
return d2-d1;
|
||||
else {
|
||||
StrCpy(buf1,e1->name);
|
||||
StrCpy(buf2,e2->name);
|
||||
FileExtRem(buf1,buf3);
|
||||
FileExtRem(buf2,buf4);
|
||||
if (d1=StrCmp(buf3,buf4))
|
||||
return d1;
|
||||
return StrCmp(buf1,buf2);
|
||||
}
|
||||
}
|
||||
|
||||
I64 DirEntryCompareCluster(CDirEntry *e1,CDirEntry *e2)
|
||||
{
|
||||
return e1->cluster-e2->cluster;
|
||||
}
|
||||
|
||||
#define SK_NAME 0
|
||||
#define SK_CLUSTER 1
|
||||
|
||||
U0 DirFilesSort(CDirEntry **_tmpde,I64 key)
|
||||
{
|
||||
I64 i,cnt;
|
||||
CDirEntry *tmpde=*_tmpde,*tmpde1,**sort_buf;
|
||||
if (tmpde) {
|
||||
cnt=LinkedLstCnt(tmpde);
|
||||
if (cnt>1) {
|
||||
sort_buf=MAlloc(cnt*sizeof(U8 *));
|
||||
i=0;
|
||||
tmpde1=tmpde;
|
||||
while (tmpde1) {
|
||||
sort_buf[i++]=tmpde1;
|
||||
tmpde1=tmpde1->next;
|
||||
}
|
||||
switch [key] {
|
||||
case SK_NAME:
|
||||
QSortI64(sort_buf,cnt,&DirEntryCompareName);
|
||||
break;
|
||||
case SK_CLUSTER:
|
||||
QSortI64(sort_buf,cnt,&DirEntryCompareCluster);
|
||||
break;
|
||||
}
|
||||
tmpde=sort_buf[0];
|
||||
*_tmpde=tmpde;
|
||||
for (i=0;i<cnt-1;i++) {
|
||||
tmpde1=sort_buf[i];
|
||||
tmpde1->next=sort_buf[i+1];
|
||||
}
|
||||
tmpde1=sort_buf[i];
|
||||
tmpde1->next=NULL;
|
||||
Free(sort_buf);
|
||||
|
||||
tmpde1=tmpde;
|
||||
while (tmpde1) {
|
||||
if (tmpde1->sub)
|
||||
DirFilesSort(&tmpde1->sub,key);
|
||||
tmpde1=tmpde1->next;
|
||||
}
|
||||
} else
|
||||
if (tmpde->sub)
|
||||
DirFilesSort(&tmpde->sub,key);
|
||||
}
|
||||
}
|
||||
|
||||
CDirEntry *DirFilesFlatten(CDirEntry *tmpde,CDirEntry **_res,I64 fuf_flags)
|
||||
{//Returns last node
|
||||
CDirEntry *tmpde1;
|
||||
Bool del;
|
||||
if (tmpde)
|
||||
while (TRUE) {
|
||||
tmpde1=tmpde->next;
|
||||
if (!(tmpde->attr&RS_ATTR_DIR)||!(fuf_flags&FUF_JUST_FILES)) {
|
||||
_res=*_res=tmpde;
|
||||
del=FALSE;
|
||||
} else
|
||||
del=TRUE;
|
||||
if (tmpde->sub) {
|
||||
_res=DirFilesFlatten(tmpde->sub,_res,fuf_flags);
|
||||
tmpde->sub=NULL;
|
||||
}
|
||||
if (del)
|
||||
DirEntryDel(tmpde);
|
||||
if (tmpde1)
|
||||
tmpde=tmpde1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*_res=NULL;
|
||||
return _res;
|
||||
}
|
||||
|
||||
U0 PutFileLink(U8 *filename,U8 *full_name=NULL,I64 line=0,Bool plain_text=FALSE)
|
||||
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ file,line link to StdOut, $LK,"DocPut",A="MN:DocPut"$.
|
||||
U8 *st;
|
||||
if (!filename) return;
|
||||
if (IsRaw) {
|
||||
if (line)
|
||||
"%s,%04d",filename,line;
|
||||
else
|
||||
"%s",filename;
|
||||
} else {
|
||||
//LK_DOC,LK_DOC_ANCHOR,LK_DOC_FIND,LK_DOC_LINE
|
||||
if (filename[0]=='A'&&filename[2]==':') {
|
||||
if (line) //See $LK,"SpriteEdText",A="MN:SpriteEdText"$()
|
||||
"$$LK,\"%s,%04d\",A=\"AL:%s,%d\"$$",filename+3,line,filename+3,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"AI:%s\"$$",filename+3,filename+3;
|
||||
} else {
|
||||
if (!full_name)
|
||||
full_name=st=FileNameAbs(filename);
|
||||
else
|
||||
st=NULL;
|
||||
if (plain_text) {
|
||||
if (line)
|
||||
"$$LK,\"%s,%04d\",A=\"PL:%s,%d\"$$",filename,line,full_name,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"PI:%s\"$$",filename,full_name;
|
||||
} else {
|
||||
if (line)
|
||||
"$$LK,\"%s,%04d\",A=\"FL:%s,%d\"$$",filename,line,full_name,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"FI:%s\"$$",filename,full_name;
|
||||
}
|
||||
Free(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 PutDirLink(U8 *dirname,U8 *full_name=NULL)
|
||||
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ dir macro to StdOut, $LK,"DocPut",A="MN:DocPut"$.
|
||||
U8 *st;
|
||||
if (!dirname) return;
|
||||
if (IsRaw)
|
||||
"%s",dirname;
|
||||
else {
|
||||
if (!full_name)
|
||||
full_name=st=DirNameAbs(dirname);
|
||||
else
|
||||
st=NULL;
|
||||
"$$MA,T=\"%s\",LM=\"Cd(\\\"%s\\\");Dir;\n\"$$",dirname,full_name;
|
||||
Free(st);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
U0 HomeSet(U8 *dirname)
|
||||
{//Change home directory.
|
||||
dirname=DirNameAbs(dirname);
|
||||
Free(blkdev.home_dir);
|
||||
blkdev.home_dir=AStrNew(dirname);
|
||||
Free(dirname);
|
||||
}
|
||||
|
||||
Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE)
|
||||
{//Change directory. Optionally, make directories, too.
|
||||
I64 maxlen,cur_dir_cluster=0;
|
||||
U8 *chg_to_buf,*new_cur_dir,*buf;
|
||||
CDrv *dv;
|
||||
Bool res=TRUE;
|
||||
if (!dirname)
|
||||
dirname="~";
|
||||
else if (!*dirname)
|
||||
return TRUE;
|
||||
if (dirname[1]==':') {
|
||||
if (*dirname==':') {
|
||||
if (Fs->cur_dv!=Let2Drv(':') && !Drv(*dirname))
|
||||
return FALSE;
|
||||
} else if (Fs->cur_dv!=Let2Drv(*dirname) && !Drv(*dirname))
|
||||
return FALSE;
|
||||
dirname+=2;
|
||||
}
|
||||
if (*dirname=='/' || !*dirname || !Fs->cur_dir) {
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
if (*dirname=='/')
|
||||
dirname++;
|
||||
}
|
||||
chg_to_buf=MStrUtil(dirname,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
maxlen=StrLen(Fs->cur_dir)+1+StrLen(chg_to_buf)+1;
|
||||
new_cur_dir=MAlloc(maxlen);
|
||||
buf=MAlloc(maxlen);
|
||||
StrCpy(new_cur_dir,Fs->cur_dir);
|
||||
while (*chg_to_buf && res) {
|
||||
StrFirstRem(chg_to_buf,"/",buf);
|
||||
if (!*buf)
|
||||
StrCpy(new_cur_dir,"/");
|
||||
else if (!StrCmp(buf,"..")) {
|
||||
StrLastRem(new_cur_dir,"/");
|
||||
if (!*new_cur_dir)
|
||||
StrCpy(new_cur_dir,"/");
|
||||
} else if (!StrCmp(buf,"~")) {
|
||||
Free(new_cur_dir);
|
||||
new_cur_dir=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(chg_to_buf)+1);
|
||||
StrCpy(new_cur_dir,blkdev.home_dir+2);
|
||||
if (Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
|
||||
return FALSE;
|
||||
} else if (StrCmp(buf,".") && *buf) {
|
||||
dv=Fs->cur_dv;
|
||||
cur_dir_cluster=Name2DirCluster(dv,new_cur_dir);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaCd(buf,cur_dir_cluster);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32Cd(buf,cur_dir_cluster);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1Cd(buf,cur_dir_cluster);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
res=FALSE;
|
||||
}
|
||||
if (!res && make_dirs) {
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew(new_cur_dir);
|
||||
res=MkDir(buf);
|
||||
}
|
||||
if (res) {
|
||||
if (StrCmp(new_cur_dir,"/"))
|
||||
CatPrint(new_cur_dir,"/");
|
||||
CatPrint(new_cur_dir,buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew(new_cur_dir);
|
||||
Free(buf);
|
||||
Free(chg_to_buf);
|
||||
Free(new_cur_dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool IsDir(U8 *dir_name)
|
||||
{//Is a str a valid, existing Dir?
|
||||
U8 *mask=MStrPrint("%s/*",dir_name);
|
||||
Bool res,old_silent=Silent;
|
||||
CDirContext *dirc;
|
||||
if (dirc=DirContextNew(mask)) {
|
||||
DirContextDel(dirc);
|
||||
res=TRUE;
|
||||
} else
|
||||
res=FALSE;
|
||||
Free(mask);
|
||||
Silent(old_silent);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 Dir(U8 *files_find_mask,Bool full)
|
||||
{//List directory.
|
||||
CDirEntry *tmpde1=NULL,*tmpde2;
|
||||
U8 *st;
|
||||
CDateStruct ds;
|
||||
I64 csize=0xFFFF,c=0xFFFF,res=0;
|
||||
tmpde1=FilesFind(files_find_mask);
|
||||
if (!(st=CurDir))
|
||||
PrintErr("Invalid Drive\n");
|
||||
else {
|
||||
if (tmpde1) {
|
||||
Free(st);
|
||||
st=MAllocIdent(tmpde1->full_name);
|
||||
StrLastRem(st,"/");
|
||||
if (!st[2])
|
||||
StrCpy(st+2,"/");
|
||||
//Find max columns
|
||||
tmpde2=tmpde1;
|
||||
while (tmpde2) {
|
||||
if (tmpde2->size>csize)
|
||||
csize=tmpde2->size;
|
||||
if (tmpde2->cluster>c)
|
||||
c=tmpde2->cluster;
|
||||
tmpde2=tmpde2->next;
|
||||
}
|
||||
csize=Bsr(csize)/4+1;
|
||||
c=Bsr(c)/4+1;
|
||||
|
||||
"$$MA,T=\"Directory\",LM=\"PopUpCd;Dir;\n\"$$ of %s\n",st;
|
||||
if (full)
|
||||
"__DATE__ __TIME__ %*ts %*ts\n",
|
||||
csize,"SIZE",c,"CLUSTER";
|
||||
else
|
||||
"DATE_ TIME_ %*ts\n",csize,"SIZE";
|
||||
while (tmpde1) {
|
||||
tmpde2=tmpde1->next;
|
||||
res++;
|
||||
if (full)
|
||||
"%D %T %0*tX %0*tX ",tmpde1->datetime,tmpde1->datetime,
|
||||
csize,tmpde1->size,c,tmpde1->cluster;
|
||||
else {
|
||||
Date2Struct(&ds,tmpde1->datetime+local_time_offset);
|
||||
"%02d/%02d %02d:%02d %0*tX ",ds.mon,ds.day_of_mon,ds.hour,ds.min,
|
||||
csize,tmpde1->size;
|
||||
}
|
||||
if (tmpde1->attr & RS_ATTR_DIR)
|
||||
PutDirLink(tmpde1->name,tmpde1->full_name);
|
||||
else
|
||||
PutFileLink(tmpde1->name,tmpde1->full_name);
|
||||
'\n';
|
||||
DirEntryDel(tmpde1);
|
||||
tmpde1=tmpde2;
|
||||
}
|
||||
} else
|
||||
"No matching entries\n";
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool MkDir(U8 *filename,I64 entry_cnt=0)
|
||||
{//Make directory. $LK,"Cd",A="MN:Cd"$() can also make directories.
|
||||
//entry_cnt is for preallocating dir blks, leave it zero if you like.
|
||||
U8 *name;
|
||||
CDirContext *dirc;
|
||||
Bool res=FALSE;
|
||||
if (FileFind(filename,,FUF_JUST_DIRS))
|
||||
return FALSE;
|
||||
if (dirc=DirContextNew(filename)) {
|
||||
if (*dirc->mask) {
|
||||
if (!FileNameChk(dirc->mask))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
"Make Directory:%s\n",filename;
|
||||
name=MStrUtil(dirc->mask,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaMkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32MkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
Free(name);
|
||||
}
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
U0 DirContextDel(CDirContext *dirc,Bool restore=TRUE)
|
||||
{//Change back to old cur_dir and drv.
|
||||
CBlkDev *bd;
|
||||
if (!dirc) return;
|
||||
if (restore) {
|
||||
bd=dirc->old_dv->bd;
|
||||
if (!(bd->flags & BDF_INIT_IN_PROGRESS)) {
|
||||
if (dirc->old_dir) {
|
||||
Drv(Drv2Let(dirc->old_dv));
|
||||
Cd(dirc->old_dir);
|
||||
}
|
||||
} else {
|
||||
Fs->cur_dv=dirc->old_dv;
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
}
|
||||
}
|
||||
Free(dirc->old_dir);
|
||||
Free(dirc->mask);
|
||||
Free(dirc);
|
||||
}
|
||||
|
||||
CDirContext *DirContextNew(U8 *_mask,Bool make_mask=FALSE,
|
||||
Bool make_dirs=FALSE,Bool no_mask=FALSE)
|
||||
{//Save cur_dir and drv. Change to new dir.
|
||||
Bool valid=TRUE,old_silent;
|
||||
I64 mask_len=StrLen(_mask);
|
||||
U8 *buf,*mask,*tmp_mask,*semicolon_mask;
|
||||
CDirContext *dirc=CAlloc(sizeof(CDirContext));
|
||||
dirc->old_dir=StrNew(Fs->cur_dir);
|
||||
dirc->old_dv=Fs->cur_dv;
|
||||
mask=MStrUtil(_mask,SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
tmp_mask=mask;
|
||||
if (*mask && mask[1]==':') {
|
||||
if (Fs->cur_dv!=Let2Drv(*mask) && !Drv(*mask))
|
||||
valid=FALSE;
|
||||
mask+=2;
|
||||
}
|
||||
if (*mask=='~' && Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
|
||||
valid=FALSE;
|
||||
dirc->dv=Fs->cur_dv;
|
||||
DrvChk(dirc->dv);
|
||||
buf=MAlloc(mask_len+2);
|
||||
StrCpy(buf,mask);
|
||||
|
||||
dirc->mask=MAlloc(mask_len+2);
|
||||
if (no_mask)
|
||||
*dirc->mask=0;
|
||||
else if (StrOcc(buf,';')) {
|
||||
semicolon_mask=MAlloc(mask_len+2);
|
||||
StrCpy(semicolon_mask,mask);
|
||||
StrFirstRem(semicolon_mask,";",buf);
|
||||
StrLastRem(buf,"/",dirc->mask);
|
||||
CatPrint(dirc->mask,";%s",semicolon_mask);
|
||||
Free(semicolon_mask);
|
||||
} else
|
||||
StrLastRem(buf,"/",dirc->mask);
|
||||
|
||||
if (*mask=='/' && !*buf)
|
||||
StrCpy(buf,"/");
|
||||
//If began with Dir, change to Dir.
|
||||
if (*buf && !Cd(buf,make_dirs))
|
||||
valid=FALSE;
|
||||
if (valid && make_mask) {
|
||||
if (!*dirc->mask) {
|
||||
Free(dirc->mask);
|
||||
dirc->mask=StrNew("*");
|
||||
} else {
|
||||
if (!make_dirs || FileNameChk(dirc->mask)) {
|
||||
old_silent=Silent;
|
||||
//Try mask to see if Dir. If Dir, change to dir and set to "*".
|
||||
if (Cd(dirc->mask,make_dirs)) {
|
||||
Free(dirc->mask);
|
||||
dirc->mask=StrNew("*");
|
||||
}
|
||||
Silent(old_silent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
Free(tmp_mask);
|
||||
if (!valid) {
|
||||
DirContextDel(dirc);
|
||||
dirc=NULL;
|
||||
}
|
||||
return dirc;
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
Bool DrvLock(CDrv *dv)
|
||||
{//Make this task have exclusive access to drv & BlkDev.
|
||||
DrvChk(dv);
|
||||
BlkDevLock(dv->bd);
|
||||
if (!Bt(&dv->locked_flags,DVlf_LOCKED) || dv->owning_task!=Fs) {
|
||||
while (LBts(&dv->locked_flags,DVlf_LOCKED))
|
||||
Yield;
|
||||
dv->owning_task=Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool DrvUnlock(CDrv *dv,Bool rst=FALSE)
|
||||
{//Release exclusive lock on access to drv & BlkDev.
|
||||
DrvChk(dv);
|
||||
if (Bt(&dv->locked_flags,DVlf_LOCKED) && dv->owning_task==Fs) {
|
||||
BlkDevUnlock(dv->bd,rst);
|
||||
dv->owning_task=NULL;
|
||||
LBtr(&dv->locked_flags,DVlf_LOCKED);
|
||||
Yield; //Prevent deadlock
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 DrvsRelease()
|
||||
{//When task dies, release all owned drvs.
|
||||
I64 i;
|
||||
CDrv *dv;
|
||||
for (i=0;i<DRVS_NUM;i++) {
|
||||
dv=&blkdev.drvs[i];
|
||||
if (dv->owning_task==Fs && dv->dv_signature==DRV_SIGNATURE_VAL)
|
||||
DrvUnlock(dv,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
CDrv *DrvMakeFreeSlot(U8 drv_let)
|
||||
{//Make a slot free for a new drv, like during $LK,"Mount",A="MN:Mount"$().
|
||||
//!!! drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
|
||||
I64 i=Let2Let(drv_let)-'A';
|
||||
CDrv *res;
|
||||
if (!(0<=i<DRVS_NUM))
|
||||
throw('Drv');
|
||||
res=&blkdev.drvs[i];
|
||||
MemSet(res,0,sizeof(CDrv));
|
||||
res->drv_let='A'+i;
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 DrvNextFreeLet(U8 first_drv_let='C')
|
||||
{//Locate free slot for new drv, like during $LK,"Mount",A="MN:Mount"$().
|
||||
//!!! first_drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
|
||||
I64 i=Let2Let(first_drv_let)-'A',type=Let2BlkDevType(first_drv_let);
|
||||
if (!(0<=i<DRVS_NUM))
|
||||
throw('Drv');
|
||||
do
|
||||
if (blkdev.drvs[i].dv_signature!=DRV_SIGNATURE_VAL) {
|
||||
if (Let2BlkDevType(i+'A')!=type)
|
||||
throw('Drv');
|
||||
else
|
||||
return i+'A';
|
||||
}
|
||||
while (++i<DRVS_NUM);
|
||||
throw('Drv');
|
||||
return 0; //Never gets here.
|
||||
}
|
||||
|
||||
U0 DrvDel(CDrv *dv)
|
||||
{//Delete drv
|
||||
if (dv->fs_type==FSt_REDSEA && dv->next_free)
|
||||
RedSeaFreeFreeLst(dv);
|
||||
Free(dv->cur_fat_blk);
|
||||
Free(dv->fis);
|
||||
MemSet(dv,0,sizeof(CDrv));
|
||||
}
|
||||
|
||||
U0 DrvBlkDevDel(CBlkDev *bd)
|
||||
{//Delete drv's of BlkDev
|
||||
I64 i;
|
||||
CDrv *dv;
|
||||
for (i=0;i<DRVS_NUM;i++) {
|
||||
dv=&blkdev.drvs[i];
|
||||
if (dv->bd==bd)
|
||||
DrvDel(dv);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DrvFATBlkAlloc(CDrv *dv)
|
||||
{
|
||||
DrvChk(dv);
|
||||
Free(dv->cur_fat_blk);
|
||||
dv->cur_fat_blk=AMAlloc(BLK_SIZE);
|
||||
dv->cur_fat_blk_num=0;
|
||||
dv->fat_blk_dirty=0;
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat1,1);
|
||||
}
|
||||
|
||||
U0 DrvFATBlkClean(CDrv *dv,I64 fat_sel=3)
|
||||
{
|
||||
if ((dv->fs_type==FSt_FAT32 || dv->fs_type==FSt_REDSEA) &&
|
||||
Bt(&dv->fat_blk_dirty,0)) {
|
||||
if (dv->fat1==dv->fat2) {
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
LBtr(&dv->fat_blk_dirty,0);
|
||||
} else {
|
||||
if (fat_sel==3 || !fat_sel)
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
if (fat_sel==3 || fat_sel==1) {
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
|
||||
LBtr(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 DrvFATBlkSet(CDrv *dv,I64 c,I64 fat_sel=3)
|
||||
{
|
||||
I64 fat_blk_num;
|
||||
if (c==INVALID_CLUSTER)
|
||||
throw('Drv');
|
||||
switch (dv->fs_type) {
|
||||
case FSt_FAT32:
|
||||
fat_blk_num=c>>(BLK_SIZE_BITS-2);
|
||||
break;
|
||||
case FSt_REDSEA:
|
||||
fat_blk_num=(c-dv->data_area)>>(BLK_SIZE_BITS+3);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (fat_blk_num!=dv->cur_fat_blk_num) {
|
||||
DrvFATBlkClean(dv,fat_sel);
|
||||
dv->cur_fat_blk_num=fat_blk_num;
|
||||
if (fat_sel==3 || !fat_sel)
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
else
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
|
||||
}
|
||||
}
|
||||
|
||||
CDrv *DrvChk(CDrv *dv,Bool except=TRUE)
|
||||
{//Check for valid drv. Throw exception.
|
||||
if (!dv || dv->dv_signature!=DRV_SIGNATURE_VAL) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return dv;
|
||||
}
|
||||
|
||||
U8 Drv2Let(CDrv *dv=NULL)
|
||||
{//Drv ptr to Drv letter.
|
||||
if (!dv)
|
||||
dv=Fs->cur_dv;
|
||||
DrvChk(dv);
|
||||
return dv->drv_let;
|
||||
}
|
||||
|
||||
U8 Let2Let(U8 drv_let=0)
|
||||
{//Drv letter to Drv letter.
|
||||
if (!drv_let)
|
||||
drv_let=Drv2Let(Fs->cur_dv);
|
||||
else if (drv_let==':')
|
||||
drv_let=blkdev.boot_drv_let;
|
||||
else if (drv_let=='~')
|
||||
drv_let=*blkdev.home_dir;
|
||||
return ToUpper(drv_let);
|
||||
}
|
||||
|
||||
I64 Let2BlkDevType(U8 drv_let)
|
||||
{//Drv letter to BlkDev Type. drv_let=0 not allowed. See $LK,"BDT_NULL",A="MN:BDT_NULL"$.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='B')
|
||||
return BDT_RAM;
|
||||
if ('C'<=drv_let<='L')
|
||||
return BDT_ATA;
|
||||
if ('M'<=drv_let<='P')
|
||||
return BDT_ISO_FILE_READ;
|
||||
if ('Q'<=drv_let<='S')
|
||||
return BDT_ISO_FILE_WRITE;
|
||||
if ('T'<=drv_let<='Z')
|
||||
return BDT_ATAPI;
|
||||
return BDT_NULL;
|
||||
}
|
||||
|
||||
CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE)
|
||||
{//Drv letter to Drv ptr.
|
||||
CDrv *dv;
|
||||
if (!drv_let)
|
||||
dv=Fs->cur_dv;
|
||||
else {
|
||||
drv_let=Let2Let(drv_let);
|
||||
if (!('A'<=drv_let<='Z')) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
dv=blkdev.let_to_drv[drv_let-'A'];
|
||||
}
|
||||
return DrvChk(dv,except);
|
||||
}
|
||||
|
||||
CBlkDev *DrvIsWritable(U8 drv_let=0,Bool except=FALSE)
|
||||
{//Is drive writable?
|
||||
CBlkDev *bd;
|
||||
if (!(bd=Let2BlkDev(drv_let,except)) || bd->flags & BDF_READ_ONLY) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return bd;
|
||||
}
|
||||
|
||||
U0 DskCacheInvalidate(CDrv *dv)
|
||||
{//Needed for removable media. Called by $LK,"ChgDsk",A="MN:ChgDsk"$().
|
||||
Bool unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheInvalidate2(dv);
|
||||
if (bd->type==BDT_ATAPI && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
|
||||
ISOInit(dv,(32767/bd->blk_size+1)*bd->blk_size>>BLK_SIZE_BITS);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 ChgDsk(U8 drv_let=0)
|
||||
{//Change disk. (Needed for removable media.)
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (!(bd->flags&BDF_INITIALIZED))
|
||||
BlkDevInit(bd);
|
||||
else if (bd->flags&BDF_REMOVABLE) {
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAInit(bd); //TODO: This is a kludge for QEMU?
|
||||
DskCacheInvalidate(dv);
|
||||
}
|
||||
Drv(drv_let);
|
||||
RedSeaFreeFreeLst(dv);
|
||||
}
|
||||
|
||||
Bool DrvMap(U8 drv_let,CDrv *dv)
|
||||
{//Make drive letter map to another.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='Z') {
|
||||
blkdev.let_to_drv[drv_let-'A']=dv;
|
||||
dv->drv_let=drv_let;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool Drv(U8 drv_let)
|
||||
{//Change drive. You can set drive with $LK,"Cd",A="MN:Cd"$() as well.
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
CBlkDev *bd;
|
||||
bd=BlkDevChk(dv->bd);
|
||||
if (dv!=Fs->cur_dv) {
|
||||
if (bd->flags & BDF_REMOVABLE && !(bd->flags & BDF_INITIALIZED))
|
||||
ChgDsk(Drv2Let(dv));
|
||||
if (bd->type==BDT_RAM ||
|
||||
bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
|
||||
BlkDevInit(bd);
|
||||
}
|
||||
Fs->cur_dv=dv;
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
case FSt_FAT32:
|
||||
case FSt_ISO9660:
|
||||
return TRUE;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U8 *DrvSerialNum(U8 drv_let=0)
|
||||
{//20 bytes max.
|
||||
CBlkDev *bd=Let2BlkDev(drv_let);
|
||||
U16 *st,*res=NULL;
|
||||
I64 i;
|
||||
if (bd->dev_id_record) {
|
||||
st=CAlloc(20+1);
|
||||
for (i=0;i<10;i++)
|
||||
st[i]=EndianU16(bd->dev_id_record[10+i]);
|
||||
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *DrvModelNum(U8 drv_let=0)
|
||||
{//40 bytes max.
|
||||
CBlkDev *bd=Let2BlkDev(drv_let);
|
||||
U16 *st,*res=NULL;
|
||||
I64 i;
|
||||
if (bd->dev_id_record) {
|
||||
st=CAlloc(40+1);
|
||||
for (i=0;i<20;i++)
|
||||
st[i]=EndianU16(bd->dev_id_record[27+i]);
|
||||
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 blkdev_text_attr[BDT_TYPES_NUM]={BLACK,LTCYAN,WHITE,LTGREEN,LTRED,LTBLUE};
|
||||
U8 drv_text_attr[3]={BLACK,BLUE,RED};
|
||||
|
||||
U8 DrvTextAttrGet(U8 drv_let=0)
|
||||
{//Get color of drive.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='Z')
|
||||
return blkdev_text_attr[Let2BlkDevType(drv_let)]<<4|
|
||||
drv_text_attr[drv_let%sizeof(drv_text_attr)];
|
||||
else
|
||||
return BLACK<<4|WHITE;
|
||||
}
|
||||
|
||||
U0 DrvRep()
|
||||
{//Drive report.
|
||||
CDrv *dv;
|
||||
CBlkDev *bd;
|
||||
I64 ch,i,drv_let,attr;
|
||||
U8 *st;
|
||||
"\nDefined Drives:\n";
|
||||
for (i=0,dv=blkdev.drvs;i<DRVS_NUM;i++,dv++) {
|
||||
if (dv->dv_signature==DRV_SIGNATURE_VAL) {
|
||||
bd=dv->bd;
|
||||
drv_let=Drv2Let(dv);
|
||||
if (Bt(&dv->fs_type,FStf_DISABLE))
|
||||
ch='-';
|
||||
else if (drv_let==blkdev.boot_drv_let)
|
||||
ch=':';
|
||||
else
|
||||
ch='+';
|
||||
attr=DrvTextAttrGet(drv_let);
|
||||
"$$FG,%d$$$$BG,%d$$%C %-8Z %-10Z %04X %04X %02X\n",
|
||||
attr&15,attr>>4,drv_let,dv->fs_type&FSG_TYPE_MASK,"ST_DRV_TYPES",
|
||||
bd->type,"ST_BLKDEV_TYPES",bd->base0,bd->base1,bd->unit;
|
||||
if (st=DrvModelNum(drv_let)) {
|
||||
" Model# :%s\n",st;
|
||||
Free(st);
|
||||
}
|
||||
if (st=DrvSerialNum(drv_let)) {
|
||||
" Serial#:%s\n",st;
|
||||
Free(st);
|
||||
}
|
||||
if (bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
|
||||
" File=\"%s\"\n",bd->file_dsk_name;
|
||||
" %016X-%016X\n$$FG$$$$BG$$",dv->drv_offset,dv->drv_offset+dv->size-1;
|
||||
}
|
||||
}
|
||||
"Home Dir:\"%s\"\n",blkdev.home_dir;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL)
|
||||
{//Read whole file from disk.
|
||||
CHashGeneric *tmph;
|
||||
U8 *absname,*altname,*curname,*res=NULL;
|
||||
I64 i,size=0,attr=0;
|
||||
CDirContext *dirc;
|
||||
CArcCompress *arc;
|
||||
absname=FileNameAbs(filename);
|
||||
altname=ToggleZorNotZ(absname);
|
||||
if ((tmph=HashFind(absname,adam_task->hash_table,HTT_FILE))||
|
||||
(tmph=HashFind(altname,adam_task->hash_table,HTT_FILE))) {
|
||||
size=tmph->user_data1;
|
||||
res=MAlloc(size+1);
|
||||
MemCpy(res,tmph->user_data0,size);
|
||||
res[size]=0; //Terminate
|
||||
attr=FileAttr(tmph->str,attr);
|
||||
} else {
|
||||
for (i=0;i<2 && !res;i++) {//Try name, then altname
|
||||
if (!i)
|
||||
curname=absname;
|
||||
else
|
||||
curname=altname;
|
||||
if (dirc=DirContextNew(curname)) {
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
|
||||
//Search parent directories.
|
||||
for (i=0;i<2 && !res;i++) {//Try name, then altname
|
||||
if (!i)
|
||||
curname=absname;
|
||||
else
|
||||
curname=altname;
|
||||
if (dirc=DirContextNew(curname)) {
|
||||
while (!res && StrCmp(Fs->cur_dir,"/")) {
|
||||
Cd("..");
|
||||
switch (Fs->cur_dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
"%s ",filename;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
if (res && attr & RS_ATTR_RESIDENT)
|
||||
HashGenericAdd(curname,HTT_FILE,AMAllocIdent(res),size,0,adam_task);
|
||||
}
|
||||
if (res && attr & RS_ATTR_COMPRESSED) {
|
||||
arc=res;
|
||||
size=arc->expanded_size;
|
||||
res=ExpandBuf(arc);
|
||||
Free(arc);
|
||||
}
|
||||
if (_attr) *_attr=attr;
|
||||
if (_size) *_size=size;
|
||||
Free(absname);
|
||||
Free(altname);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 FileWrite(U8 *filename,U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0)
|
||||
{//Write whole file to disk.
|
||||
I64 c=0;
|
||||
CHashGeneric *tmph;
|
||||
CDirContext *dirc;
|
||||
U8 *fbuf2,*absname=FileNameAbs(filename);
|
||||
if (dirc=DirContextNew(filename,FALSE,TRUE)) {
|
||||
attr=FileAttr(dirc->mask,attr);
|
||||
if (attr&RS_ATTR_COMPRESSED) {
|
||||
fbuf=CompressBuf(fbuf,size);
|
||||
size=fbuf(CArcCompress *)->compressed_size;
|
||||
fbuf2=fbuf;
|
||||
} else
|
||||
fbuf2=NULL;
|
||||
if (!cdt) cdt=Now;
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
c=RedSeaFileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
c=FAT32FileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
if (tmph=HashFind(absname,adam_task->hash_table,HTT_FILE)) {
|
||||
if (attr & RS_ATTR_RESIDENT) {
|
||||
Free(tmph->user_data0);
|
||||
tmph->user_data0=AMAllocIdent(fbuf);
|
||||
tmph->user_data1=size;
|
||||
} else
|
||||
HashRemDel(tmph,adam_task->hash_table);
|
||||
} else if (attr & RS_ATTR_RESIDENT)
|
||||
HashGenericAdd(absname,HTT_FILE,AMAllocIdent(fbuf),size,0,adam_task);
|
||||
Free(fbuf2);
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
Free(absname);
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
CDirEntry *FilesFind2(U8 *files_find_mask,I64 fuf_flags)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CDirEntry *res=NULL;
|
||||
DrvChk(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
res=NULL;
|
||||
}
|
||||
if (res) {
|
||||
DirFilesSort(&res,SK_NAME);
|
||||
if (fuf_flags&(FUF_FLATTEN_TREE|FUF_JUST_FILES))
|
||||
DirFilesFlatten(res,&res,fuf_flags);
|
||||
if (fuf_flags&FUF_CLUSTER_ORDER)
|
||||
DirFilesSort(&res,SK_CLUSTER);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CDirEntry *FilesFind(U8 *files_find_mask,I64 fuf_flags=0)
|
||||
{/* See $LK,"::/Doc/FileUtils.DD"$.
|
||||
|
||||
Find files and make a directory tree in memory.
|
||||
|
||||
When done, you free with $LK,"DirEntryDel",A="MN:DirEntryDel"$(),$LK,"DirEntryDel2",A="MN:DirEntryDel2"$(),
|
||||
$LK,"DirTreeDel",A="MN:DirTreeDel"$() or $LK,"DirTreeDel2",A="MN:DirTreeDel2"$().
|
||||
|
||||
*/
|
||||
CDirEntry *res;
|
||||
CDirContext *dirc;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
if (fuf_flags&FUF_SINGLE) {
|
||||
res=MAlloc(sizeof(CDirEntry));
|
||||
if (!FileFind(files_find_mask,res)) {
|
||||
Free(res);
|
||||
return NULL;
|
||||
}
|
||||
} else if (dirc=DirContextNew(files_find_mask,TRUE)) {
|
||||
res=FilesFind2(dirc->mask,fuf_flags);
|
||||
DirContextDel(dirc);
|
||||
} else
|
||||
return NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$, $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$
|
||||
//If you pass _de, you must Free(_de->full_name);
|
||||
I64 i,j,cur_dir_cluster;
|
||||
U8 *altname,*curname,*full_name=NULL;
|
||||
CDirEntry de;
|
||||
CDirContext *dirc;
|
||||
Bool res=FALSE,old_silent;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
if (!filename || *filename && filename[1]==':' && !Let2Drv(*filename,FALSE))
|
||||
return FALSE;
|
||||
altname=ToggleZorNotZ(filename);
|
||||
if (fuf_flags&FUF_Z_OR_NOT_Z)
|
||||
j=2;
|
||||
else
|
||||
j=1;
|
||||
for (i=0;i<j && !res;i++) {
|
||||
if (!i)
|
||||
curname=filename;
|
||||
else
|
||||
curname=altname;
|
||||
old_silent=Silent;
|
||||
if (!(dirc=DirContextNew(curname)))
|
||||
Silent(old_silent);
|
||||
else {
|
||||
Silent(old_silent);
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
if (res && _de) {
|
||||
if (StrCmp(Fs->cur_dir,"/"))
|
||||
full_name=MStrPrint("%C:%s/%s",
|
||||
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
|
||||
else
|
||||
full_name=MStrPrint("%C:/%s",Drv2Let(Fs->cur_dv),de.name);
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
for (i=0;i<j && !res && fuf_flags&FUF_SCAN_PARENTS;i++) {
|
||||
if (!i)
|
||||
curname=filename;
|
||||
else
|
||||
curname=altname;
|
||||
old_silent=Silent;
|
||||
if (!(dirc=DirContextNew(curname)))
|
||||
Silent(old_silent);
|
||||
else {
|
||||
Silent(old_silent);
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
while (!res && StrCmp(Fs->cur_dir,"/")) {
|
||||
Cd("..");
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
if (res && _de) {
|
||||
if (StrCmp(Fs->cur_dir,"/"))
|
||||
full_name=MStrPrint("%C:%s/%s",
|
||||
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
|
||||
else
|
||||
full_name=MStrPrint("%C:/%s",
|
||||
Drv2Let(Fs->cur_dv),de.name);
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
if (_de) {
|
||||
if (res) {
|
||||
MemCpy(_de,&de,sizeof(CDirEntry));
|
||||
_de->full_name=full_name;
|
||||
} else
|
||||
MemSet(_de,0,sizeof(CDirEntry));
|
||||
}
|
||||
Free(altname);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
Bool DrvTypeSet(U8 drv_let,I64 type=FSt_REDSEA)
|
||||
{//Very dangerous
|
||||
I64 i,j,ext_base,drv_num,offset,cur_type;
|
||||
CMasterBoot mbr;
|
||||
CBlkDev *bd;
|
||||
drv_let=Let2Let(drv_let);
|
||||
bd=Let2BlkDev(drv_let);
|
||||
drv_num=bd->first_drv_let-'A';
|
||||
switch (bd->type) {
|
||||
case BDT_ATA:
|
||||
offset=0;
|
||||
ext_base=INVALID_CLUSTER;
|
||||
while (TRUE) {
|
||||
ATAReadBlks(bd,&mbr,offset,1);
|
||||
j=-1;
|
||||
for (i=0;i<4;i++) {
|
||||
cur_type=mbr.p[i].type;
|
||||
if (cur_type) {
|
||||
if (cur_type==5 || cur_type==15)
|
||||
j=i;
|
||||
else {
|
||||
if (drv_num+'A'==drv_let) {
|
||||
switch (type) {
|
||||
case FSt_REDSEA:
|
||||
mbr.p[i].type=MBR_PT_REDSEA;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
mbr.p[i].type=MBR_PT_FAT32a;
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
mbr.p[i].active=0x80;
|
||||
ATAWriteBlks(bd,&mbr,offset,1);
|
||||
return TRUE;
|
||||
}
|
||||
drv_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j<0)
|
||||
break;
|
||||
if (!mbr.p[j].offset)
|
||||
break;
|
||||
if (ext_base==INVALID_CLUSTER) {
|
||||
offset=mbr.p[j].offset;
|
||||
ext_base=offset;
|
||||
} else
|
||||
offset=mbr.p[j].offset+ext_base;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Fmt(I64 drv_let,Bool quick=TRUE,Bool confirm=TRUE,I64 type=FSt_FAT32)
|
||||
{//Format hard drive or RAM drive.
|
||||
//$BK,1$Warning:$BK,0$ Destroys all prev info.
|
||||
//quick=FALSE means fill entire drive with zeros.
|
||||
//Choose $LK,"FSt_FAT32",A="MN:FSt_FAT32"$ or $LK,"FSt_REDSEA",A="MN:FSt_REDSEA"$.
|
||||
//You don't format a CD/DVD with this.
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
Bool old_silent=IsSilent;
|
||||
if (confirm && !AreYouSure)
|
||||
return;
|
||||
if (!dv) {
|
||||
PrintErr("Invalid Drive\n");
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case FSt_FAT32:
|
||||
if (dv->bd->type==BDT_ATA) {
|
||||
Silent;
|
||||
Drv(drv_let);
|
||||
Silent(old_silent);
|
||||
FAT32Fmt(drv_let,quick);
|
||||
DskCacheInvalidate(Let2Drv(drv_let));
|
||||
Drv(drv_let);
|
||||
break;
|
||||
}
|
||||
"Using RedSea File System.\n";
|
||||
case FSt_REDSEA:
|
||||
Silent;
|
||||
Drv(drv_let);
|
||||
Silent(old_silent);
|
||||
RedSeaFmt(drv_let,quick);
|
||||
DskCacheInvalidate(Let2Drv(drv_let));
|
||||
Drv(drv_let);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
U8 *FileExtDot(U8 *src)
|
||||
{//Find dot char in name.
|
||||
I64 ch;
|
||||
while (ch=*src++)
|
||||
if (ch=='.' && *src!='/' && *src!='.')
|
||||
return src-1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8 *FileExtRem(U8 *src,U8 *dst=NULL)
|
||||
{//Remove filename extension from str.
|
||||
U8 *ptr;
|
||||
if (ptr=FileExtDot(src)) {
|
||||
if (dst)
|
||||
StrCpy(dst,ptr+1);
|
||||
*ptr=0;
|
||||
} else if (dst)
|
||||
*dst=0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
Bool IsDotZ(U8 *filename)
|
||||
{//Does name end in .Z?
|
||||
I64 i=StrLen(filename);
|
||||
if (StrOcc(filename,'.')>1 && filename[i-1]=='Z' && filename[i-2]=='.')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool IsDotC(U8 *filename)
|
||||
{//Does name end in .C?
|
||||
I64 i=StrLen(filename);
|
||||
if (StrOcc(filename,'.')>1 && filename[i-1]=='C' && filename[i-2]=='.')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool FilesFindMatch(U8 *_test_name,U8 *files_find_mask,I64 fuf_flags=0)
|
||||
{//Does filename meet $LK,"Files Find",A="FI:::/Doc/FileUtils.DD"$ mask?
|
||||
I64 tn_len=StrLen(_test_name),mask_len=StrLen(files_find_mask);
|
||||
U8 *mask1=MAlloc(mask_len+1),*mask2=MAlloc(mask_len+1),
|
||||
*ptr,*test_name1,*test_name2;
|
||||
Bool res=FALSE;
|
||||
StrCpy(mask1,files_find_mask);
|
||||
if (StrOcc(_test_name,'/')) {
|
||||
test_name1=MAlloc(tn_len+1);
|
||||
test_name2=MAlloc(tn_len+1);
|
||||
StrCpy(test_name1,_test_name);
|
||||
StrLastRem(test_name1,"/",test_name2);
|
||||
} else {
|
||||
test_name1=NULL;
|
||||
test_name2=NULL;
|
||||
}
|
||||
while (TRUE) {
|
||||
StrFirstRem(mask1,";",mask2);
|
||||
if (!test_name2 || StrOcc(mask2,'/'))
|
||||
ptr=_test_name;
|
||||
else
|
||||
ptr=test_name2;
|
||||
if (*mask2) {
|
||||
if (*mask2=='!') {
|
||||
if (WildMatch(ptr,mask2+1)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (WildMatch(ptr,mask2)) {
|
||||
if (Bt(&fuf_flags,FUf_JUST_TXT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_TXT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_DD) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_DD)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_SRC) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_SRC)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_AOT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_AOT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_JIT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_JIT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_GR) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_GR)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else
|
||||
res=TRUE;
|
||||
}
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
Free(test_name1);
|
||||
Free(test_name2);
|
||||
Free(mask1);
|
||||
Free(mask2);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *DirNameAbs(U8 *_dirname)
|
||||
{//MAlloc absolute dir string with drv letter.
|
||||
I64 maxlen;
|
||||
U8 drv[3],*res,*buf,*buf2,*buf3,*buf4,*dirname,*free_dirname;
|
||||
if (!Fs->cur_dir || !*Fs->cur_dir)
|
||||
return StrNew(_dirname);
|
||||
free_dirname=dirname=MStrUtil(_dirname,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
*drv=Drv2Let;
|
||||
drv[1]=':';
|
||||
drv[2]=0;
|
||||
if (*dirname && dirname[1]==':') {
|
||||
if (*dirname==':')
|
||||
*drv=blkdev.boot_drv_let;
|
||||
else if (*dirname=='~')
|
||||
*drv=*blkdev.home_dir;
|
||||
else
|
||||
*drv=*dirname;
|
||||
dirname=dirname+2;
|
||||
buf=StrNew("/");
|
||||
} else
|
||||
buf=StrNew(Fs->cur_dir);
|
||||
if (*dirname=='/') {
|
||||
Free(buf);
|
||||
buf=StrNew("/");
|
||||
dirname++;
|
||||
}
|
||||
buf2=StrNew(dirname);
|
||||
maxlen=StrLen(buf)+1+StrLen(buf2)+1;
|
||||
buf3=MAlloc(maxlen);
|
||||
buf4=MAlloc(maxlen);
|
||||
StrCpy(buf3,buf);
|
||||
while (*buf2) {
|
||||
StrFirstRem(buf2,"/",buf4);
|
||||
if (!*buf4)
|
||||
StrCpy(buf3,"/");
|
||||
else if (!StrCmp(buf4,"..")) {
|
||||
StrLastRem(buf3,"/");
|
||||
if (!*buf3)
|
||||
StrCpy(buf3,"/");
|
||||
} else if (!StrCmp(buf4,"~")) {
|
||||
Free(buf3);
|
||||
buf3=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(buf2)+1);
|
||||
StrCpy(buf3,blkdev.home_dir+2);
|
||||
*drv=*blkdev.home_dir;
|
||||
} else if (!StrCmp(buf4,"."));
|
||||
else if (*buf4) {
|
||||
if (StrCmp(buf3,"/"))
|
||||
CatPrint(buf3,"/");
|
||||
CatPrint(buf3,buf4);
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
res=MAlloc(StrLen(buf3)+3);
|
||||
StrCpy(res,drv);
|
||||
StrCpy(res+2,buf3);
|
||||
Free(buf2);
|
||||
Free(buf3);
|
||||
Free(buf4);
|
||||
Free(free_dirname);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FileNameAbs(U8 *_filename,I64 fuf_flags=0)
|
||||
{//Absolute filename. Accepts $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$.
|
||||
U8 *res,*filename,*buf,*buf_file,*buf_dir,*free_filename,*free_buf;
|
||||
CDirEntry de;
|
||||
free_filename=filename=MStrUtil(_filename,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
free_buf=buf=StrNew(filename);
|
||||
if (*buf && buf[1]==':') {
|
||||
buf+=2;
|
||||
filename+=2;
|
||||
}
|
||||
buf_file=MAlloc(StrLen(free_filename)+1);
|
||||
StrLastRem(buf,"/",buf_file);
|
||||
if (*filename=='/' && !*buf)
|
||||
StrCpy(buf,"/");
|
||||
buf_dir=DirNameAbs(free_buf);
|
||||
Free(free_buf);
|
||||
res=MAlloc(StrLen(buf_dir)+1+StrLen(buf_file)+1);
|
||||
StrCpy(res,buf_dir);
|
||||
if (res[StrLen(res)-1]!='/')
|
||||
CatPrint(res,"/");
|
||||
CatPrint(res,buf_file);
|
||||
Free(buf_file);
|
||||
Free(buf_dir);
|
||||
Free(free_filename);
|
||||
if (fuf_flags && FileFind(res,&de,fuf_flags|FUF_JUST_FILES)) {
|
||||
Free(res);
|
||||
res=de.full_name;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *ChgExt(U8 *filename,U8 *extension)
|
||||
{//Change filename extension.
|
||||
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
|
||||
StrCpy(res,filename);
|
||||
if (FileExtDot(filename))
|
||||
FileExtRem(res);
|
||||
return CatPrint(res,".%s",extension);
|
||||
}
|
||||
|
||||
U8 *DftExt(U8 *filename,U8 *extension)
|
||||
{//Give extension if has none.
|
||||
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
|
||||
StrCpy(res,filename);
|
||||
if (!FileExtDot(filename))
|
||||
CatPrint(res,".%s",extension);
|
||||
return res;
|
||||
}
|
||||
|
||||
CDirEntry *Cd2DirEntry(CDirEntry *tmpde,U8 *abs_name)
|
||||
{
|
||||
I64 i;
|
||||
while (tmpde) {
|
||||
i=StrLen(tmpde->full_name);
|
||||
if (StrNCmp(tmpde->full_name,abs_name,i)||
|
||||
i && tmpde->full_name[i-1]!='/' && abs_name[i] && abs_name[i]!='/')
|
||||
tmpde=tmpde->next;
|
||||
else
|
||||
if (StrLen(abs_name)==i)
|
||||
return tmpde;
|
||||
else
|
||||
return Cd2DirEntry(tmpde->sub,abs_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 FileAttr(U8 *name,I64 attr=0)
|
||||
{
|
||||
if (IsDotZ(name))
|
||||
attr|=RS_ATTR_COMPRESSED;
|
||||
else
|
||||
attr&=~RS_ATTR_COMPRESSED;
|
||||
if (IsDotC(name))
|
||||
attr|=RS_ATTR_CONTIGUOUS;
|
||||
return attr;
|
||||
}
|
||||
|
||||
Bool FileNameChk(U8 *filename)
|
||||
{//Return check for valid filename, not checking existence.
|
||||
U8 *ptr=filename;
|
||||
if (!filename) return FALSE;
|
||||
if (!*ptr) return FALSE;
|
||||
if (*ptr=='.') {
|
||||
if (!ptr[1]) return TRUE;
|
||||
if (ptr[1]=='.' && !ptr[2]) return TRUE;
|
||||
}
|
||||
if (StrLen(filename)>=CDIR_FILENAME_LEN) return FALSE;
|
||||
while (*ptr)
|
||||
if (!Bt(char_bmp_filename,*ptr++))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U8 *ToggleZorNotZ(U8 *name)
|
||||
{//MAlloc name with Z if not Z or vice versa.
|
||||
U8 *res;
|
||||
if (IsDotZ(name)) {
|
||||
res=StrNew(name);
|
||||
res[StrLen(name)-2]=0;
|
||||
} else
|
||||
res=MStrPrint("%s.Z",name);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FileNameTmpTxt()
|
||||
{//Make pretty-safe tmp filename in home dir.
|
||||
return MStrPrint("~/SysTmp%X.DD.Z",GetTSC>>8&0xFFFFFFFF);
|
||||
}
|
||||
|
||||
U8 *CurDir(CTask *task=NULL,CTask *mem_task=NULL)
|
||||
{//MAlloc copy of cur dir with drv letter.
|
||||
U8 *st;
|
||||
if (!task) task=Fs;
|
||||
if (!task->cur_dir)
|
||||
return NULL;
|
||||
st=MAlloc(StrLen(task->cur_dir)+3,mem_task);
|
||||
*st=Drv2Let(task->cur_dv);
|
||||
st[1]=':';
|
||||
StrCpy(st+2,task->cur_dir);
|
||||
return st;
|
||||
}
|
||||
|
||||
U8 *DirFile(U8 *dirname,U8 *name=NULL,U8 *_extension=NULL)
|
||||
{/*Strips file from dirname, scans for file upward until found or
|
||||
returns default.
|
||||
|
||||
("/Kernel/KHashA.HC.Z",NULL,NULL) returns "D:/Kernel"
|
||||
("/Kernel",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
|
||||
("/Kernel/BlkDev",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
|
||||
("/Apps/Psalmody","Load","HC.Z") returns "D:/Apps/Psalmody/Load.HC.Z"
|
||||
*/
|
||||
U8 *st=DirNameAbs(dirname),*st2,*st3,*res,*dft=NULL,*ext;
|
||||
if (_extension && *_extension) {
|
||||
if (*_extension=='.')
|
||||
ext=StrNew(_extension);
|
||||
else
|
||||
ext=MStrPrint(".%s",_extension);
|
||||
} else
|
||||
ext=StrNew("");
|
||||
while (StrOcc(st,'/')&&!IsDir(st))
|
||||
StrLastRem(st,"/");
|
||||
while (StrOcc(st,'/')) {
|
||||
st2=StrNew(st);
|
||||
st3=StrNew(st);
|
||||
StrLastRem(st2,"/",st3);
|
||||
|
||||
if (name)
|
||||
res=MStrPrint("%s/%s%s",st,name,ext);
|
||||
else {
|
||||
if (*ext)
|
||||
res=MStrPrint("%s/%s%s",st,st3,ext);
|
||||
else
|
||||
res=StrNew(st);
|
||||
}
|
||||
if (!dft)
|
||||
dft=StrNew(res);
|
||||
if (!*ext && (!name||!*name) || FileFind(res)) {
|
||||
Free(st3);
|
||||
Free(st2);
|
||||
Free(st);
|
||||
Free(dft);
|
||||
Free(ext);
|
||||
return res;
|
||||
}
|
||||
Free(st);
|
||||
st=st2;
|
||||
Free(st3);
|
||||
}
|
||||
Free(st);
|
||||
Free(ext);
|
||||
return dft;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
Bool CFileNameTo(U8 *dst,U8 *src)
|
||||
{
|
||||
MemSet(dst,0,CDIR_FILENAME_LEN);
|
||||
if (!FileNameChk(src))
|
||||
return FALSE;
|
||||
StrCpy(dst,src);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
I64 Name2DirCluster(CDrv *dv,U8 *dirname)
|
||||
{
|
||||
Bool cont=TRUE,unlock;
|
||||
I64 cur_dir_cluster;
|
||||
CDirEntry de;
|
||||
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=dv->root_cluster;
|
||||
while (*buf && cont) {
|
||||
StrFirstRem(buf,"/",buf2);
|
||||
if (*buf2) {
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
cur_dir_cluster=de.cluster;
|
||||
}
|
||||
}
|
||||
if (!cont) {
|
||||
"%s ",dirname;
|
||||
PrintErr("File not found.\n");
|
||||
cur_dir_cluster=0;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
Free(buf);
|
||||
Free(buf2);
|
||||
return cur_dir_cluster;
|
||||
}
|
||||
|
||||
I64 Name2ParentDirCluster(CDrv *dv,U8 *dirname)
|
||||
{
|
||||
Bool cont=TRUE,unlock;
|
||||
I64 cur_dir_cluster,cur_dir_cluster2;
|
||||
CDirEntry de;
|
||||
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=cur_dir_cluster2=dv->root_cluster;
|
||||
while (*buf && cont) {
|
||||
cur_dir_cluster2=cur_dir_cluster;
|
||||
StrFirstRem(buf,"/",buf2);
|
||||
if (*buf2) {
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
cur_dir_cluster=de.cluster;
|
||||
}
|
||||
}
|
||||
if (!cont) {
|
||||
"%s ",dirname;
|
||||
PrintErr("File not found.\n");
|
||||
cur_dir_cluster2=0;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
Free(buf);
|
||||
Free(buf2);
|
||||
return cur_dir_cluster2;
|
||||
}
|
||||
@@ -0,0 +1,961 @@
|
||||
U0 CDate2Dos(U16 *t,U16 *d,CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt);
|
||||
*d=ds.day_of_mon+(ds.mon+(ds.year-1980)<<4)<<5;
|
||||
*t=ds.sec>>1+(ds.min+ds.hour<<6)<<5;
|
||||
}
|
||||
|
||||
CDate Dos2CDate(U16 t,U16 d)
|
||||
{
|
||||
CDateStruct ds;
|
||||
MemSet(&ds,0,sizeof(CDateStruct));
|
||||
ds.day_of_mon=d&0x1F; d=d>>5;
|
||||
ds.mon=d&0xF;
|
||||
ds.year=d>>4+1980;
|
||||
ds.sec=(t&0x1F)*2; t=t>>5;
|
||||
ds.min=t&0x3F;
|
||||
ds.hour=t>>6;
|
||||
return Struct2Date(&ds);
|
||||
}
|
||||
|
||||
U0 FAT32Init(CDrv *dv)
|
||||
{
|
||||
CFAT32Boot br32;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
dv->fs_type=FSt_FAT32;
|
||||
RBlks(dv,&br32,dv->drv_offset,1);
|
||||
dv->file_system_info_sect=dv->drv_offset+br32.file_system_info_sect;
|
||||
dv->fat1=dv->drv_offset+br32.reserved_sects;
|
||||
dv->fat2=dv->fat1+br32.sects_per_fat;
|
||||
dv->data_area=dv->fat2+br32.sects_per_fat
|
||||
-2*br32.sects_per_cluster; //Starts at Cluster 2
|
||||
dv->spc=br32.sects_per_cluster;
|
||||
dv->root_cluster=br32.root_cluster;
|
||||
DrvFATBlkAlloc(dv);
|
||||
Free(dv->fis);
|
||||
dv->fis=AMAlloc(BLK_SIZE);
|
||||
RBlks(dv,dv->fis,dv->file_system_info_sect,1);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 FAT32Fmt(U8 drv_let,Bool quick=TRUE)
|
||||
{
|
||||
CFAT32Boot *br=CAlloc(BLK_SIZE);
|
||||
CFAT32FileInfoSect *fis=CAlloc(BLK_SIZE);
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
I64 i,l;
|
||||
try {
|
||||
DrvLock(dv);
|
||||
DrvTypeSet(drv_let,FSt_FAT32);
|
||||
dv->fs_type=FSt_FAT32;
|
||||
br->jump_and_nop[0]=OC_JMP_REL8;
|
||||
br->jump_and_nop[1]=offset(CFAT32Boot.code)-2;
|
||||
br->jump_and_nop[2]=OC_NOP;
|
||||
br->oem_name[0](I64)='MSWIN4.1';
|
||||
br->bytes_per_sect=BLK_SIZE;
|
||||
if (dv->size<= 500000)
|
||||
br->sects_per_cluster=1;
|
||||
else if (dv->size<=2000000)
|
||||
br->sects_per_cluster=2;
|
||||
else if (dv->size<=6000000)
|
||||
br->sects_per_cluster=4;
|
||||
else if (dv->size<=12000000)
|
||||
br->sects_per_cluster=8;
|
||||
else if (dv->size<=33000000)
|
||||
br->sects_per_cluster=16;
|
||||
else if (dv->size<=67000000)
|
||||
br->sects_per_cluster=32;
|
||||
else
|
||||
br->sects_per_cluster=64;
|
||||
|
||||
br->reserved_sects=32;
|
||||
br->copies_of_fat=2;
|
||||
br->media_desc=0xF8;
|
||||
br->sects=dv->size;
|
||||
l=(br->sects/br->sects_per_cluster)>>(BLK_SIZE_BITS-2)+1;
|
||||
br->sects_per_fat=l;
|
||||
br->root_cluster=2;
|
||||
br->file_system_info_sect=1;
|
||||
br->log_drv_num=0x80;
|
||||
br->ext_signature=0x29;
|
||||
br->serial_num=RandU32;
|
||||
MemCpy(br->vol_name,"NO NAME ",11);
|
||||
br->fat_name[0](I64)='FAT32 ';
|
||||
br->signature=0xAA55;
|
||||
fis->signature1='RRaA';
|
||||
fis->signature2='rrAa';
|
||||
fis->free_clusters=-1;
|
||||
fis->most_recently_alloced=0;
|
||||
fis->signature3=0xAA550000;
|
||||
|
||||
if (quick)
|
||||
i=br->reserved_sects+2*l+4*br->sects_per_cluster;
|
||||
else
|
||||
i=dv->size;
|
||||
WZeroBlks(dv,dv->drv_offset,i);
|
||||
|
||||
WBlks(dv,fis,dv->drv_offset+br->file_system_info_sect,1);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
FAT32Init(dv);
|
||||
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
|
||||
br->root_cluster=ClustersAlloc(dv,0,1,FALSE);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
FAT32Init(dv);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
Free(br);
|
||||
Free(fis);
|
||||
}
|
||||
|
||||
Bool FATNameTo(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i;
|
||||
MemSet(dst,CH_SPACE,11);
|
||||
if (!FileNameChk(src))
|
||||
return FALSE;
|
||||
if (!StrCmp(src,"..")) {
|
||||
*dst='.';
|
||||
dst[1]='.';
|
||||
return TRUE;
|
||||
} else if (!StrCmp(src,".")) {
|
||||
*dst='.';
|
||||
return TRUE;
|
||||
}
|
||||
i=0;
|
||||
while (i<8 && *src && *src!='.')
|
||||
dst[i++]=ToUpper(*src++);
|
||||
i=8;
|
||||
if (*src=='.') src++;
|
||||
while (*src)
|
||||
if (*src!='.')
|
||||
dst[i++]=ToUpper(*src++);
|
||||
else
|
||||
src++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
I64 FATNameXSum(U8 *src)
|
||||
{
|
||||
I64 i,res=0;
|
||||
for (i=0;i<11;i++)
|
||||
if (res&1)
|
||||
res.u8[0]=0x80+res>>1+*src++;
|
||||
else
|
||||
res.u8[0]=res>>1+*src++;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FATFromName(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i,j,k=0;
|
||||
for (j=7;j>=0 && src[j]==CH_SPACE;j--);
|
||||
for(i=0;i<=j;i++)
|
||||
dst[k++]=src[i];
|
||||
for (j=10;j>=8 && src[j]==CH_SPACE;j--);
|
||||
if (*src!='.' && j!=7)
|
||||
dst[k++]='.';
|
||||
for(i=8;i<=j;i++)
|
||||
dst[k++]=src[i];
|
||||
dst[k++]=0;
|
||||
return FileNameChk(dst);
|
||||
}
|
||||
|
||||
U8 fat_long_name_map[13]={
|
||||
offset(CFAT32DirEntryLong.name1),
|
||||
offset(CFAT32DirEntryLong.name1)+2,
|
||||
offset(CFAT32DirEntryLong.name1)+4,
|
||||
offset(CFAT32DirEntryLong.name1)+6,
|
||||
offset(CFAT32DirEntryLong.name1)+8,
|
||||
offset(CFAT32DirEntryLong.name2),
|
||||
offset(CFAT32DirEntryLong.name2)+2,
|
||||
offset(CFAT32DirEntryLong.name2)+4,
|
||||
offset(CFAT32DirEntryLong.name2)+6,
|
||||
offset(CFAT32DirEntryLong.name2)+8,
|
||||
offset(CFAT32DirEntryLong.name2)+10,
|
||||
offset(CFAT32DirEntryLong.name3),
|
||||
offset(CFAT32DirEntryLong.name3)+2
|
||||
};
|
||||
|
||||
Bool DirLongNameFill(CDirEntry *tmpde,CFAT32DirEntryLong *de,I64 *xsum)
|
||||
{
|
||||
I64 i;
|
||||
U8 *ptr=de;
|
||||
if (de->ord&0x40) {
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
*xsum=de->xsum;
|
||||
} else if (de->type || de->zero || de->xsum!=*xsum) {
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
*xsum=0;
|
||||
return FALSE;
|
||||
}
|
||||
switch (de->ord&0x3F) {
|
||||
case 1:
|
||||
for (i=0;i<13;i++)
|
||||
if (!(tmpde->name[i]=ptr[fat_long_name_map[i]]))
|
||||
return TRUE;
|
||||
break;
|
||||
case 2:
|
||||
for (i=0;i<12;i++)
|
||||
if (!(tmpde->name[i+13]=ptr[fat_long_name_map[i]]))
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool FAT32CDirFill(CDirEntry *tmpde,
|
||||
CFAT32DirEntry *de,CDate _local_time_offset)
|
||||
{
|
||||
Bool res;
|
||||
if (*tmpde->name)
|
||||
res=TRUE;
|
||||
else
|
||||
res=FATFromName(tmpde->name,de->name);
|
||||
tmpde->cluster=de->cluster_lo+de->cluster_hi<<16;
|
||||
tmpde->size=de->size;
|
||||
tmpde->attr=de->attr;
|
||||
tmpde->datetime=Dos2CDate(de->WrtTime,de->WrtDate)-_local_time_offset;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32DirFill(CFAT32DirEntry *de,
|
||||
CDirEntry *tmpde,I64 *_de_cnt,CDate _local_time_offset)
|
||||
{//Fill up to 3 entries and store cnt of entries.
|
||||
I64 de_cnt=0,i,l,xsum,ord;
|
||||
U8 *ptr,dname[16];
|
||||
CFAT32DirEntryLong *ld=de;
|
||||
Bool res;
|
||||
|
||||
MemSet(de,0,sizeof(CFAT32DirEntry));
|
||||
res=FATNameTo(de->name,tmpde->name);
|
||||
FATFromName(dname,de->name);
|
||||
if (StrCmp(dname,tmpde->name)) {
|
||||
ord=0x41;
|
||||
xsum=FATNameXSum(de->name);
|
||||
if ((l=StrLen(tmpde->name))>13) {
|
||||
ptr=&ld[de_cnt];
|
||||
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
|
||||
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
|
||||
ld[de_cnt].xsum=xsum;
|
||||
ld[de_cnt].ord=0x42;
|
||||
for (i=13;i<l;i++)
|
||||
ptr[fat_long_name_map[i-13]]=tmpde->name[i];
|
||||
i++;
|
||||
for (;i<26;i++)
|
||||
ptr[fat_long_name_map[i-13]](U16)=0xFFFF;
|
||||
ord=1;
|
||||
l=13;
|
||||
de_cnt++;
|
||||
}
|
||||
ptr=&de[de_cnt];
|
||||
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
|
||||
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
|
||||
ld[de_cnt].xsum=xsum;
|
||||
ld[de_cnt].ord=ord;
|
||||
for (i=0;i<l;i++)
|
||||
ptr[fat_long_name_map[i]]=tmpde->name[i];
|
||||
i++;
|
||||
for (;i<13;i++)
|
||||
ptr[fat_long_name_map[i]](U16)=0xFFFF;
|
||||
de_cnt++;
|
||||
MemSet(&de[de_cnt],0,sizeof(CFAT32DirEntry));
|
||||
res=FATNameTo(de[de_cnt].name,tmpde->name);
|
||||
}
|
||||
de[de_cnt].cluster_lo=tmpde->cluster.u16[0];
|
||||
de[de_cnt].cluster_hi=tmpde->cluster.u16[1];
|
||||
if (!(tmpde->attr&RS_ATTR_DIR))
|
||||
de[de_cnt].size=tmpde->size;
|
||||
de[de_cnt].attr=tmpde->attr;
|
||||
if (!tmpde->datetime)
|
||||
tmpde->datetime=Now;
|
||||
CDate2Dos(&de[de_cnt].WrtTime,&de[de_cnt].WrtDate,
|
||||
tmpde->datetime+_local_time_offset);
|
||||
if (_de_cnt)
|
||||
*_de_cnt=de_cnt+1;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32FileFind(CDrv *dv,I64 cur_dir_cluster,
|
||||
U8 *name,CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
Bool res=FALSE,unlock;
|
||||
CFAT32DirEntry *buf;
|
||||
I64 xsum=0,attr,cur_dir_entry,entries_per_cluster;
|
||||
U8 dname[CDIR_FILENAME_LEN],ch;
|
||||
CDirEntry long_name;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (!CFileNameTo(dname,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
buf=MAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5) {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr&RS_ATTR_VOL_ID)) {
|
||||
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemCpy(_res,&long_name,sizeof(CDirEntry));
|
||||
else
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
if (!(fuf_flags&FUF_JUST_DIRS && !(attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && attr & RS_ATTR_DIR) &&
|
||||
FAT32CDirFill(_res,&buf[cur_dir_entry],
|
||||
dv->fat32_local_time_offset) &&
|
||||
!StrCmp(dname,_res->name)) {
|
||||
res=TRUE;
|
||||
goto fff_done;
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (!(0<cur_dir_cluster<0x0FFFFFF8))
|
||||
break;
|
||||
else {
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
fff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FAT32FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (FAT32FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
c=0x0FFFFFFF;
|
||||
else
|
||||
c=RClustersBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool FAT32Cd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (FAT32FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 FAT32FreeClusters(CDrv *dv,I64 c)
|
||||
{
|
||||
I64 next,saved_c=c;
|
||||
Bool unlock,unlock_break;
|
||||
DrvChk(dv);
|
||||
if (!(0<c<0x0FFFFFF8)) return;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
DrvFATBlkClean(dv);
|
||||
do {
|
||||
DrvFATBlkSet(dv,c,0);
|
||||
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c=next;
|
||||
} while (0<c<0x0FFFFFF8);
|
||||
DrvFATBlkClean(dv,0);
|
||||
|
||||
c=saved_c;
|
||||
do {
|
||||
DrvFATBlkSet(dv,c,1);
|
||||
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c=next;
|
||||
} while (0<c<0x0FFFFFF8);
|
||||
DrvFATBlkClean(dv,1);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
}
|
||||
|
||||
I64 FAT32AllocClusters(CDrv *dv,I64 c,I64 cnt)
|
||||
{
|
||||
Bool wrap_around=FALSE,unlock,unlock_break;
|
||||
I64 first=INVALID_CLUSTER,j,l;
|
||||
|
||||
if (cnt<=0) return 0x0FFFFFFF;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
l=(dv->size+dv->drv_offset-dv->data_area)/dv->spc-1;
|
||||
j=dv->fis->most_recently_alloced;
|
||||
while (cnt-->0) {
|
||||
while (TRUE) {
|
||||
j++;
|
||||
if (j<1) j=1;
|
||||
if (j>=l) {
|
||||
if (wrap_around)
|
||||
throw('Drv');
|
||||
j=1;
|
||||
wrap_around=TRUE;
|
||||
}
|
||||
DrvFATBlkSet(dv,j);
|
||||
if (!dv->cur_fat_blk[j&(BLK_SIZE/4-1)])
|
||||
break;
|
||||
}
|
||||
if (!(0<first<0x0FFFFFF8))
|
||||
first=j;
|
||||
if (0<c<l) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=j;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
c=j;
|
||||
}
|
||||
|
||||
if (0<c<l) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
dv->fis->most_recently_alloced=j;
|
||||
dv->fis->free_clusters=-1;
|
||||
WBlks(dv,dv->fis,dv->file_system_info_sect,1);
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return first;
|
||||
}
|
||||
|
||||
I64 FAT32AllocContiguousClusters(CDrv *dv,I64 cnt)
|
||||
{
|
||||
I64 i,first=1;
|
||||
Bool cont,unlock,unlock_break;
|
||||
|
||||
if (cnt<=0) return 0x0FFFFFFF;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
while (TRUE) {
|
||||
first++;
|
||||
i=0;
|
||||
cont=TRUE;
|
||||
while (cont && i<cnt) {
|
||||
if ((first+i+1)*dv->spc+dv->data_area>dv->size+dv->drv_offset)
|
||||
throw('Drv');
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
if (dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)])
|
||||
cont=FALSE;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (!cont)
|
||||
first=first+i;
|
||||
else {
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i,0);
|
||||
if (i+1==cnt)
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
else
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv,0);
|
||||
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i,1);
|
||||
if (i+1==cnt)
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
else
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return first;
|
||||
}
|
||||
|
||||
Bool FAT32DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
|
||||
{
|
||||
//See $LK,"::/Doc/CutCorners.DD"$.
|
||||
CFAT32DirEntry *buf,*last_buf,*tmp_buf,de[3];
|
||||
I64 i,attr,avail_cnt,de_cnt,c,
|
||||
cur_dir_entry,entries_per_cluster,
|
||||
cur_dir_cluster,xsum=0,last_dir_cluster=INVALID_CLUSTER;
|
||||
U8 ch;
|
||||
Bool written=FALSE,unlock,unlock_break;
|
||||
CDirEntry long_name;
|
||||
FAT32DirFill(&de,tmpde,&de_cnt,dv->fat32_local_time_offset);
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf =MAlloc(BLK_SIZE*dv->spc);
|
||||
last_buf=CAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5 && attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry
|
||||
&(FAT32_ENTRIES_PER_BLK-1);
|
||||
for (i=0;i<avail_cnt;i++)
|
||||
if (*buf[cur_dir_entry+i].name!=0xE5) {
|
||||
if (*buf[cur_dir_entry+i].name)
|
||||
avail_cnt=i;
|
||||
break;
|
||||
}
|
||||
if (ch==0xE5 && !written && avail_cnt>=de_cnt) {
|
||||
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=de_cnt-1; //gets inc'ed
|
||||
written=TRUE;
|
||||
} else if (ch!=0xE5 && !(attr&RS_ATTR_VOL_ID)) {
|
||||
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (!*long_name.name)
|
||||
FATFromName(long_name.name,buf[cur_dir_entry].name);
|
||||
//Del old entry with same name
|
||||
if (!StrCmp(long_name.name,tmpde->name)) {
|
||||
if (free_old_chain)
|
||||
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
|
||||
buf[cur_dir_entry].cluster_hi<<16);
|
||||
if (!written) {
|
||||
MemCpy(&buf[cur_dir_entry],&de[de_cnt-1],sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
written=TRUE;
|
||||
} else {
|
||||
*buf[cur_dir_entry].name=0xE5;
|
||||
i=1;
|
||||
while (i<=cur_dir_entry &&
|
||||
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
|
||||
==RS_ATTR_LONG_NAME)
|
||||
*buf[cur_dir_entry-i++].name=0xE5;
|
||||
i--;
|
||||
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
|
||||
if (i==cur_dir_entry && 0<last_dir_cluster<0x0FFFFFF8) {
|
||||
i=1;
|
||||
while (i<=entries_per_cluster &&
|
||||
last_buf[entries_per_cluster-i].attr
|
||||
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
*last_buf[entries_per_cluster-i++].name=0xE5;
|
||||
if (--i>0)
|
||||
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+last_dir_cluster*dv->spc
|
||||
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
c=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (!(0<c<0x0FFFFFF8)) {
|
||||
c=ClustersAlloc(dv,cur_dir_cluster,1,FALSE);
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,c,1);
|
||||
} else
|
||||
RClusters(dv,buf,c,1);
|
||||
cur_dir_cluster=c;
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
if (!written) {
|
||||
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry & (FAT32_ENTRIES_PER_BLK-1);
|
||||
if (avail_cnt<de_cnt) {
|
||||
for (i=0;i<avail_cnt;i++)
|
||||
*buf[cur_dir_entry+i].name=0xE5;
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=avail_cnt;
|
||||
if (cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,cur_dir_cluster,1);
|
||||
}
|
||||
}
|
||||
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc+
|
||||
cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=de_cnt;
|
||||
if (cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,cur_dir_cluster,1);
|
||||
} else {
|
||||
MemSet(&buf[cur_dir_entry],0,sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
}
|
||||
}
|
||||
Free(last_buf);
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 FAT32FilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
|
||||
Bool del_dir,Bool print_msg)
|
||||
{
|
||||
CFAT32DirEntry *buf,*last_buf,*tmp_buf;
|
||||
I64 i,res=0,attr,xsum=0,last_dir_cluster=INVALID_CLUSTER,
|
||||
cur_dir_entry,entries_per_cluster,cur_dir_cluster;
|
||||
U8 ch;
|
||||
Bool unlock_break;
|
||||
CDirEntry long_name;
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf =MAlloc(BLK_SIZE*dv->spc);
|
||||
last_buf=CAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5 && ch!='.') {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr & RS_ATTR_VOL_ID) &&
|
||||
(del_dir || !(attr & RS_ATTR_DIR))) {
|
||||
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (!*long_name.name)
|
||||
FATFromName(long_name.name,buf[cur_dir_entry].name);
|
||||
if (FilesFindMatch(long_name.name,files_find_mask,fuf_flags)) {
|
||||
if (!(attr & RS_ATTR_DIR)) res++;
|
||||
if (print_msg)
|
||||
"Del %s\n",long_name.name;
|
||||
*buf[cur_dir_entry].name=0xE5;
|
||||
i=1;
|
||||
while (i<=cur_dir_entry &&
|
||||
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
|
||||
==RS_ATTR_LONG_NAME)
|
||||
*buf[cur_dir_entry-i++].name=0xE5;
|
||||
i--;
|
||||
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
|
||||
if (i==cur_dir_entry && last_dir_cluster!=INVALID_CLUSTER) {
|
||||
i=1;
|
||||
while (i<=entries_per_cluster &&
|
||||
last_buf[entries_per_cluster-i].attr
|
||||
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
*last_buf[entries_per_cluster-i++].name=0xE5;
|
||||
if (--i>0)
|
||||
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+last_dir_cluster*dv->spc
|
||||
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
|
||||
}
|
||||
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
|
||||
buf[cur_dir_entry].cluster_hi<<16);
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster,1);
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
Free(last_buf);
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 FAT32FileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
|
||||
CDate cdt,I64 attr)
|
||||
{
|
||||
CDirEntry de;
|
||||
I64 c=0,blk_cnt;
|
||||
Bool contiguous;
|
||||
MemSet(&de,0,sizeof(CDirEntry));
|
||||
if (size<0) size=0;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (!CFileNameTo(de.name,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
FAT32FilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
|
||||
if (attr & RS_ATTR_CONTIGUOUS)
|
||||
contiguous=TRUE;
|
||||
else
|
||||
contiguous=FALSE;
|
||||
de.size=size;
|
||||
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
|
||||
c=ClustersAlloc(dv,0,(blk_cnt+dv->spc-1)/dv->spc,contiguous);
|
||||
else
|
||||
c=0x0FFFFFFF;
|
||||
de.cluster=c;
|
||||
de.attr=attr;
|
||||
de.datetime=cdt;
|
||||
if (blk_cnt)
|
||||
WClustersBlks(dv,buf,c,blk_cnt);
|
||||
FAT32DirNew(dv,cur_dir,&de,TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
CDirEntry *FAT32FilesFind(U8 *files_find_mask,
|
||||
I64 fuf_flags,CDirEntry *parent=NULL,I64 *_dir_size=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CFAT32DirEntry *buf;
|
||||
I64 attr,xsum=0,dir_size=0,sub_dir_size,
|
||||
cur_dir_cluster,cur_dir_entry,entries_per_cluster;
|
||||
U8 ch;
|
||||
CDirEntry *res=NULL,*tmpde,long_name;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
try {
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
buf=MAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
dir_size+=dv->spc*BLK_SIZE;
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5) {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr&RS_ATTR_VOL_ID)) {
|
||||
tmpde=MAlloc(sizeof(CDirEntry));
|
||||
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemCpy(tmpde,&long_name,sizeof(CDirEntry));
|
||||
else
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
if (FAT32CDirFill(tmpde,&buf[cur_dir_entry],
|
||||
dv->fat32_local_time_offset)) {
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
DrvUnlock(dv);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=FAT32FilesFind(files_find_mask,fuf_flags,
|
||||
tmpde,&sub_dir_size);
|
||||
tmpde->size=sub_dir_size;
|
||||
Cd("..");
|
||||
}
|
||||
DrvLock(dv);
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((attr&RS_ATTR_DIR || !Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) &&
|
||||
*tmpde->name=='.' && attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,
|
||||
fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (cur_dir_cluster==INVALID_CLUSTER)
|
||||
break;
|
||||
else {
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
dir_size+=dv->spc*BLK_SIZE;
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
if (_dir_size)
|
||||
*_dir_size=dir_size;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32MkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
|
||||
{
|
||||
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
|
||||
//Rough estimate of size
|
||||
size=CeilU64((entry_cnt+2)<<FAT32_ENTRIES_BITS,dv->spc<<BLK_SIZE_BITS);
|
||||
U8 *buf=CAlloc(size);
|
||||
CDirEntry d_native;
|
||||
CFAT32DirEntry *dFAT=buf;
|
||||
Bool unlock_break;
|
||||
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
|
||||
MemSet(&d_native,0,sizeof(CDirEntry));
|
||||
d_native.attr=RS_ATTR_DIR;
|
||||
*d_native.name='.';
|
||||
d_native.name[1]=0;
|
||||
d_native.cluster=c;
|
||||
d_native.size=0;
|
||||
d_native.datetime=Now;
|
||||
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
|
||||
dFAT++;
|
||||
|
||||
MemSet(&d_native,0,sizeof(CDirEntry));
|
||||
d_native.attr=RS_ATTR_DIR;
|
||||
*d_native.name='.';
|
||||
d_native.name[1]='.';
|
||||
d_native.name[2]=0;
|
||||
d_native.cluster=cur_dir_cluster;
|
||||
d_native.size=0;
|
||||
d_native.datetime=Now;
|
||||
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
|
||||
WClusters(dv,buf,c,1);
|
||||
Free(buf);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
U0 Date2ISO1(CISO1Date *dst,CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt);
|
||||
dst->year=ds.year-ISO1_BASE_YEAR;
|
||||
dst->mon=ds.mon;
|
||||
dst->day=ds.day_of_mon;
|
||||
dst->hour=ds.hour;
|
||||
dst->min=ds.min;
|
||||
dst->sec=ds.sec;
|
||||
dst->sec100=ds.sec100;
|
||||
}
|
||||
|
||||
CDate ISO1DateStruct2CDate(CISO1Date *dt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
MemSet(&ds,0,sizeof(CDateStruct));
|
||||
ds.day_of_mon=dt->day;
|
||||
ds.mon=dt->mon;
|
||||
ds.year=dt->year+ISO1_BASE_YEAR;
|
||||
ds.sec100=dt->sec100;
|
||||
ds.sec=dt->sec;
|
||||
ds.min=dt->min;
|
||||
ds.hour=dt->hour;
|
||||
return Struct2Date(&ds);
|
||||
}
|
||||
|
||||
Bool ISO1FromName(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i,j,n;
|
||||
MemSet(dst,0,CDIR_FILENAME_LEN);
|
||||
n=*src++;
|
||||
if (n==1 && !*src) {
|
||||
*dst='.';
|
||||
} else if (n==1 && *src==1) {
|
||||
*dst='.';
|
||||
dst[1]='.';
|
||||
} else {
|
||||
n>>=1;
|
||||
j=0;
|
||||
for (i=0;i<n;i++) {
|
||||
src++;
|
||||
if (*src==';')
|
||||
break;
|
||||
if (Bt(char_bmp_filename,*src)) {
|
||||
if (j>=CDIR_FILENAME_LEN-1)
|
||||
return FALSE;
|
||||
dst[j++]=*src++;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FileNameChk(dst);
|
||||
}
|
||||
|
||||
Bool ISO1CDirFill(CDirEntry *tmpde,CISO1DirEntry *de)
|
||||
{
|
||||
Bool res;
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
res=ISO1FromName(tmpde->name,&de->name_len);
|
||||
tmpde->cluster=de->loc.little;
|
||||
tmpde->size=de->size.little;
|
||||
tmpde->attr=FileAttr(tmpde->name);
|
||||
if (de->flags & ISO1_ATTR_DIR)
|
||||
tmpde->attr|=RS_ATTR_DIR;
|
||||
tmpde->datetime=ISO1DateStruct2CDate(&de->date);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool ISO1FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
CISO1DirEntry *isoptr,*buf;
|
||||
U8 dname[CDIR_FILENAME_LEN];
|
||||
Bool res=FALSE,unlock;
|
||||
I64 i;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
|
||||
RClusters(dv,isoptr,cur_dir_cluster,1);
|
||||
if (isoptr->name_len==1 && !isoptr->name) {//curdir
|
||||
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
|
||||
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
|
||||
RClusters(dv,buf,cur_dir_cluster,i);
|
||||
Free(isoptr);
|
||||
} else {
|
||||
buf=isoptr;
|
||||
i=1;
|
||||
}
|
||||
i*=dv->spc<<BLK_SIZE_BITS;
|
||||
isoptr=buf;
|
||||
while (i>0) {
|
||||
if (!isoptr->len) {
|
||||
isoptr(U8 *)++;
|
||||
i--;
|
||||
} else {
|
||||
ISO1FromName(dname,&isoptr->name_len);
|
||||
if (*dname) {
|
||||
if (!StrCmp(name,dname)) {
|
||||
res=ISO1CDirFill(_res,isoptr);
|
||||
if (res &&
|
||||
!(fuf_flags&FUF_JUST_DIRS &&
|
||||
!(_res->attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && _res->attr & RS_ATTR_DIR) )
|
||||
goto iff_done;
|
||||
else
|
||||
res=FALSE;
|
||||
}
|
||||
}
|
||||
i-=isoptr->len;
|
||||
isoptr(U8 *)+=isoptr->len;
|
||||
}
|
||||
}
|
||||
iff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *ISO1FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (ISO1FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
c=RClustersBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool ISO1Cd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else if (ISO1FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CDirEntry *ISO1FilesFind(U8 *files_find_mask,
|
||||
I64 fuf_flags,CDirEntry *parent=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CISO1DirEntry *buf,*buf2,*isoptr;
|
||||
I64 i,cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
CDirEntry *res=NULL,*tmpde;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
|
||||
RClusters(dv,isoptr,cur_dir_cluster,1);
|
||||
if (isoptr->name_len==1 && !isoptr->name) {//curdir
|
||||
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
|
||||
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
|
||||
RClusters(dv,buf,cur_dir_cluster,i);
|
||||
Free(isoptr);
|
||||
} else {
|
||||
buf=isoptr;
|
||||
i=1;
|
||||
}
|
||||
buf2=buf;
|
||||
i*=dv->spc<<BLK_SIZE_BITS;
|
||||
while (i>0) {
|
||||
if (!buf->len) {
|
||||
buf(U8 *)++;
|
||||
i--;
|
||||
} else {
|
||||
tmpde=MAlloc(sizeof(CDirEntry));
|
||||
if (ISO1CDirFill(tmpde,buf)) {
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=ISO1FilesFind(files_find_mask,fuf_flags,tmpde);
|
||||
Cd("..");
|
||||
}
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((tmpde->attr & RS_ATTR_DIR ||
|
||||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) &&
|
||||
*tmpde->name=='.' && tmpde->attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
i-=buf->len;
|
||||
buf(U8 *)+=buf->len;
|
||||
}
|
||||
}
|
||||
Free(buf2);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,637 @@
|
||||
// See $LK,"RedSea File System",A="FI:::/Doc/RedSea.DD"$
|
||||
|
||||
U0 RedSeaFreeFreeLst(CDrv *dv)
|
||||
{
|
||||
CFreeLst *tmpf,*tmpf1;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
if (tmpf=dv->next_free) {
|
||||
while (tmpf!=&dv->next_free) {
|
||||
tmpf1=tmpf->next;
|
||||
Free(tmpf);
|
||||
tmpf=tmpf1;
|
||||
}
|
||||
}
|
||||
dv->next_free=NULL;
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 RedSeaFreeLstBuild(CDrv *dv)
|
||||
{
|
||||
Bool unlock;
|
||||
CFreeLst *tmpf;
|
||||
I64 i,first=dv->data_area,max_blk=dv->size+dv->drv_offset;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
if (dv->next_free)
|
||||
RedSeaFreeFreeLst(dv);
|
||||
QueInit(&dv->next_free);
|
||||
while (first<max_blk) {
|
||||
i=0; //count free clusters
|
||||
while (first+i<max_blk) {
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
if (Bt(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1)))
|
||||
break;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (i) {
|
||||
tmpf=AMAlloc(sizeof(CFreeLst));
|
||||
tmpf->size=i;
|
||||
tmpf->start=first;
|
||||
QueIns(tmpf,dv->last_free);
|
||||
}
|
||||
first+=i+1;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 RedSeaInit(CDrv *dv)
|
||||
{
|
||||
CRedSeaBoot br;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
RBlks(dv,&br,dv->drv_offset,1);
|
||||
if (br.signature!=MBR_PT_REDSEA || br.signature2!=0xAA55)
|
||||
throw('Drv');
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaFreeFreeLst(dv);
|
||||
dv->spc=1;
|
||||
dv->size=br.sects;
|
||||
dv->data_area=dv->drv_offset+br.bitmap_sects;
|
||||
dv->root_cluster=br.root_cluster;
|
||||
dv->fat1=dv->fat2=dv->drv_offset+1;
|
||||
DrvFATBlkAlloc(dv);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
Bool RedSeaValidate(U8 drv_let)
|
||||
{
|
||||
CDrv *dv;
|
||||
CRedSeaBoot br;
|
||||
if ((dv=Let2Drv(drv_let,FALSE)) && dv->fs_type==FSt_REDSEA &&
|
||||
RBlks(dv,&br,dv->drv_offset,1) && br.signature==MBR_PT_REDSEA &&
|
||||
br.signature2==0xAA55 && br.sects==dv->size)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE)
|
||||
{
|
||||
U8 *root_dir;
|
||||
CDirEntry *d_native;
|
||||
CRedSeaBoot *br=CAlloc(BLK_SIZE);
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
I64 i,n,root_dir_blks;
|
||||
try {
|
||||
DrvLock(dv);
|
||||
// DrvTypeSet(drv_let,FSt_REDSEA);
|
||||
DrvTypeSet(drv_let,FSt_FAT32);
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
br->signature=MBR_PT_REDSEA;
|
||||
br->signature2=0xAA55;
|
||||
br->drv_offset=dv->drv_offset; //For CD/DVD image copy.
|
||||
br->sects=dv->size;
|
||||
n=(br->sects+BLK_SIZE<<3-1)/BLK_SIZE<<3;
|
||||
br->bitmap_sects=n;
|
||||
br->unique_id=GetTSC^Now()(U64);
|
||||
br->root_cluster=0;
|
||||
|
||||
if (quick)
|
||||
i=n+1;
|
||||
else
|
||||
i=dv->size;
|
||||
WZeroBlks(dv,dv->drv_offset,i);
|
||||
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
RedSeaInit(dv);
|
||||
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
|
||||
|
||||
root_dir_blks=MaxI64(1,dv->bd->init_root_dir_blks);
|
||||
br->root_cluster=ClustersAlloc(dv,0,root_dir_blks,FALSE);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
root_dir=CAlloc(BLK_SIZE*root_dir_blks);
|
||||
|
||||
d_native=root_dir-offset(CDirEntry.start);
|
||||
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
*d_native->name='.';
|
||||
d_native->cluster=br->root_cluster;
|
||||
d_native->size=BLK_SIZE*root_dir_blks;
|
||||
d_native->datetime=Now;
|
||||
|
||||
d_native(U8 *)+=CDIR_SIZE;
|
||||
|
||||
*d_native->name='.';
|
||||
d_native->name[1]='.';
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
d_native->cluster=br->root_cluster;
|
||||
d_native->datetime=Now;
|
||||
|
||||
WBlks(dv,root_dir,br->root_cluster,root_dir_blks);
|
||||
RedSeaInit(dv);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
Free(br);
|
||||
Free(root_dir);
|
||||
}
|
||||
|
||||
Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
CDirEntry *buf,*buf2,*ptr;
|
||||
U8 dname[CDIR_FILENAME_LEN];
|
||||
I64 ch;
|
||||
Bool res=FALSE,unlock;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (!CFileNameTo(dname,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED) &&
|
||||
!(fuf_flags&FUF_JUST_DIRS && !(ptr->attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && ptr->attr & RS_ATTR_DIR) &&
|
||||
!StrCmp(dname,ptr->name)) {
|
||||
MemCpy(&_res->attr,&ptr->attr,CDIR_SIZE);
|
||||
res=TRUE;
|
||||
goto rsff_done;
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
}
|
||||
rsff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *RedSeaFileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (RedSeaFileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
c=RBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool RedSeaCd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (RedSeaFileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 RedSeaFreeClusters(CDrv *dv,I64 c,I64 cnt)
|
||||
{
|
||||
CFreeLst *tmpf;
|
||||
Bool found=FALSE,unlock,unlock_break;
|
||||
DrvChk(dv);
|
||||
if (!c) return;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
if (!dv->next_free)
|
||||
RedSeaFreeLstBuild(dv);
|
||||
tmpf=dv->next_free;
|
||||
while (!found && tmpf!=&dv->next_free) {
|
||||
if (tmpf->start+tmpf->size==c) {
|
||||
tmpf->size+=cnt;
|
||||
found=TRUE;
|
||||
} else if (c+cnt==tmpf->start) {
|
||||
tmpf->size+=cnt;
|
||||
tmpf->start=c;
|
||||
found=TRUE;
|
||||
}
|
||||
tmpf=tmpf->next;
|
||||
}
|
||||
if (!found) {
|
||||
tmpf=AMAlloc(sizeof(CFreeLst));
|
||||
tmpf->size=cnt;
|
||||
tmpf->start=c;
|
||||
QueIns(tmpf,dv->last_free);
|
||||
}
|
||||
while (cnt-->0) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
LBtr(dv->cur_fat_blk,(c-dv->data_area)&(BLK_SIZE<<3-1));
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c++;
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
}
|
||||
|
||||
I64 RedSeaAllocClusters(CDrv *dv,I64 cnt)
|
||||
{
|
||||
CFreeLst *tmpf,*best_free=NULL;
|
||||
I64 i,first,best_size=I64_MAX;
|
||||
Bool unlock,unlock_break;
|
||||
if (cnt<=0)
|
||||
throw('Drv');
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
if (!dv->next_free)
|
||||
RedSeaFreeLstBuild(dv);
|
||||
tmpf=dv->next_free;
|
||||
while (tmpf!=&dv->next_free) {
|
||||
if (tmpf->size>=cnt && tmpf->size<best_size) {
|
||||
best_free=tmpf;
|
||||
best_size=tmpf->size;
|
||||
if (tmpf->size==cnt)
|
||||
break;
|
||||
}
|
||||
tmpf=tmpf->next;
|
||||
}
|
||||
if (!best_free)
|
||||
throw('Drv');
|
||||
first=best_free->start;
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
LBts(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1));
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
if (best_free->size-=cnt)
|
||||
best_free->start+=cnt;
|
||||
else {
|
||||
QueRem(best_free);
|
||||
Free(best_free);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
|
||||
{
|
||||
CDirEntry *buf,*buf2,*ptr,de2;
|
||||
CRedSeaBoot *br;
|
||||
I64 c,ch,i=1,j=0,n=BLK_SIZE/CDIR_SIZE,dir_size,cur_dir_cluster;
|
||||
Bool written=FALSE,unlock,unlock_break;
|
||||
U8 *tmp,*parent_dir;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
tmpde->attr|=RS_ATTR_CONTIGUOUS;
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
|
||||
dir_size=ptr->size;
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start)+CDIR_SIZE;
|
||||
Free(buf2);
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name)) {
|
||||
if (!written)
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
if ((i+1)*CDIR_SIZE+j<<BLK_SIZE_BITS<dir_size)
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
else {
|
||||
buf2=CAlloc(dir_size+BLK_SIZE);
|
||||
MemCpy(buf2,buf,dir_size);
|
||||
RedSeaFreeClusters(dv,cur_dir_cluster,dir_size>>BLK_SIZE_BITS);
|
||||
dir_size+=BLK_SIZE;
|
||||
c=ClustersAlloc(dv,0,dir_size>>BLK_SIZE_BITS,TRUE);
|
||||
Free(buf);
|
||||
buf=buf2;
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
ptr->size=dir_size;
|
||||
ptr->cluster=c;
|
||||
WBlks(dv,buf,c,dir_size>>BLK_SIZE_BITS);
|
||||
if (cur_dir_cluster==dv->root_cluster) {
|
||||
br=CAlloc(BLK_SIZE);
|
||||
RBlks(dv,br,dv->drv_offset,1);
|
||||
br->root_cluster=c;
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
Free(br);
|
||||
dv->root_cluster=c;
|
||||
} else {
|
||||
tmp=StrNew(cur_dir);
|
||||
parent_dir=StrNew(cur_dir);
|
||||
StrLastRem(parent_dir,"/",tmp);
|
||||
if (!*parent_dir) {
|
||||
Free(parent_dir);
|
||||
parent_dir=StrNew("/");
|
||||
}
|
||||
if (RedSeaFileFind(dv,Name2DirCluster(dv,parent_dir),
|
||||
tmp,&de2,FUF_JUST_DIRS)) {
|
||||
de2.cluster=c;
|
||||
de2.size=dir_size;
|
||||
RedSeaDirNew(dv,parent_dir,&de2,FALSE);
|
||||
} else
|
||||
throw('Drv');
|
||||
Free(tmp);
|
||||
Free(parent_dir);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (ptr->attr & RS_ATTR_DELETED) {
|
||||
if (!written) {
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
written=TRUE;
|
||||
}
|
||||
} else {
|
||||
if (!StrCmp(tmpde->name,ptr->name)) {
|
||||
if (free_old_chain)
|
||||
RedSeaFreeClusters(dv,ptr->cluster,
|
||||
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
|
||||
if (!written)
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
else
|
||||
ptr->attr|=RS_ATTR_DELETED;
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
if (++i>=n) {
|
||||
j++;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 RedSeaFilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
|
||||
Bool del_dir,Bool print_msg)
|
||||
{
|
||||
CDirEntry *buf,*buf2,*ptr;
|
||||
I64 i=0,res=0,ch,j=0,n=BLK_SIZE/CDIR_SIZE,cur_dir_cluster;
|
||||
Bool unlock_break;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED) && ch!='.' && (del_dir ||
|
||||
!(ptr->attr & RS_ATTR_DIR)) &&
|
||||
FilesFindMatch(ptr->name,files_find_mask,fuf_flags)) {
|
||||
if (!(ptr->attr & RS_ATTR_DIR)) res++;
|
||||
if (print_msg)
|
||||
"Del %s\n",ptr->name;
|
||||
ptr->attr|=RS_ATTR_DELETED;
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
RedSeaFreeClusters(dv,ptr->cluster,
|
||||
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
if (++i>=n) {
|
||||
j++;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 RedSeaFileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
|
||||
CDate cdt,I64 attr)
|
||||
{
|
||||
CDirEntry de;
|
||||
I64 c=0,blk_cnt;
|
||||
MemSet(&de,0,sizeof(CDirEntry));
|
||||
if (size<0) size=0;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (!CFileNameTo(de.name,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
RedSeaFilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
|
||||
de.size=size;
|
||||
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
|
||||
c=ClustersAlloc(dv,0,blk_cnt,TRUE); //Always contiguous
|
||||
else
|
||||
c=INVALID_CLUSTER;
|
||||
de.cluster=c;
|
||||
de.attr=attr|RS_ATTR_CONTIGUOUS;
|
||||
de.datetime=cdt;
|
||||
if (blk_cnt)
|
||||
WBlks(dv,buf,c,blk_cnt);
|
||||
RedSeaDirNew(dv,cur_dir,&de,TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
CDirEntry *RedSeaFilesFind(U8 *files_find_mask,I64 fuf_flags,
|
||||
CDirEntry *parent=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CDirEntry *buf,*buf2,*ptr,*res=NULL,*tmpde;
|
||||
I64 ch,cur_dir_cluster;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
ptr->cluster=Name2ParentDirCluster(dv,Fs->cur_dir);
|
||||
ptr(U8 *)-=CDIR_SIZE;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED)) {
|
||||
tmpde=CAlloc(sizeof(CDirEntry));
|
||||
MemCpy(&tmpde->start,&ptr->start,CDIR_SIZE);
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
DrvUnlock(dv);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=RedSeaFilesFind(files_find_mask,fuf_flags,tmpde);
|
||||
Cd("..");
|
||||
}
|
||||
DrvLock(dv);
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((tmpde->attr&RS_ATTR_DIR ||
|
||||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) && *tmpde->name=='.' &&
|
||||
tmpde->attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool RedSeaMkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
|
||||
{//entry_cnt is for preallocating dir blks.
|
||||
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
|
||||
size=CeilU64((entry_cnt+3)<<6,BLK_SIZE);
|
||||
#assert CDIR_SIZE==64
|
||||
U8 *buf=CAlloc(size);
|
||||
CDirEntry *d_native=buf-offset(CDirEntry.start);
|
||||
Bool unlock_break;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
StrCpy(d_native->name,name);
|
||||
d_native->cluster=c;
|
||||
d_native->size=size;
|
||||
d_native->datetime=Now;
|
||||
d_native(U8 *)+=CDIR_SIZE;
|
||||
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
*d_native->name='.';
|
||||
d_native->name[1]='.';
|
||||
d_native->name[2]=0;
|
||||
d_native->cluster=cur_dir_cluster;
|
||||
d_native->size=0;
|
||||
d_native->datetime=Now;
|
||||
WBlks(dv,buf,c,1);
|
||||
Free(buf);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#exe {Cd(__DIR__);};
|
||||
#include "DskStrA"
|
||||
#include "DskCache"
|
||||
#include "DskATA"
|
||||
#include "DskATAId"
|
||||
#include "DskBlkDev"
|
||||
#include "DskDrv"
|
||||
#include "DskBlk"
|
||||
#include "DskCluster"
|
||||
#include "DskStrB"
|
||||
#include "DskAddDev"
|
||||
#include "DskDirA"
|
||||
#include "FileSysISO"
|
||||
#include "FileSysRedSea"
|
||||
#include "FileSysFAT"
|
||||
#include "DskDirContext"
|
||||
#include "DskFind"
|
||||
#include "DskDirB"
|
||||
#include "DskFile"
|
||||
#include "DskCFile"
|
||||
#include "DskCopy"
|
||||
#include "DskCDDVD"
|
||||
#include "DskFmt"
|
||||
#exe {Cd("..");};
|
||||
@@ -0,0 +1,308 @@
|
||||
//See $LK,"::/Doc/Credits.DD"$.
|
||||
//See $LK,"CArcCompress",A="MN:CArcCompress"$, $LK,"CArcEntry",A="MN:CArcEntry"$, and $LK,"CArcCtrl",A="MN:CArcCtrl"$
|
||||
|
||||
asm {
|
||||
/****
|
||||
U0 ArcEntryGet(CArcCtrl *c)
|
||||
{
|
||||
I64 i;
|
||||
CArcEntry *tmp,*tmp1;
|
||||
|
||||
if (c->entry_used) {
|
||||
i=c->free_idx;
|
||||
|
||||
c->entry_used=FALSE;
|
||||
c->cur_entry=c->next_entry;
|
||||
c->cur_bits_in_use=c->next_bits_in_use;
|
||||
if (c->next_bits_in_use<ARC_BITS_MAX) {
|
||||
c->next_entry = &c->compress[i++];
|
||||
if (i==c->free_limit) {
|
||||
c->next_bits_in_use++;
|
||||
c->free_limit=1<<c->next_bits_in_use;
|
||||
}
|
||||
} else {
|
||||
do if (++i==c->free_limit)
|
||||
i=c->min_table_entry;
|
||||
while (c->hash[i]);
|
||||
tmp=&c->compress[i];
|
||||
c->next_entry=tmp;
|
||||
tmp1=&c->hash[tmp->basecode];
|
||||
while (tmp1) {
|
||||
if (tmp1->next==tmp) {
|
||||
tmp1->next=tmp->next;
|
||||
break;
|
||||
} else
|
||||
tmp1=tmp1->next;
|
||||
}
|
||||
}
|
||||
c->free_idx=i;
|
||||
}
|
||||
}
|
||||
****/
|
||||
_ARC_ENTRY_GET::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
BTR U64 CArcCtrl.entry_used[RSI],0
|
||||
JNC I32 @@30
|
||||
MOV RDX,U64 CArcCtrl.free_idx[RSI]
|
||||
MOV RAX,U64 CArcCtrl.next_entry[RSI]
|
||||
MOV U64 CArcCtrl.cur_entry[RSI],RAX
|
||||
MOV RCX,U64 CArcCtrl.next_bits_in_use[RSI]
|
||||
MOV U64 CArcCtrl.cur_bits_in_use[RSI],RCX
|
||||
CMP RCX,ARC_BITS_MAX
|
||||
JAE @@05
|
||||
MOV RAX,RDX
|
||||
SHL RAX,4
|
||||
LEA RAX,U64 CArcCtrl.compress[RSI+RAX]
|
||||
MOV U64 CArcCtrl.next_entry[RSI],RAX
|
||||
INC RDX
|
||||
CMP U64 CArcCtrl.free_limit[RSI],RDX
|
||||
JNE @@25
|
||||
INC RCX
|
||||
MOV U64 CArcCtrl.next_bits_in_use[RSI],RCX
|
||||
MOV RAX,1
|
||||
SHL RAX,CL
|
||||
MOV U64 CArcCtrl.free_limit[RSI],RAX
|
||||
JMP @@25
|
||||
@@05: INC RDX
|
||||
CMP U64 CArcCtrl.free_limit[RSI],RDX
|
||||
JNE @@10
|
||||
MOV RDX,U64 CArcCtrl.min_table_entry[RSI]
|
||||
@@10: MOV RAX,U64 CArcCtrl.hash[RSI+RDX*8]
|
||||
TEST RAX,RAX
|
||||
JNZ @@05
|
||||
MOV RDI,RDX
|
||||
SHL RDI,4
|
||||
LEA RDI,U64 CArcCtrl.compress[RSI+RDI]
|
||||
MOV U32 CArcCtrl.next_entry[RSI],EDI
|
||||
MOVZX RBX,U16 CArcEntry.basecode[RDI]
|
||||
LEA RCX,U64 CArcCtrl.hash[RSI+RBX*8]
|
||||
@@15: TEST RCX,RCX
|
||||
JZ @@25
|
||||
MOV RAX,U64 CArcEntry.next[RCX]
|
||||
CMP RDI,RAX
|
||||
JNE @@20
|
||||
MOV RAX,U64 CArcEntry.next[RDI]
|
||||
MOV U64 CArcEntry.next[RCX],RAX
|
||||
JMP @@25
|
||||
@@20: MOV RCX,RAX
|
||||
JMP @@15
|
||||
@@25: MOV U64 CArcCtrl.free_idx[RSI],RDX
|
||||
@@30: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
_extern _ARC_ENTRY_GET U0 ArcEntryGet(CArcCtrl *c);
|
||||
|
||||
I64 ArcDetermineCompressionType(U8 *src,I64 size)
|
||||
{
|
||||
while (size--)
|
||||
if (*src++&0x80)
|
||||
return CT_8_BIT;
|
||||
return CT_7_BIT;
|
||||
}
|
||||
|
||||
U0 ArcCompressBuf(CArcCtrl *c)
|
||||
{//Use $LK,"CompressBuf",A="MN:CompressBuf"$() unless doing more than one buf.
|
||||
CArcEntry *tmp,*tmp1;
|
||||
I64 ch,basecode;
|
||||
U8 *src_ptr,*src_limit;
|
||||
|
||||
src_ptr=c->src_buf+c->src_pos;
|
||||
src_limit=c->src_buf+c->src_size;
|
||||
|
||||
if (c->saved_basecode==U32_MAX)
|
||||
basecode=*src_ptr++;
|
||||
else
|
||||
basecode=c->saved_basecode;
|
||||
|
||||
while (src_ptr<src_limit && c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
|
||||
ArcEntryGet(c);
|
||||
ac_start:
|
||||
if (src_ptr>=src_limit) goto ac_done;
|
||||
ch=*src_ptr++;
|
||||
if (tmp=c->hash[basecode])
|
||||
do {
|
||||
if (tmp->ch==ch) {
|
||||
basecode=tmp-&c->compress[0];
|
||||
goto ac_start;
|
||||
}
|
||||
} while (tmp=tmp->next);
|
||||
|
||||
BFieldOrU32(c->dst_buf,c->dst_pos,basecode);
|
||||
c->dst_pos+=c->cur_bits_in_use;
|
||||
|
||||
c->entry_used=TRUE;
|
||||
tmp=c->cur_entry;
|
||||
tmp->basecode=basecode;
|
||||
tmp->ch=ch;
|
||||
tmp1=&c->hash[basecode];
|
||||
tmp->next=tmp1->next;
|
||||
tmp1->next=tmp;
|
||||
|
||||
basecode=ch;
|
||||
}
|
||||
ac_done:
|
||||
c->saved_basecode=basecode;
|
||||
c->src_pos=src_ptr-c->src_buf;
|
||||
}
|
||||
|
||||
Bool ArcFinishCompression(CArcCtrl *c)
|
||||
{//Do closing touch on archivew ctrl struct.
|
||||
if (c->dst_pos+c->cur_bits_in_use<=c->dst_size) {
|
||||
BFieldOrU32(c->dst_buf,c->dst_pos,c->saved_basecode);
|
||||
c->dst_pos+=c->next_bits_in_use;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 ArcExpandBuf(CArcCtrl *c)
|
||||
{//Use $LK,"ExpandBuf",A="MN:ExpandBuf"$() unless you know what you're doing.
|
||||
U8 *dst_ptr,*dst_limit;
|
||||
I64 basecode,lastcode,code;
|
||||
CArcEntry *tmp,*tmp1;
|
||||
|
||||
dst_ptr=c->dst_buf+c->dst_pos;
|
||||
dst_limit=c->dst_buf+c->dst_size;
|
||||
|
||||
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
|
||||
*dst_ptr++ = * -- c->stk_ptr;
|
||||
|
||||
if (c->stk_ptr==c->stk_base && dst_ptr<dst_limit) {
|
||||
if (c->saved_basecode==U32_MAX) {
|
||||
lastcode=BFieldExtU32(c->src_buf,c->src_pos,
|
||||
c->next_bits_in_use);
|
||||
c->src_pos+=c->next_bits_in_use;
|
||||
*dst_ptr++=lastcode;
|
||||
ArcEntryGet(c);
|
||||
c->last_ch=lastcode;
|
||||
} else
|
||||
lastcode=c->saved_basecode;
|
||||
while (dst_ptr<dst_limit && c->src_pos+c->next_bits_in_use<=c->src_size) {
|
||||
basecode=BFieldExtU32(c->src_buf,c->src_pos,
|
||||
c->next_bits_in_use);
|
||||
c->src_pos+=c->next_bits_in_use;
|
||||
if (c->cur_entry==&c->compress[basecode]) {
|
||||
*c->stk_ptr++=c->last_ch;
|
||||
code=lastcode;
|
||||
} else
|
||||
code=basecode;
|
||||
while (code>=c->min_table_entry) {
|
||||
*c->stk_ptr++=c->compress[code].ch;
|
||||
code=c->compress[code].basecode;
|
||||
}
|
||||
*c->stk_ptr++=code;
|
||||
c->last_ch=code;
|
||||
|
||||
c->entry_used=TRUE;
|
||||
tmp=c->cur_entry;
|
||||
tmp->basecode=lastcode;
|
||||
tmp->ch=c->last_ch;
|
||||
tmp1=&c->hash[lastcode];
|
||||
tmp->next=tmp1->next;
|
||||
tmp1->next=tmp;
|
||||
|
||||
ArcEntryGet(c);
|
||||
while (dst_ptr<dst_limit && c->stk_ptr!=c->stk_base)
|
||||
*dst_ptr++ = * -- c->stk_ptr;
|
||||
lastcode=basecode;
|
||||
}
|
||||
c->saved_basecode=lastcode;
|
||||
}
|
||||
c->dst_pos=dst_ptr-c->dst_buf;
|
||||
}
|
||||
|
||||
CArcCtrl *ArcCtrlNew(Bool expand,I64 compression_type=CT_8_BIT)
|
||||
{//MAlloc archive ctrl struct.
|
||||
CArcCtrl *c;
|
||||
c=CAlloc(sizeof(CArcCtrl));
|
||||
if (expand) {
|
||||
c->stk_base=MAlloc(1<<ARC_BITS_MAX);
|
||||
c->stk_ptr=c->stk_base;
|
||||
}
|
||||
if (compression_type==CT_7_BIT)
|
||||
c->min_bits=7;
|
||||
else
|
||||
c->min_bits=8;
|
||||
c->min_table_entry=1<<c->min_bits;
|
||||
c->free_idx=c->min_table_entry;
|
||||
c->next_bits_in_use=c->min_bits+1;
|
||||
c->free_limit=1<<c->next_bits_in_use;
|
||||
c->saved_basecode=U32_MAX;
|
||||
c->entry_used=TRUE;
|
||||
ArcEntryGet(c);
|
||||
c->entry_used=TRUE;
|
||||
return c;
|
||||
}
|
||||
|
||||
U0 ArcCtrlDel(CArcCtrl *c)
|
||||
{//Free archive ctrl struct.
|
||||
Free(c->stk_base);
|
||||
Free(c);
|
||||
}
|
||||
|
||||
U8 *ExpandBuf(CArcCompress *arc,CTask *mem_task=NULL)
|
||||
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
|
||||
CArcCtrl *c;
|
||||
U8 *res;
|
||||
|
||||
if (!(CT_NONE<=arc->compression_type<=CT_8_BIT) ||
|
||||
arc->expanded_size>mem_mapped_space)
|
||||
throw('Compress');
|
||||
|
||||
res=MAlloc(arc->expanded_size+1,mem_task);
|
||||
res[arc->expanded_size]=0; //terminate
|
||||
switch [arc->compression_type] {
|
||||
case CT_NONE:
|
||||
MemCpy(res,&arc->body,arc->expanded_size);
|
||||
break;
|
||||
case CT_7_BIT:
|
||||
case CT_8_BIT:
|
||||
c=ArcCtrlNew(TRUE,arc->compression_type);
|
||||
c->src_size=arc->compressed_size<<3;
|
||||
c->src_pos=sizeof(CArcCompress)<<3;
|
||||
c->src_buf=arc;
|
||||
c->dst_size=arc->expanded_size;
|
||||
c->dst_buf=res;
|
||||
c->dst_pos=0;
|
||||
ArcExpandBuf(c);
|
||||
ArcCtrlDel(c);
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL)
|
||||
{//See $LK,"::/Demo/Dsk/SerializeTree.HC"$.
|
||||
CArcCompress *arc;
|
||||
I64 size_out,compression_type=ArcDetermineCompressionType(src,size);
|
||||
CArcCtrl *c=ArcCtrlNew(FALSE,compression_type);
|
||||
c->src_size=size;
|
||||
c->src_buf=src;
|
||||
c->dst_size=(size+sizeof(CArcCompress))<<3;
|
||||
c->dst_buf=CAlloc(c->dst_size>>3);
|
||||
c->dst_pos=sizeof(CArcCompress)<<3;
|
||||
ArcCompressBuf(c);
|
||||
if (ArcFinishCompression(c) && c->src_pos==c->src_size) {
|
||||
size_out=(c->dst_pos+7)>>3;
|
||||
arc=MAlloc(size_out,mem_task);
|
||||
MemCpy(arc,c->dst_buf,size_out);
|
||||
arc->compression_type=compression_type;
|
||||
arc->compressed_size=size_out;
|
||||
} else {
|
||||
arc=MAlloc(size+sizeof(CArcCompress),mem_task);
|
||||
MemCpy(&arc->body,src,size);
|
||||
arc->compression_type=CT_NONE;
|
||||
arc->compressed_size=size+sizeof(CArcCompress);
|
||||
}
|
||||
arc->expanded_size=size;
|
||||
Free(c->dst_buf);
|
||||
ArcCtrlDel(c);
|
||||
return arc;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
U0 RawPutChar(I64 ch)
|
||||
{/*For RAW output during boot and in debugger.
|
||||
|
||||
See $LK,"GrUpdateTextFG",A="MN:GrUpdateTextFG"$ for
|
||||
the normal scrn text output routine.
|
||||
|
||||
See also $LK,"GrUpdateScrn",A="MN:GrUpdateScrn"$().
|
||||
*/
|
||||
I64 i,row,col;
|
||||
U8 *ptr,*ptr1,*ptr2;
|
||||
|
||||
if (!(text.raw_flags&RWF_SHOW_DOLLAR)) {
|
||||
if (ch=='$$') {
|
||||
if (text.raw_flags&RWF_IN_DOLLAR) {
|
||||
text.raw_flags&=~RWF_IN_DOLLAR;
|
||||
if (!(text.raw_flags & RWF_LAST_DOLLAR)) {
|
||||
text.raw_flags&=~RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
text.raw_flags|=RWF_IN_DOLLAR|RWF_LAST_DOLLAR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
text.raw_flags&=~RWF_LAST_DOLLAR;
|
||||
if (text.raw_flags&RWF_IN_DOLLAR)
|
||||
return;
|
||||
}
|
||||
if (ch=='\t') {
|
||||
RawPutChar(CH_SPACE);
|
||||
while (text.raw_col & 7)
|
||||
RawPutChar(CH_SPACE);
|
||||
} else if (ch==CH_BACKSPACE) {
|
||||
text.raw_col--;
|
||||
RawPutChar(CH_SPACE);
|
||||
text.raw_col--;
|
||||
} else if (ch=='\n') {
|
||||
RawPutChar(CH_SPACE);
|
||||
while (text.raw_col % text.cols)
|
||||
RawPutChar(CH_SPACE);
|
||||
|
||||
} else if (Bt(char_bmp_displayable,ch)) {
|
||||
row=text.raw_col/text.cols%text.rows;
|
||||
col=text.raw_col%text.cols;
|
||||
if (!Bt(&sys_run_level,RLf_VGA)) { //if text mode
|
||||
if (text.raw_flags&RWF_SCROLL && text.raw_col && !row && !col) {
|
||||
MemCpy(text.vga_text_alias,text.vga_text_alias+text.cols*2,
|
||||
text.cols*(text.rows-1)*2);
|
||||
MemSet(text.vga_text_alias+text.cols*(text.rows-1)*2,0,text.cols*2);
|
||||
text.raw_col-=text.cols;
|
||||
row=text.rows-1;
|
||||
}
|
||||
ptr=text.vga_text_alias+(row*text.cols+col)*2;
|
||||
ptr[0]=ch;
|
||||
ptr[1]=BLACK<<4+WHITE;
|
||||
} else {
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,0x0F); //All planes -- WHITE
|
||||
if (text.raw_flags&RWF_SCROLL && text.raw_col && !row && !col) {
|
||||
//Scroll cached image
|
||||
MemCpy(text.raw_scrn_image,
|
||||
text.raw_scrn_image+GR_WIDTH*FONT_HEIGHT>>3,
|
||||
GR_WIDTH*(GR_HEIGHT-FONT_HEIGHT)>>3);
|
||||
MemSet(text.raw_scrn_image+GR_WIDTH*(GR_HEIGHT-FONT_HEIGHT)>>3,0,
|
||||
GR_WIDTH*FONT_HEIGHT>>3);
|
||||
|
||||
MemCpy(text.vga_alias,text.raw_scrn_image,GR_WIDTH*GR_HEIGHT>>3);
|
||||
text.raw_col-=text.cols;
|
||||
row=text.rows-1;
|
||||
}
|
||||
PUSHFD
|
||||
CLI
|
||||
ptr=ptr1=col+row*GR_WIDTH*FONT_HEIGHT>>3;
|
||||
ptr+=text.vga_alias;
|
||||
ptr1+=text.raw_scrn_image; //Write to cached image as well
|
||||
ptr2=&text.font[ch&255];
|
||||
for (i=0;i<FONT_HEIGHT;i++) {
|
||||
*ptr=*ptr1=rev_bits_table[*ptr2++];
|
||||
ptr+=GR_WIDTH>>3;
|
||||
ptr1+=GR_WIDTH>>3;
|
||||
}
|
||||
POPFD
|
||||
}
|
||||
text.raw_col++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 VGAFlush()
|
||||
{//Flush winmgr vga cache, so updates whole scrn.
|
||||
LBts(&sys_semas[SEMA_FLUSH_VGA_IMAGE],0);
|
||||
}
|
||||
|
||||
U0 WinDerivedValsUpdate(CTask *task)
|
||||
{//Those things calculated from other variables.
|
||||
if (!task) task=Fs;
|
||||
//Assert: This is called with TASKf_TASK_LOCK set
|
||||
PUSHFD
|
||||
CLI
|
||||
task->win_width =task->win_right-task->win_left+1;
|
||||
task->win_height=task->win_bottom-task->win_top+1;
|
||||
task->pix_left =FONT_WIDTH*task->win_left;
|
||||
task->pix_right =FONT_WIDTH*(task->win_right+1)-1;
|
||||
task->pix_width =task->pix_right-task->pix_left+1;
|
||||
task->pix_top =FONT_HEIGHT*task->win_top;
|
||||
task->pix_bottom =FONT_HEIGHT*(task->win_bottom+1)-1;
|
||||
task->pix_height =task->pix_bottom-task->pix_top+1;
|
||||
POPFD
|
||||
}
|
||||
|
||||
Bool WinInside(I64 x,I64 y,CTask *task=NULL,I64 border=0)
|
||||
{//Is pixel (x,y) inside task's win? Border to FONT_WIDTH.
|
||||
if (!task) task=Fs;
|
||||
if (TaskValidate(task) && Bt(&task->display_flags,DISPLAYf_SHOW)) {
|
||||
if (Bt(&task->display_flags,DISPLAYf_NO_BORDER))
|
||||
border=0;
|
||||
if (task->pix_left-border<=x<=task->pix_right+border &&
|
||||
task->pix_top-border<=y<=task->pix_bottom+border)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
class CLine
|
||||
{
|
||||
CLine *next,*last;
|
||||
U8 *line;
|
||||
};
|
||||
|
||||
U0 EdLiteUpdate(CLine *head,CLine *cur_line,I64 cur_col,I64 line_start_col)
|
||||
{
|
||||
I64 ch,i,j,k,k2,cursor_col,cursor_row=-1;
|
||||
U8 *st;
|
||||
CLine *tmpl=cur_line;
|
||||
Bool done_eof=FALSE;
|
||||
text.raw_col=0;
|
||||
for (i=0;i<text.rows/2;i++)
|
||||
if (tmpl->last!=head)
|
||||
tmpl=tmpl->last;
|
||||
for (i=0;i<text.rows;i++) {
|
||||
if (cursor_row<0 && tmpl==cur_line) {
|
||||
k=0;
|
||||
for (j=0;j<cur_col;j++)
|
||||
if (tmpl->line[j]=='\t')
|
||||
k=(k+8)&~7;
|
||||
else
|
||||
k++;
|
||||
cursor_col=k;
|
||||
cursor_row=i;
|
||||
}
|
||||
if (tmpl!=head) {
|
||||
st=tmpl->line;
|
||||
k=0;
|
||||
j=0;
|
||||
while (ch=*st++) {
|
||||
if (ch=='\t')
|
||||
k2=(k+8)&~7;
|
||||
else
|
||||
k2=k+1;
|
||||
if (line_start_col<=k<line_start_col+text.cols) {
|
||||
'' ch;
|
||||
j=k2-line_start_col;
|
||||
}
|
||||
k=k2;
|
||||
}
|
||||
if (j<text.cols)
|
||||
'\n';
|
||||
tmpl=tmpl->next;
|
||||
} else {
|
||||
if (!done_eof) {
|
||||
'<EOF>';
|
||||
done_eof=TRUE;
|
||||
}
|
||||
'\n';
|
||||
}
|
||||
}
|
||||
text.raw_col=text.cols*cursor_row+cursor_col-line_start_col;
|
||||
RawPutChar(0x7F);
|
||||
}
|
||||
|
||||
Bool EdLite(U8 *filename,I64 num=1,I64 edf_dof_flags=0)
|
||||
{//Light weight text editor for debugging.
|
||||
U8 *src,*src2,*src3,*dst,*buf,*bin_data=NULL;
|
||||
I64 i,cnt=0,ch,sc,size,bin_size=0,line_start_col=0,cur_col=0,
|
||||
old_raw_flags=text.raw_flags;
|
||||
CLine head,*tmpl,*tmpl1,*cur_line;
|
||||
Bool res=FALSE,
|
||||
old_raw=Raw(ON),
|
||||
old_debug=DbgMode(ON),
|
||||
old_single=SingleUser(ON);
|
||||
|
||||
if (!filename) filename=blkdev.tmp_filename;
|
||||
buf=FileRead(filename,&size);
|
||||
|
||||
PUSHFD
|
||||
CLI
|
||||
text.raw_flags=text.raw_flags&~RWF_SCROLL|RWF_SHOW_DOLLAR;
|
||||
kbd.scan_code=0;
|
||||
QueInit(&head);
|
||||
head.line=StrNew("");
|
||||
|
||||
if (buf) {
|
||||
src=buf;
|
||||
while (*src) {
|
||||
src2=src;
|
||||
while ((ch=*src++) && ch!='\r' && ch!='\n');
|
||||
src--;
|
||||
*src++=0;
|
||||
if (!ch)
|
||||
src--;
|
||||
while (ch=='\r' && *src=='\n' || *src==CH_CURSOR)
|
||||
src++;
|
||||
dst=src3=src2;
|
||||
while (ch=*src3++)
|
||||
if (ch!='\n' && ch!=CH_CURSOR)
|
||||
*dst++=ch;
|
||||
*dst=0;
|
||||
|
||||
tmpl=MAlloc(sizeof(CLine));
|
||||
tmpl->line=StrNew(src2);
|
||||
QueIns(tmpl,head.last);
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (src+1-buf<size) {
|
||||
bin_data=MAlloc(bin_size=size-(src-buf));
|
||||
MemCpy(bin_data,src,bin_size);
|
||||
}
|
||||
Free(buf);
|
||||
res=TRUE;
|
||||
}
|
||||
|
||||
cur_line=head.next;
|
||||
if (--num<0)
|
||||
res=FALSE;
|
||||
else {
|
||||
if (num<=cnt)
|
||||
while (num--)
|
||||
cur_line=cur_line->next;
|
||||
else {
|
||||
cur_line=&head;
|
||||
res=FALSE;
|
||||
}
|
||||
}
|
||||
do {
|
||||
if (cur_line==&head)
|
||||
cur_col=0;
|
||||
while (cur_col-line_start_col<0)
|
||||
line_start_col-=8;
|
||||
while (cur_col-line_start_col>=text.cols)
|
||||
line_start_col+=8;
|
||||
EdLiteUpdate(&head,cur_line,cur_col,line_start_col);
|
||||
switch (ch=GetKey(&sc,FALSE,TRUE)) {
|
||||
case 0:
|
||||
switch (sc.u8[0]) {
|
||||
case SC_CURSOR_UP:
|
||||
if (cur_line->last!=&head)
|
||||
cur_line=cur_line->last;
|
||||
if (cur_col>StrLen(cur_line->line))
|
||||
cur_col=StrLen(cur_line->line);
|
||||
break;
|
||||
case SC_CURSOR_DOWN:
|
||||
if (cur_line!=&head)
|
||||
cur_line=cur_line->next;
|
||||
if (cur_col>StrLen(cur_line->line))
|
||||
cur_col=StrLen(cur_line->line);
|
||||
break;
|
||||
case SC_CURSOR_RIGHT:
|
||||
cur_col++;
|
||||
if (cur_col>StrLen(cur_line->line)) {
|
||||
tmpl=cur_line->next;
|
||||
if (tmpl!=&head) {
|
||||
cur_col=0;
|
||||
cur_line=tmpl;
|
||||
} else
|
||||
cur_col=StrLen(cur_line->line);
|
||||
}
|
||||
break;
|
||||
case SC_CURSOR_LEFT:
|
||||
if (cur_col)
|
||||
cur_col--;
|
||||
else {
|
||||
tmpl=cur_line->last;
|
||||
if (tmpl!=&head) {
|
||||
cur_line=tmpl;
|
||||
cur_col=StrLen(tmpl->line);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SC_PAGE_UP:
|
||||
for (i=1;i<text.rows;i++) {
|
||||
if (cur_line->last!=&head)
|
||||
cur_line=cur_line->last;
|
||||
if (cur_col>StrLen(cur_line->line))
|
||||
cur_col=StrLen(cur_line->line);
|
||||
}
|
||||
break;
|
||||
case SC_PAGE_DOWN:
|
||||
for (i=1;i<text.rows;i++) {
|
||||
if (cur_line!=&head)
|
||||
cur_line=cur_line->next;
|
||||
if (cur_col>StrLen(cur_line->line))
|
||||
cur_col=StrLen(cur_line->line);
|
||||
}
|
||||
break;
|
||||
case SC_DELETE:
|
||||
if (cur_col==StrLen(cur_line->line)) {
|
||||
tmpl=cur_line->next;
|
||||
if (cur_line!=&head && tmpl!=&head) {
|
||||
src=MStrPrint("%s%s",cur_line->line,tmpl->line);
|
||||
Free(cur_line->line);
|
||||
Free(tmpl->line);
|
||||
cur_line->line=src;
|
||||
QueRem(tmpl);
|
||||
Free(tmpl);
|
||||
}
|
||||
} else
|
||||
StrCpy(cur_line->line+cur_col,cur_line->line+cur_col+1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
tmpl=MAlloc(sizeof(CLine));
|
||||
tmpl->line=StrNew(cur_line->line+cur_col);
|
||||
cur_line->line[cur_col]=0;
|
||||
QueIns(tmpl,cur_line);
|
||||
cur_line=tmpl;
|
||||
cur_col=0;
|
||||
break;
|
||||
case CH_BACKSPACE:
|
||||
if (cur_col) {
|
||||
StrCpy(cur_line->line+cur_col-1,cur_line->line+cur_col);
|
||||
cur_col--;
|
||||
} else if (cur_line!=&head && cur_line->last!=&head) {
|
||||
tmpl=cur_line->last;
|
||||
src=MStrPrint("%s%s",tmpl->line,cur_line->line);
|
||||
cur_col=StrLen(tmpl->line);
|
||||
Free(cur_line->line);
|
||||
Free(tmpl->line);
|
||||
tmpl->line=src;
|
||||
QueRem(cur_line);
|
||||
Free(cur_line);
|
||||
cur_line=tmpl;
|
||||
}
|
||||
break;
|
||||
case CH_CTRLY:
|
||||
if (cur_line!=&head) {
|
||||
tmpl=cur_line;
|
||||
cur_line=cur_line->next;
|
||||
QueRem(tmpl);
|
||||
Free(tmpl->line);
|
||||
Free(tmpl);
|
||||
cur_col=0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (Bt(char_bmp_printable,ch)) {
|
||||
if (cur_line==&head) {
|
||||
cur_line=MAlloc(sizeof(CLine));
|
||||
cur_line->line=StrNew("");
|
||||
QueIns(cur_line,head.last);
|
||||
}
|
||||
src=MAlloc(StrLen(cur_line->line)+2);
|
||||
MemCpy(src,cur_line->line,cur_col);
|
||||
src[cur_col]=ch;
|
||||
if (cur_col<StrLen(cur_line->line))
|
||||
StrCpy(src+cur_col+1,cur_line->line+cur_col);
|
||||
else
|
||||
src[cur_col+1]=0;
|
||||
Free(cur_line->line);
|
||||
cur_line->line=src;
|
||||
cur_col++;
|
||||
}
|
||||
}
|
||||
} while (ch!=CH_SHIFT_ESC && ch!=CH_ESC);
|
||||
|
||||
if (ch!=CH_ESC) {
|
||||
if (edf_dof_flags&EDF_WAS_WRITE)
|
||||
res=FALSE;
|
||||
} else {
|
||||
size=bin_size;
|
||||
|
||||
tmpl=head.next;
|
||||
while (tmpl!=&head) {
|
||||
size+=StrLen(tmpl->line)+1;
|
||||
tmpl=tmpl->next;
|
||||
}
|
||||
|
||||
buf=dst=MAlloc(size);
|
||||
tmpl=head.next;
|
||||
while (tmpl!=&head) {
|
||||
i=StrLen(tmpl->line);
|
||||
MemCpy(dst,tmpl->line,i);
|
||||
dst+=i;
|
||||
*dst++='\n';
|
||||
tmpl=tmpl->next;
|
||||
}
|
||||
if (bin_data)
|
||||
MemCpy(dst,bin_data,bin_size);
|
||||
FileWrite(filename,buf,size);
|
||||
Free(buf);
|
||||
|
||||
if (edf_dof_flags&EDF_WAS_WRITE)
|
||||
res=TRUE;
|
||||
}
|
||||
|
||||
tmpl=head.next;
|
||||
while (tmpl!=&head) {
|
||||
tmpl1=tmpl->next;
|
||||
QueRem(tmpl);
|
||||
Free(tmpl->line);
|
||||
Free(tmpl);
|
||||
tmpl=tmpl1;
|
||||
}
|
||||
Free(head.line);
|
||||
Free(bin_data);
|
||||
Raw(old_raw);
|
||||
DbgMode(old_debug);
|
||||
SingleUser(old_single);
|
||||
text.raw_flags=text.raw_flags&~RWF_SHOW_DOLLAR|old_raw_flags&RWF_SHOW_DOLLAR;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 ToFileLine(U8 *_fl_file_line,U8 **_filename,I64 *_linenum)
|
||||
{//"FI:D:/Dir/File.HC,123" to "D:/Dir/File.HC" and 123.
|
||||
U8 *st,*fl_file_line=StrNew(_fl_file_line);
|
||||
I64 linenum;
|
||||
StrFirstRem(fl_file_line,":");
|
||||
st=StrNew(fl_file_line);
|
||||
StrLastRem(fl_file_line,",",st);
|
||||
linenum=Str2I64(st);
|
||||
Free(st);
|
||||
*_filename=fl_file_line;
|
||||
*_linenum=linenum;
|
||||
}
|
||||
|
||||
Bool EdLiteFileLine(U8 *fl_file_line,I64 edf_dof_flags=0)
|
||||
{
|
||||
Bool res;
|
||||
U8 *filename;
|
||||
I64 linenum;
|
||||
ToFileLine(fl_file_line,&filename,&linenum);
|
||||
res=EdLite(filename,linenum,edf_dof_flags);
|
||||
Free(filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 FixSet(U8 *filename,I64 line)
|
||||
{//Compiler calls this to set file line for Fix
|
||||
U8 *st=MStrPrint("FL:%s,%d",filename,line);
|
||||
while (LBts(&sys_semas[SEMA_FIX],0))
|
||||
Yield;
|
||||
Free(dbg.fix_file_line);
|
||||
dbg.fix_file_line=AStrNew(st);
|
||||
LBtr(&sys_semas[SEMA_FIX],0);
|
||||
}
|
||||
|
||||
Bool Fix(I64 edf_dof_flags=0)
|
||||
{//Jump to last err src code to fix it.
|
||||
U8 *st;
|
||||
Bool res=FALSE;
|
||||
|
||||
while (LBts(&sys_semas[SEMA_FIX],0))
|
||||
Yield;
|
||||
st=StrNew(dbg.fix_file_line);
|
||||
LBtr(&sys_semas[SEMA_FIX],0);
|
||||
|
||||
if (st) {
|
||||
if (IsRaw)
|
||||
res=EdLiteFileLine(st,edf_dof_flags);
|
||||
else
|
||||
res=Ed(st,edf_dof_flags);
|
||||
}
|
||||
Free(st);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
//See $LK,"::/Doc/Credits.DD"$.
|
||||
|
||||
U64 sys_font_cyrillic[256]= {
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x000000FF00000000,0x000000FF00FF0000,//ÄÍ
|
||||
0x1818181818181818,0x6C6C6C6C6C6C6C6C,//³º
|
||||
0x181818F800000000,0x6C6C6CEC0CFC0000,//ÚÉ
|
||||
0x1818181F00000000,0x6C6C6C6F607F0000,//¿»
|
||||
0x000000F818181818,0x000000FC0CEC6C6C,//ÀÈ
|
||||
0x0000001F18181818,0x0000007F606F6C6C,//Ù¼
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0008000000000000,//
|
||||
0x0000000000000000,0x00180018183C3C18,// !
|
||||
0x0000000000363636,0x006C6CFE6CFE6C6C,//"#
|
||||
0x00187ED07C16FC30,0x0060660C18306606,//$$%
|
||||
0x00DC66B61C36361C,0x0000000000181818,//&'
|
||||
0x0030180C0C0C1830,0x000C18303030180C,//()
|
||||
0x0000187E3C7E1800,0x000018187E181800,//*+
|
||||
0x0C18180000000000,0x000000007E000000,//,-
|
||||
0x0018180000000000,0x0000060C18306000,//./
|
||||
0x003C666E7E76663C,0x007E181818181C18,//01
|
||||
0x007E0C183060663C,0x003C66603860663C,//23
|
||||
0x0030307E363C3830,0x003C6660603E067E,//45
|
||||
0x003C66663E060C38,0x000C0C0C1830607E,//67
|
||||
0x003C66663C66663C,0x001C30607C66663C,//89
|
||||
0x0018180018180000,0x0C18180018180000,//:;
|
||||
0x0030180C060C1830,0x0000007E007E0000,//<=
|
||||
0x000C18306030180C,0x001800181830663C,//>?
|
||||
0x003C06765676663C,0x006666667E66663C,//@A
|
||||
0x003E66663E66663E,0x003C66060606663C,//BC
|
||||
0x001E36666666361E,0x007E06063E06067E,//DE
|
||||
0x000606063E06067E,0x003C66667606663C,//FG
|
||||
0x006666667E666666,0x007E18181818187E,//HI
|
||||
0x001C36303030307C,0x0066361E0E1E3666,//JK
|
||||
0x007E060606060606,0x00C6C6D6D6FEEEC6,//LM
|
||||
0x006666767E6E6666,0x003C66666666663C,//NO
|
||||
0x000606063E66663E,0x006C36566666663C,//PQ
|
||||
0x006666363E66663E,0x003C66603C06663C,//RS
|
||||
0x001818181818187E,0x003C666666666666,//TU
|
||||
0x00183C6666666666,0x00C6EEFED6D6C6C6,//VW
|
||||
0x0066663C183C6666,0x001818183C666666,//XY
|
||||
0x007E060C1830607E,0x003E06060606063E,//Z[
|
||||
0x00006030180C0600,0x007C60606060607C,//\]
|
||||
0x000000000000663C,0xFFFF000000000000,//^_
|
||||
0x000000000030180C,0x007C667C603C0000,//`a
|
||||
0x003E6666663E0606,0x003C6606663C0000,//bc
|
||||
0x007C6666667C6060,0x003C067E663C0000,//de
|
||||
0x000C0C0C3E0C0C38,0x3C607C66667C0000,//fg
|
||||
0x00666666663E0606,0x003C1818181C0018,//hi
|
||||
0x0E181818181C0018,0x0066361E36660606,//jk
|
||||
0x003C18181818181C,0x00C6D6D6FE6C0000,//lm
|
||||
0x00666666663E0000,0x003C6666663C0000,//no
|
||||
0x06063E66663E0000,0xE0607C66667C0000,//pq
|
||||
0x000606066E360000,0x003E603C067C0000,//rs
|
||||
0x00380C0C0C3E0C0C,0x007C666666660000,//tu
|
||||
0x00183C6666660000,0x006CFED6D6C60000,//vw
|
||||
0x00663C183C660000,0x3C607C6666660000,//xy
|
||||
0x007E0C18307E0000,0x003018180E181830,//z{
|
||||
0x0018181818181818,0x000C18187018180C,//|}
|
||||
0x000000000062D68C,0xFFFFFFFFFFFFFFFF,//~
|
||||
0x1E30181E3303331E,0x007E333333003300,//€�
|
||||
0x001E033F331E0038,0x00FC667C603CC37E,//‚ƒ
|
||||
0x007E333E301E0033,0x007E333E301E0007,//„…
|
||||
0x007E333E301E0C0C,0x3C603E03033E0000,//†‡
|
||||
0x003C067E663CC37E,0x001E033F331E0033,//ˆ‰
|
||||
0x001E033F331E0007,0x001E0C0C0C0E0033,//Š‹
|
||||
0x003C1818181C633E,0x001E0C0C0C0E0007,//Œ�
|
||||
0x00333F33331E0C33,0x00333F331E000C0C,//�
|
||||
0x003F061E063F0038,0x00FE33FE30FE0000,//�‘
|
||||
0x007333337F33367C,0x001E33331E00331E,//’“
|
||||
0x001E33331E003300,0x001E33331E000700,//”•
|
||||
0x007E33333300331E,0x007E333333000700,//–—
|
||||
0x1F303F3333003300,0x001C3E63633E1C63,//˜™
|
||||
0x001E333333330033,0x18187E03037E1818,//š›
|
||||
0x003F67060F26361C,0x000C3F0C3F1E3333,//œ�
|
||||
0x70337B332F1B1B0F,0x0E1B18187E18D870,//žŸ
|
||||
0x000F11110F01111F,0x000101010101111F,// ¡
|
||||
0x000F0107010F000A,0x001515150E151515,//¢£
|
||||
0x000F10100E10100F,0x0011111315191111,//¤¥
|
||||
0x001113151911040A,0x001215141414141E,//¦§
|
||||
0x001111111111111F,0x000102040A111111,//¨©
|
||||
0x00040E1515150E04,0x001010101E111111,//ª«
|
||||
0x001F151515151515,0x000E12120E020203,//¬
|
||||
0x0013151513111111,0x000E11101C10110E,//®¯
|
||||
0x0009151517151509,0x001112141E11111E,//°±
|
||||
0x000E11110F010618,0x0007090709070000,//²³
|
||||
0x00010101111F0000,0x000E011F110E000A,//´µ
|
||||
0x0015150E15150000,0x000F100C100F0000,//¶·
|
||||
0x0011131519110000,0x0013151911040A00,//¸¹
|
||||
0x0009050305090000,0x00121514141E0000,//º»
|
||||
0x001111151B110000,0x0011111F11110000,//¼½
|
||||
0x00111111111F0000,0x00040404041F0000,//¾¿
|
||||
0x0010101E11110000,0x001F151515150000,//ÀÁ
|
||||
0x000E120E02030000,0x0013151311110000,//ÂÃ
|
||||
0x0007090701010000,0x000E111C110E0000,//ÄÅ
|
||||
0x0009151715090000,0x0012141E111E0000,//ÆÇ
|
||||
0x0004120912040000,0x0004091209040000,//ÈÉ
|
||||
0x001B091200000000,0x000000000009121B,//ÊË
|
||||
0x001C141C090D0B09,0x000E110102040004,//ÌÍ
|
||||
0x000304040E040418,0x001E02020F020A04,//ÎÏ
|
||||
0x0004040000000000,0x0004040404000000,//ÐÑ
|
||||
0x000E000A0A0A0000,0x000A000A0A0A0000,//ÒÓ
|
||||
0x0001020408170005,0x00001B0E040E1B00,//ÔÕ
|
||||
0x0001020408150205,0x00000E040404040E,//Ö×
|
||||
0x00001F0A0A0A0A1F,0x0004040404150E04,//ØÙ
|
||||
0x00040E1504040404,0x0001090D1F0D0901,//ÚÛ
|
||||
0x001012161F161210,0x000111151F151101,//ÜÝ
|
||||
0x0001020408110701,0x000000000C0C0000,//Þß
|
||||
0x111F11121414141E,0x101F111111111111,//àá
|
||||
0x101F151515151515,0x111F1112141E0000,//âã
|
||||
0x040E15150E040400,0x101A111111110000,//äå
|
||||
0x101F151515150000,0x0000000000000408,//æç
|
||||
0x000000000000000A,0x0000000000000D12,//èé
|
||||
0x000E011F110E0408,0x06040E11010E0000,//êë
|
||||
0x0006080A0A0A000A,0x0000041F0E0E0E04,//ìí
|
||||
0x00000A0011000A00,0x00000E1111110E00,//îï
|
||||
0x0010101D1A150911,0x001C1019121D0911,//ðñ
|
||||
0x001C0419121D0911,0x10101C1B12030203,//òó
|
||||
0x00111F111F111F11,0x0000000600180003,//ôõ
|
||||
0x041E141015070502,0x07020E021E020E02,//ö÷
|
||||
0x0E040E041F040E04,0x1C08160017001600,//øù
|
||||
0x1C080E080F080E08,0x00040E041F040E04,//úû
|
||||
0x1C08090A0C0A0908,0x0609040A0A04120C,//üý
|
||||
0x001414141E15151E,0xFFFFFFFFFFFFFFFF,//þÿ
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
//See $LK,"::/Doc/Credits.DD"$.
|
||||
|
||||
U64 sys_font_std[256]= {
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x000000FF00000000,0x000000FF00FF0000,//騵
|
||||
0x1818181818181818,0x6C6C6C6C6C6C6C6C,//竟
|
||||
0x181818F800000000,0x6C6C6CEC0CFC0000,//硭
|
||||
0x1818181F00000000,0x6C6C6C6F607F0000,//蕃
|
||||
0x000000F818181818,0x000000FC0CEC6C6C,//檀
|
||||
0x0000001F18181818,0x0000007F606F6C6C,//椇
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0000000000000000,
|
||||
0x0000000000000000,0x0008000000000000,//
|
||||
0x0000000000000000,0x00180018183C3C18,// !
|
||||
0x0000000000363636,0x006C6CFE6CFE6C6C,//"#
|
||||
0x00187ED07C16FC30,0x0060660C18306606,//$$%
|
||||
0x00DC66B61C36361C,0x0000000000181818,//&'
|
||||
0x0030180C0C0C1830,0x000C18303030180C,//()
|
||||
0x0000187E3C7E1800,0x000018187E181800,//*+
|
||||
0x0C18180000000000,0x000000007E000000,//,-
|
||||
0x0018180000000000,0x0000060C18306000,//./
|
||||
0x003C666E7E76663C,0x007E181818181C18,//01
|
||||
0x007E0C183060663C,0x003C66603860663C,//23
|
||||
0x0030307E363C3830,0x003C6660603E067E,//45
|
||||
0x003C66663E060C38,0x000C0C0C1830607E,//67
|
||||
0x003C66663C66663C,0x001C30607C66663C,//89
|
||||
0x0018180018180000,0x0C18180018180000,//:;
|
||||
0x0030180C060C1830,0x0000007E007E0000,//<=
|
||||
0x000C18306030180C,0x001800181830663C,//>?
|
||||
0x003C06765676663C,0x006666667E66663C,//@A
|
||||
0x003E66663E66663E,0x003C66060606663C,//BC
|
||||
0x001E36666666361E,0x007E06063E06067E,//DE
|
||||
0x000606063E06067E,0x003C66667606663C,//FG
|
||||
0x006666667E666666,0x007E18181818187E,//HI
|
||||
0x001C36303030307C,0x0066361E0E1E3666,//JK
|
||||
0x007E060606060606,0x00C6C6D6D6FEEEC6,//LM
|
||||
0x006666767E6E6666,0x003C66666666663C,//NO
|
||||
0x000606063E66663E,0x006C36566666663C,//PQ
|
||||
0x006666363E66663E,0x003C66603C06663C,//RS
|
||||
0x001818181818187E,0x003C666666666666,//TU
|
||||
0x00183C6666666666,0x00C6EEFED6D6C6C6,//VW
|
||||
0x0066663C183C6666,0x001818183C666666,//XY
|
||||
0x007E060C1830607E,0x003E06060606063E,//Z[
|
||||
0x00006030180C0600,0x007C60606060607C,//\]
|
||||
0x000000000000663C,0xFFFF000000000000,//^_
|
||||
0x000000000030180C,0x007C667C603C0000,//`a
|
||||
0x003E6666663E0606,0x003C6606663C0000,//bc
|
||||
0x007C6666667C6060,0x003C067E663C0000,//de
|
||||
0x000C0C0C3E0C0C38,0x3C607C66667C0000,//fg
|
||||
0x00666666663E0606,0x003C1818181C0018,//hi
|
||||
0x0E181818181C0018,0x0066361E36660606,//jk
|
||||
0x003C18181818181C,0x00C6D6D6FE6C0000,//lm
|
||||
0x00666666663E0000,0x003C6666663C0000,//no
|
||||
0x06063E66663E0000,0xE0607C66667C0000,//pq
|
||||
0x000606066E360000,0x003E603C067C0000,//rs
|
||||
0x00380C0C0C3E0C0C,0x007C666666660000,//tu
|
||||
0x00183C6666660000,0x006CFED6D6C60000,//vw
|
||||
0x00663C183C660000,0x3C607C6666660000,//xy
|
||||
0x007E0C18307E0000,0x003018180E181830,//z{
|
||||
0x0018181818181818,0x000C18187018180C,//|}
|
||||
0x000000000062D68C,0xFFFFFFFFFFFFFFFF,//~
|
||||
0x1E30181E3303331E,0x007E333333003300,//��
|
||||
0x001E033F331E0038,0x00FC667C603CC37E,//�
|
||||
0x007E333E301E0033,0x007E333E301E0007,//�
|
||||
0x007E333E301E0C0C,0x3C603E03033E0000,//�
|
||||
0x003C067E663CC37E,0x001E033F331E0033,//�
|
||||
0x001E033F331E0007,0x001E0C0C0C0E0033,//�
|
||||
0x003C1818181C633E,0x001E0C0C0C0E0007,//�
|
||||
0x00333F33331E0C33,0x00333F331E000C0C,//�
|
||||
0x003F061E063F0038,0x00FE33FE30FE0000,//�
|
||||
0x007333337F33367C,0x001E33331E00331E,//�
|
||||
0x001E33331E003300,0x001E33331E000700,//�
|
||||
0x007E33333300331E,0x007E333333000700,//�
|
||||
0x1F303F3333003300,0x001C3E63633E1C63,//�
|
||||
0x001E333333330033,0x18187E03037E1818,//�
|
||||
0x003F67060F26361C,0x000C3F0C3F1E3333,//�
|
||||
0x70337B332F1B1B0F,0x0E1B18187E18D870,//�
|
||||
0x007E333E301E0038,0x001E0C0C0C0E001C,//嵗
|
||||
0x001E33331E003800,0x007E333333003800,//╯
|
||||
0x003333331F001F00,0x00333B3F3733003F,//丰
|
||||
0x00007E007C36363C,0x00007E003C66663C,//戍
|
||||
0x001E3303060C000C,0x000003033F000000,//貝
|
||||
0x000030303F000000,0xF81973C67C1B3363,//物
|
||||
0xC0F9F3E6CF1B3363,0x183C3C1818001800,//洎
|
||||
0x0000CC663366CC00,0x00003366CC663300,//悖
|
||||
0x1144114411441144,0x55AA55AA55AA55AA,//停
|
||||
0xEEBBEEBBEEBBEEBB,0x1818181818181818,//眾
|
||||
0x1818181F18181818,0x1818181F181F1818,//斯
|
||||
0x6C6C6C6F6C6C6C6C,0x6C6C6C7F00000000,//須
|
||||
0x1818181F181F0000,0x6C6C6C6F606F6C6C,//號
|
||||
0x6C6C6C6C6C6C6C6C,0x6C6C6C6F607F0000,//獄
|
||||
0x0000007F606F6C6C,0x0000007F6C6C6C6C,//播
|
||||
0x0000001F181F1818,0x1818181F00000000,//噶
|
||||
0x000000F818181818,0x000000FF18181818,//擱
|
||||
0x181818FF00000000,0x181818F818181818,//藏
|
||||
0x000000FF00000000,0x181818FF18181818,//霰
|
||||
0x181818F818F81818,0x6C6C6CEC6C6C6C6C,//匸
|
||||
0x000000FC0CEC6C6C,0x6C6C6CEC0CFC0000,//�
|
||||
0x000000FF00EF6C6C,0x6C6C6CEF00FF0000,//帊
|
||||
0x6C6C6CEC0CEC6C6C,0x000000FF00FF0000,//昅
|
||||
0x6C6C6CEF00EF6C6C,0x000000FF00FF1818,//恘
|
||||
0x000000FF6C6C6C6C,0x181818FF00FF0000,//倳
|
||||
0x6C6C6CFF00000000,0x000000FC6C6C6C6C,//眑
|
||||
0x000000F818F81818,0x181818F818F80000,//婭
|
||||
0x6C6C6CFC00000000,0x6C6C6CEF6C6C6C6C,//笫
|
||||
0x181818FF00FF1818,0x0000001F18181818,//崷
|
||||
0x181818F800000000,0xFFFFFFFFFFFFFFFF,//窙
|
||||
0xFFFFFFFF00000000,0x0F0F0F0F0F0F0F0F,//嗲
|
||||
0xF0F0F0F0F0F0F0F0,0x00000000FFFFFFFF,//睧
|
||||
0x006E3B133B6E0000,0x03031F331F331E00,//颬
|
||||
0x0003030303637F00,0x0036363636367F00,//睼
|
||||
0x007F660C180C667F,0x001E3333337E0000,//麧
|
||||
0x03063E6666666600,0x00181818183B6E00,//緗
|
||||
0x3F0C1E33331E0C3F,0x001C36637F63361C,//鴇
|
||||
0x007736366363361C,0x001E33333E180C38,//膹
|
||||
0x00007EDBDB7E0000,0x03067EDBDB7E3060,//擨
|
||||
0x003C06033F03063C,0x003333333333331E,//闀
|
||||
0x00003F003F003F00,0x003F000C0C3F0C0C,//貘
|
||||
0x003F00060C180C06,0x003F00180C060C18,//覷
|
||||
0x1818181818D8D870,0x0E1B1B1818181818,//鏷
|
||||
0x000C0C003F000C0C,0x0000394E00394E00,//禴
|
||||
0x000000001C36361C,0x0000001818000000,//矙
|
||||
0x0000001800000000,0x383C3637303030F0,//𡜍
|
||||
0x000000363636361E,0x0000003E061C301E,//𦶠
|
||||
0x00003C3C3C3C0000,0xFFFFFFFFFFFFFFFF,//�
|
||||
};
|
||||
@@ -0,0 +1,338 @@
|
||||
I64 HasLower(U8 *src)
|
||||
{
|
||||
I64 ch;
|
||||
while (ch=*src++)
|
||||
if ('a'<=ch<='z')
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 HashFunSegFind(CHashTable *h,U8 *addr,
|
||||
Bool *_has_lower,U64 *_best,CHash **_res)
|
||||
{
|
||||
Bool *has_lower=*_has_lower;
|
||||
CHashExport *tmpex;
|
||||
U64 i,j,best=*_best;
|
||||
CHash *res=*_res;
|
||||
for (i=0;i<=h->mask;i++) {
|
||||
tmpex=h->body[i];
|
||||
while (tmpex) {
|
||||
j=0;
|
||||
if (tmpex->type&HTT_FUN) {
|
||||
if (!Bt(&tmpex(CHashFun *)->flags,Cf_EXTERN) &&
|
||||
!Bt(&tmpex(CHashFun *)->flags,Ff_INTERNAL))
|
||||
j=tmpex(CHashFun *)->exe_addr;
|
||||
} else if (tmpex->type&HTT_EXPORT_SYS_SYM)
|
||||
j=tmpex->val;
|
||||
if (j) {
|
||||
j=addr(I64)-j;
|
||||
if (0<=j<=best) {
|
||||
if (tmpex->type&HTT_EXPORT_SYS_SYM) {
|
||||
if (j<best || j==best && !has_lower) {
|
||||
has_lower=HasLower(tmpex->str);
|
||||
best=j;
|
||||
res=tmpex;
|
||||
}
|
||||
} else if (tmpex->type&HTT_FUN) {
|
||||
if (j<best || j==best &&
|
||||
(res && res->type&HTT_EXPORT_SYS_SYM||!has_lower)) {
|
||||
has_lower=HasLower(tmpex->str);
|
||||
best=j;
|
||||
res=tmpex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tmpex=tmpex->next;
|
||||
}
|
||||
}
|
||||
*_has_lower=has_lower;
|
||||
*_best=best;
|
||||
*_res =res;
|
||||
}
|
||||
|
||||
CHash *FunSegFind(U8 *addr,I64 *_offset)
|
||||
{//See $LK,"Hash",A="HI:Hash"$.
|
||||
CHash *res=NULL;
|
||||
Bool has_lower=FALSE;
|
||||
CTask *task;
|
||||
CHashTable *h;
|
||||
CCPU *c;
|
||||
U64 i,best=0xFFFF;
|
||||
if (!ChkCodePtr(addr)) {
|
||||
*_offset=best;
|
||||
return NULL;
|
||||
}
|
||||
if (IsDbgMode)
|
||||
for (i=0;i<mp_cnt;i++) {
|
||||
c=&cpu_structs[i];
|
||||
task=c->seth_task;
|
||||
do {
|
||||
if (!TaskValidate(task)) goto fs_abort_task;
|
||||
h=task->hash_table;
|
||||
while (h) {
|
||||
HashFunSegFind(h,addr,&has_lower,&best,&res);
|
||||
h=h->next;
|
||||
}
|
||||
task=task->next_task;
|
||||
} while (task!=c->seth_task);
|
||||
fs_abort_task:
|
||||
}
|
||||
else {
|
||||
h=Fs->hash_table;
|
||||
while (h) {
|
||||
HashFunSegFind(h,addr,&has_lower,&best,&res);
|
||||
h=h->next;
|
||||
}
|
||||
}
|
||||
*_offset=best;
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 FunSegCacheAdd(CHash *tmps,U8 *addr)
|
||||
{
|
||||
I64 i;
|
||||
CDbgInfo *dbg_info;
|
||||
CFunSegCache *tmpfsc;
|
||||
if (tmps && tmps->type&HTT_FUN &&
|
||||
(dbg_info=tmps(CHashFun *)->dbg_info)) {
|
||||
lock i=dbg.fun_seg_cache_index++;
|
||||
tmpfsc=&dbg.fun_seg_cache[i&(FUN_SEG_CACHE_SIZE-1)];
|
||||
tmpfsc->base=dbg_info->body[0];
|
||||
if (addr<tmpfsc->base)
|
||||
tmpfsc->base=addr;
|
||||
tmpfsc->limit=dbg_info->body[dbg_info->max_line+1-dbg_info->min_line];
|
||||
if (addr>=tmpfsc->limit)
|
||||
tmpfsc->limit=addr+1;
|
||||
i=MinI64(StrLen(tmps->str),FUN_SEG_CACHE_STR_LEN-1);
|
||||
MemCpy(tmpfsc->str,tmps->str,i);
|
||||
tmpfsc->str[i]=0;
|
||||
tmpfsc->time_stamp=tS;
|
||||
}
|
||||
}
|
||||
|
||||
U8 *FunSegCacheFind(U8 *addr,I64 *_offset)
|
||||
{
|
||||
I64 i;
|
||||
F64 timeout;
|
||||
CFunSegCache *tmpfsc=dbg.fun_seg_cache;
|
||||
if (addr==SYS_IDLE_PT) {
|
||||
*_offset=0;
|
||||
return "SYS_IDLE_PT";
|
||||
} else {
|
||||
timeout=tS+8.0;
|
||||
for (i=0;i<FUN_SEG_CACHE_SIZE;i++,tmpfsc++)
|
||||
if (tmpfsc->base<=addr<tmpfsc->limit &&
|
||||
tmpfsc->time_stamp>timeout) {
|
||||
*_offset=addr-tmpfsc->base;
|
||||
return tmpfsc->str;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
U0 StrPrintFunSeg(U8 *buf,I64 addr,I64 field_len,I64 flags)
|
||||
{
|
||||
I64 offset;
|
||||
CHashExport *tmpex;
|
||||
U8 *str,*str2;
|
||||
Bool is_fun=FALSE;
|
||||
if (!(flags&PRTF_TRUNCATE))
|
||||
field_len=0;
|
||||
if (addr) {
|
||||
if (str=FunSegCacheFind(addr,&offset)) {
|
||||
if (addr!=SYS_IDLE_PT)
|
||||
is_fun=TRUE;
|
||||
} else {
|
||||
if (tmpex=FunSegFind(addr,&offset)) {
|
||||
if (tmpex->type&HTT_FUN)
|
||||
is_fun=TRUE;
|
||||
FunSegCacheAdd(tmpex,addr);
|
||||
str=tmpex->str;
|
||||
}
|
||||
}
|
||||
if (str) {
|
||||
if (offset>0xFFFF) offset=0xFFFF;
|
||||
if (is_fun) {
|
||||
str2=MStrPrint("&%s",str);
|
||||
if (field_len>7) {
|
||||
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str2)<field_len-7)
|
||||
StrPrint(buf,"%s+0x%04X",str2,offset);
|
||||
else
|
||||
StrPrint(buf,"%*ts+0x%04X",field_len-7,str2,offset);
|
||||
} else
|
||||
StrPrint(buf,"%s+0x%04X",str2,offset);
|
||||
Free(str2);
|
||||
} else {
|
||||
if (field_len>7) {
|
||||
if (flags&PRTF_LEFT_JUSTIFY && StrLen(str)<field_len-7)
|
||||
StrPrint(buf,"%s+0x%04X",str,offset);
|
||||
else
|
||||
StrPrint(buf,"%*ts+0x%04X",field_len-7,str,offset);
|
||||
} else
|
||||
StrPrint(buf,"%s+0x%04X",str,offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (flags&PRTF_TRUNCATE)
|
||||
StrPrint(buf,"%*tX",field_len,addr);
|
||||
else
|
||||
StrPrint(buf,"%X",addr);
|
||||
}
|
||||
|
||||
I64 SrcLineNum(U8 *addr,I64 cnt=1)
|
||||
{//linenum for src of addr.
|
||||
CHashSrcSym *tmph;
|
||||
I64 cur_line,first_line,last_line,num_lines,offset;
|
||||
CDbgInfo *dbg_info;
|
||||
U32 *body;
|
||||
U8 *src,*src2;
|
||||
if (tmph=FunSegFind(addr,&offset)) {
|
||||
if (tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
|
||||
if (dbg_info=tmph->dbg_info) {
|
||||
num_lines=dbg_info->max_line-dbg_info->min_line+1;
|
||||
body=dbg_info->body;
|
||||
|
||||
//find first nonzero
|
||||
first_line=0;
|
||||
while (!body[first_line]) {
|
||||
first_line++;
|
||||
if (first_line>=num_lines)
|
||||
return -1;
|
||||
}
|
||||
|
||||
//find last nonzero
|
||||
last_line=num_lines-1;
|
||||
while (!body[last_line] && last_line>first_line)
|
||||
last_line--;
|
||||
|
||||
//interpolate to guess line num
|
||||
cur_line=ClampI64(ToF64(addr-body[first_line])*(last_line-first_line+1)/
|
||||
(body[last_line]-body[first_line]+1),first_line,last_line);
|
||||
|
||||
//retreat while too high
|
||||
while ((!body[cur_line] || body[cur_line]>=addr) && cur_line>first_line)
|
||||
cur_line--;
|
||||
|
||||
//advance while to low
|
||||
while ((!body[cur_line] || body[cur_line]<addr) && cur_line<last_line)
|
||||
cur_line++;
|
||||
|
||||
if (addr<body[cur_line]+cnt)
|
||||
return cur_line+dbg_info->min_line;
|
||||
|
||||
} else if (tmph->src_link) {
|
||||
src =StrNew(tmph->src_link);
|
||||
src2=StrNew(tmph->src_link);
|
||||
StrLastRem(src,",",src2);
|
||||
cur_line=Str2I64(src2);
|
||||
Free(src);
|
||||
Free(src2);
|
||||
return cur_line;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
U8 *SrcFileName(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
|
||||
{//MAlloc filename for src of addr.
|
||||
CHashSrcSym *tmph;
|
||||
I64 i,j,ii,offset,best=NULL,d,best_d;
|
||||
U32 *body;
|
||||
CDbgInfo *dbg_info;
|
||||
U8 *src;
|
||||
if ((tmph=FunSegFind(addr,&offset)) &&
|
||||
tmph->type&(HTT_FUN|HTT_EXPORT_SYS_SYM)) {
|
||||
if (dbg_info=tmph->dbg_info) {
|
||||
j=dbg_info->max_line-dbg_info->min_line+1;
|
||||
body=dbg_info->body;
|
||||
best_d=I64_MAX;
|
||||
for (i=0;i<j;i++) {
|
||||
if (0<body[i]<=addr<body[i]+cnt) {
|
||||
ii=i+1;
|
||||
while (!body[ii])
|
||||
ii++;
|
||||
if (addr<body[ii]) {
|
||||
d=addr(I64)-body[i];
|
||||
if (d<best_d) {
|
||||
best_d=d;
|
||||
best=tmph->src_link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
best=tmph->src_link;
|
||||
}
|
||||
if (best) {
|
||||
src=StrNew(best,mem_task);
|
||||
StrFirstRem(src,":");
|
||||
StrLastRem(src,",");
|
||||
return src;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8 *SrcEdLink(U8 *addr,I64 cnt=1,CTask *mem_task=NULL)
|
||||
{//MAlloc file,line link to src of addr.
|
||||
U8 *filename,*st,*st2;
|
||||
I64 linenum;
|
||||
if (filename=SrcFileName(addr,cnt)) {
|
||||
linenum=SrcLineNum(addr,cnt);
|
||||
if (linenum<1)
|
||||
linenum=1;
|
||||
st2=MStrPrint("FL:%s,%d",filename,linenum);
|
||||
Free(filename);
|
||||
st=StrNew(st2,mem_task);
|
||||
Free(st2);
|
||||
return st;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Bool PutSrcLink(U8 *addr,I64 cnt=1,U8 *buf=NULL)
|
||||
{//Put to StdOut a $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ file,line link to src of addr.
|
||||
U8 *src;
|
||||
if (src=SrcEdLink(addr,cnt)) {
|
||||
if (buf)
|
||||
StrPrint(buf,"$$LK,\"%p\",A=\"%s\"$$",addr,src);
|
||||
else
|
||||
"$$LK,\"%p\",A=\"%s\"$$",addr,src;
|
||||
Free(src);
|
||||
return TRUE;
|
||||
} else if (buf)
|
||||
*buf=0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool E(U8 *addr,I64 cnt=512,I64 edf_dof_flags=0)
|
||||
{//Edit src at addr.
|
||||
U8 *st;
|
||||
Bool res=FALSE;
|
||||
if (st=SrcEdLink(addr,cnt)) {
|
||||
if (IsRaw)
|
||||
res=EdLiteFileLine(st,edf_dof_flags);
|
||||
else
|
||||
res=Ed(st,edf_dof_flags);
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool Man(U8 *st,I64 edf_dof_flags=0)
|
||||
{//Owner's manual for symbol. Edit src code for symbol.
|
||||
Bool res=FALSE;
|
||||
U8 **st2;
|
||||
CHashSrcSym *tmph;
|
||||
if (IsRaw) {
|
||||
if ((tmph=HashFind(st,Fs->hash_table,HTG_SRC_SYM)) && tmph->src_link)
|
||||
res=EdLiteFileLine(tmph->src_link,edf_dof_flags);
|
||||
} else {
|
||||
st2=MStrPrint("MN:%s",st);
|
||||
res=Ed(st2,edf_dof_flags);
|
||||
Free(st2);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,502 @@
|
||||
U0 JobDel(CJob *tmpc)
|
||||
{//Free one cmd node.
|
||||
Free(tmpc->aux_str);
|
||||
Free(tmpc);
|
||||
}
|
||||
|
||||
U0 JobQueDel(CJob *head)
|
||||
{
|
||||
CJob *tmpc=head->next,*tmpc1;
|
||||
while (tmpc!=head) {
|
||||
tmpc1=tmpc->next;
|
||||
QueRem(tmpc);
|
||||
JobDel(tmpc);
|
||||
tmpc=tmpc1;
|
||||
}
|
||||
}
|
||||
|
||||
U0 JobCtrlInit(CJobCtrl *ctrl)
|
||||
{
|
||||
QueInit(&ctrl->next_waiting);
|
||||
QueInit(&ctrl->next_done);
|
||||
ctrl->flags=0;
|
||||
}
|
||||
|
||||
U0 TaskRstAwaitingMsg(CTask *task=NULL)
|
||||
{//Pop-ups get parent messages so wake-up our pop-ups if we got a msg.
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
do {
|
||||
if (TaskValidate(task))
|
||||
LBtr(&task->task_flags,TASKf_AWAITING_MSG);
|
||||
else
|
||||
break;
|
||||
} while (task=task->popup_task);
|
||||
POPFD
|
||||
}
|
||||
|
||||
CJob *TaskExe(CTask *srv,CTask *master,U8 *data,I64 flags)
|
||||
{//Queues a request to compile and execute src code text.
|
||||
CJob *res;
|
||||
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
|
||||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
|
||||
return NULL;
|
||||
res=ACAlloc(sizeof(CJob));
|
||||
res->master_task=master;
|
||||
res->job_code=JOBT_EXE_STR;
|
||||
res->flags=flags;
|
||||
res->aux_str=AStrNew(data);
|
||||
res->ctrl=&srv->srv_ctrl;
|
||||
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
if (!TaskValidate(srv)) {
|
||||
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
POPFD
|
||||
JobDel(res);
|
||||
return NULL;
|
||||
} else {
|
||||
LBtr(&srv->task_flags,TASKf_IDLE);
|
||||
TaskRstAwaitingMsg(srv);
|
||||
QueIns(res,srv->srv_ctrl.last_waiting);
|
||||
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
if (Bt(&flags,JOBf_WAKE_MASTER)) {
|
||||
Suspend(master);
|
||||
Yield;
|
||||
}
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
CJob *TaskText(CTask *srv,CTask *master,U8 *data,I64 flags)
|
||||
{//Post StdIn text to servant task. Tell who the master task is.
|
||||
CJob *res;
|
||||
CTask *task;
|
||||
if (!data || !TaskValidate(srv) || master && !TaskValidate(master) ||
|
||||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
|
||||
return NULL;
|
||||
res=ACAlloc(sizeof(CJob));
|
||||
res->master_task=master; //in case somebody cares
|
||||
res->job_code=JOBT_TEXT_INPUT;
|
||||
res->flags=flags;
|
||||
res->aux_str=AStrNew(data);
|
||||
|
||||
PUSHFD
|
||||
task=srv->last_input_filter_task;
|
||||
if (Bt(&flags,JOBf_HIGHEST_PRIORITY) || task==srv) {
|
||||
if (task!=srv)
|
||||
TaskWait(srv);
|
||||
task=Spawn(&InputFilterTask,NULL,"Input Filter",,srv);
|
||||
CLI
|
||||
task->next_input_filter_task=srv->next_input_filter_task;
|
||||
task->last_input_filter_task=srv;
|
||||
srv->next_input_filter_task=task;
|
||||
task->next_input_filter_task->last_input_filter_task=task;
|
||||
} else {
|
||||
CLI
|
||||
task=srv->next_input_filter_task;
|
||||
}
|
||||
res->ctrl=&task->srv_ctrl;
|
||||
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
if (!TaskValidate(task)) {
|
||||
JobDel(res);
|
||||
res=NULL;
|
||||
} else {
|
||||
LBtr(&task->task_flags,TASKf_IDLE);
|
||||
TaskRstAwaitingMsg(task);
|
||||
QueIns(res,task->srv_ctrl.last_waiting);
|
||||
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
CJob *TaskMsg(CTask *_srv,CTask *master,
|
||||
I64 msg_code,I64 arg1,I64 arg2,I64 flags)
|
||||
{//Post message to servant task. Tell who the master task is.
|
||||
//See $LK,"flags",A="MN:JOBf_WAKE_MASTER"$ and $LK,"msg_code",A="MN:MSG_CMD"$.
|
||||
CJob *tmpc1,*tmpc;
|
||||
CTask *srv=_srv;
|
||||
if (!TaskValidate(srv) || master && !TaskValidate(master)||
|
||||
srv->popup_task && !Bt(&srv->task_flags,TASKf_FILTER_INPUT))
|
||||
return NULL;
|
||||
tmpc=ACAlloc(sizeof(CJob));
|
||||
tmpc->master_task=master;
|
||||
tmpc->job_code=JOBT_MSG;
|
||||
tmpc->msg_code=AbsI64(msg_code); //negative means do a down and up
|
||||
tmpc->aux1=arg1;
|
||||
tmpc->aux2=arg2;
|
||||
tmpc->flags=flags;
|
||||
PUSHFD
|
||||
if (Bt(&sys_semas[SEMA_RECORD_MACRO],0) &&
|
||||
srv!=sys_macro_task && msg_code==MSG_KEY_DOWN) {
|
||||
tmpc1=AMAllocIdent(tmpc);
|
||||
CLI
|
||||
QueIns(tmpc1,sys_macro_head.last);
|
||||
}
|
||||
CLI
|
||||
while (Bt(&srv->task_flags,TASKf_FILTER_INPUT) &&
|
||||
!Bt(&flags,JOBf_DONT_FILTER))
|
||||
srv=srv->next_input_filter_task;
|
||||
tmpc->ctrl=&srv->srv_ctrl;
|
||||
while (LBts(&srv->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
if (!TaskValidate(srv)) {
|
||||
JobDel(tmpc);
|
||||
tmpc=NULL;
|
||||
} else {
|
||||
LBtr(&srv->task_flags,TASKf_IDLE);
|
||||
TaskRstAwaitingMsg(srv);
|
||||
QueIns(tmpc,srv->srv_ctrl.last_waiting);
|
||||
LBtr(&srv->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
}
|
||||
POPFD
|
||||
if (msg_code<0) //Down-Up
|
||||
TaskMsg(_srv,master,-msg_code+1,arg1,arg2,flags);
|
||||
return tmpc;
|
||||
}
|
||||
|
||||
Bool JobResScan(CJob *rqst=NULL,I64 *_res=NULL)
|
||||
{//Check rqst complete, return with or without.
|
||||
CJobCtrl *ctrl;
|
||||
CJob *tmpc,*tmpc1;
|
||||
if (!rqst || Bt(&rqst->flags,JOBf_DONE)) {
|
||||
if (!rqst || rqst->master_task)
|
||||
ctrl=&Fs->srv_ctrl;
|
||||
else
|
||||
ctrl=rqst->ctrl;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&ctrl->flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
tmpc1=&ctrl->next_done;
|
||||
tmpc=tmpc1->next;
|
||||
while (tmpc!=tmpc1) {
|
||||
if (!rqst || rqst==tmpc) {
|
||||
QueRem(tmpc);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
POPFD
|
||||
if (_res)
|
||||
*_res=tmpc->res;
|
||||
JobDel(tmpc);
|
||||
return TRUE;
|
||||
}
|
||||
tmpc=tmpc->next;
|
||||
}
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
POPFD
|
||||
}
|
||||
if (_res)
|
||||
*_res=0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 JobResGet(CJob *rqst=NULL)
|
||||
{//See $LK,"::/Demo/MultiCore/Lock.HC"$
|
||||
I64 res;
|
||||
CJob *tmpc1;
|
||||
if (!rqst) {
|
||||
tmpc1=&Fs->srv_ctrl.next_done;
|
||||
while (tmpc1==tmpc1->next) {
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
Yield;
|
||||
}
|
||||
} else {
|
||||
while (!Bt(&rqst->flags,JOBf_DONE)) {
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
Yield;
|
||||
}
|
||||
}
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
//Could get taken by someone else.
|
||||
JobResScan(rqst,&res);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE)
|
||||
{//Wait for idle.
|
||||
CTask *task1;
|
||||
CJob *tmpc1;
|
||||
if (!task) task=Fs;
|
||||
if (TaskValidate(task)) {
|
||||
PUSHFD
|
||||
CLI
|
||||
while (TRUE) {
|
||||
task1=task->last_input_filter_task;
|
||||
tmpc1=&task1->srv_ctrl.next_waiting;
|
||||
if (task1==Fs || !TaskValidate(task1) ||
|
||||
tmpc1==tmpc1->next && Bt(&task1->task_flags,TASKf_IDLE) &&
|
||||
(!cmd_line_pmt || Bt(&task1->task_flags,TASKf_CMD_LINE_PMT)))
|
||||
break;
|
||||
Yield;
|
||||
}
|
||||
POPFD
|
||||
}
|
||||
}
|
||||
|
||||
U0 PostMsg(CTask *task,I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
|
||||
{//Post message to a task and return immediately. See $LK,"msg_code",A="MN:MSG_CMD"$.
|
||||
if (TaskValidate(task)) {
|
||||
if (Bt(&task->task_flags,TASKf_INPUT_FILTER_TASK))
|
||||
TaskMsg(task->last_input_filter_task,NULL,msg_code,arg1,arg2,
|
||||
flags|1<<JOBf_DONT_FILTER);
|
||||
else
|
||||
TaskMsg(task,NULL,msg_code,arg1,arg2,flags);
|
||||
}
|
||||
}
|
||||
|
||||
U0 PostMsgWait(CTask *task,I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
|
||||
{//Post message to a task and wait until task is idle.See $LK,"msg_code",A="MN:MSG_CMD"$.
|
||||
PostMsg(task,msg_code,arg1,arg2,flags);
|
||||
TaskWait(task);
|
||||
}
|
||||
|
||||
U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0)
|
||||
{//Post message to current task and return immediately.
|
||||
//See $LK,"msg_code",A="MN:MSG_CMD"$.
|
||||
PostMsg(Fs,msg_code,arg1,arg2,flags);
|
||||
}
|
||||
|
||||
#define JOB_DONE 0
|
||||
#define JOB_CONT 1
|
||||
#define JOB_EXIT 2
|
||||
|
||||
I64 JobRunOne(I64 run_flags,CJobCtrl *ctrl)
|
||||
{//Called with ctrl->flags,JOBCf_LOCKED.
|
||||
CJob *tmpc=ctrl->next_waiting;
|
||||
CTask *master;
|
||||
I64 res,flags=tmpc->flags,old_flags=GetRFlags;
|
||||
if (Bt(&flags,JOBf_EXIT_ON_COMPLETE))
|
||||
res=JOB_EXIT;
|
||||
else
|
||||
res=JOB_CONT;
|
||||
switch (tmpc->job_code) {
|
||||
case JOBT_SPAWN_TASK:
|
||||
QueRem(tmpc);
|
||||
LBts(&tmpc->flags,JOBf_DISPATCHED);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
if (tmpc->aux_str)
|
||||
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
|
||||
tmpc->aux_str,,tmpc->aux1,tmpc->aux2,tmpc->flags);
|
||||
else
|
||||
tmpc->spawned_task=Spawn(tmpc->addr,tmpc->fun_arg,
|
||||
"Unnamed",,tmpc->aux1,tmpc->aux2,tmpc->flags);
|
||||
break;
|
||||
case JOBT_CALL:
|
||||
QueRem(tmpc);
|
||||
LBts(&tmpc->flags,JOBf_DISPATCHED);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
SetRFlags(run_flags);
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
try
|
||||
tmpc->res=(*tmpc->addr)(tmpc->fun_arg);
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
SetRFlags(old_flags);
|
||||
break;
|
||||
case JOBT_EXE_STR:
|
||||
QueRem(tmpc);
|
||||
LBts(&tmpc->flags,JOBf_DISPATCHED);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
SetRFlags(run_flags);
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
try
|
||||
tmpc->res=ExePrint("%s",tmpc->aux_str);
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
SetRFlags(old_flags);
|
||||
break;
|
||||
default:
|
||||
res=JOB_DONE;
|
||||
}
|
||||
if (res) {
|
||||
if (master=tmpc->master_task) {
|
||||
if (!Bt(&flags,JOBf_FREE_ON_COMPLETE)) {
|
||||
CLI
|
||||
while (LBts(&master->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
QueIns(tmpc,master->srv_ctrl.last_done);
|
||||
LBts(&tmpc->flags,JOBf_DONE);
|
||||
LBtr(&master->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
SetRFlags(old_flags);
|
||||
}
|
||||
if (Bt(&flags,JOBf_FOCUS_MASTER) &&
|
||||
!Bt(&master->win_inhibit,WIf_SELF_FOCUS))
|
||||
sys_focus_task=master;
|
||||
if (Bt(&flags,JOBf_WAKE_MASTER))
|
||||
Suspend(master,FALSE);
|
||||
}
|
||||
if (Bt(&flags,JOBf_FREE_ON_COMPLETE))
|
||||
JobDel(tmpc);
|
||||
else if (!master) {
|
||||
CLI
|
||||
while (LBts(&ctrl->flags,JOBCf_LOCKED))
|
||||
Yield;
|
||||
QueIns(tmpc,ctrl->last_done);
|
||||
LBts(&tmpc->flags,JOBf_DONE);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
SetRFlags(old_flags);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 JobsHndlr(I64 run_flags,CTask *task=NULL)
|
||||
{//Handle all waiting cmds and return.
|
||||
I64 cnt=0,old_flags=GetRFlags;
|
||||
if (!task) task=Fs;
|
||||
while (TRUE) {
|
||||
CLI
|
||||
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
if (task->srv_ctrl.next_waiting!=&task->srv_ctrl)
|
||||
switch (JobRunOne(run_flags,&task->srv_ctrl)) {
|
||||
case JOB_CONT:
|
||||
cnt++;
|
||||
break;
|
||||
case JOB_EXIT:
|
||||
Exit;
|
||||
case JOB_DONE:
|
||||
goto jh_done;
|
||||
}
|
||||
else
|
||||
goto jh_done;
|
||||
}
|
||||
jh_done:
|
||||
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
SetRFlags(old_flags);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL)
|
||||
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
|
||||
I64 res;
|
||||
CJob *tmpc;
|
||||
CTask *task=Spawn(&SrvCmdLine,NULL,"Servant",,parent);
|
||||
if (!parent) {
|
||||
TaskExe(task,parent,buf,1<<JOBf_EXIT_ON_COMPLETE|1<<JOBf_FREE_ON_COMPLETE);
|
||||
if (_pu_task) *_pu_task=task;
|
||||
return 0;
|
||||
} else {
|
||||
Fs->popup_task=task;
|
||||
tmpc=TaskExe(task,parent,buf,1<<JOBf_WAKE_MASTER|1<<JOBf_FOCUS_MASTER);
|
||||
if (_pu_task) *_pu_task=task;
|
||||
JobResScan(tmpc,&res);
|
||||
Fs->popup_task=NULL;
|
||||
Kill(task);
|
||||
if (_pu_task) *_pu_task=NULL;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
I64 PopUpPrint(U8 *fmt,...)
|
||||
{//Execute code in $LK,"PopUp",A="MN:PopUp"$ task.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
I64 res;
|
||||
res=PopUp(buf,Fs);
|
||||
Free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 Adam(U8 *fmt,...)
|
||||
{//Make adam_task execute code.
|
||||
I64 res;
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
CJob *tmpc;
|
||||
if (Fs==adam_task) {
|
||||
tmpc=TaskExe(adam_task,Fs,buf,0);
|
||||
JobsHndlr(GetRFlags);
|
||||
} else {
|
||||
TaskWait(adam_task);
|
||||
tmpc=TaskExe(adam_task,Fs,buf,1<<JOBf_WAKE_MASTER);
|
||||
}
|
||||
JobResScan(tmpc,&res);
|
||||
Free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 AdamLog(U8 *fmt,...)
|
||||
{//Display text in adam_task.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
if (Fs==adam_task)
|
||||
"%s",buf;
|
||||
else if (!IsSingleUser)
|
||||
Adam("\"%%s\",%d;",buf);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 AdamErr(U8 *fmt,...)
|
||||
{//Display red blinking Err text in adam_task.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),
|
||||
*st=MStrPrint(ST_ERR_ST "%s",buf);
|
||||
if (Fs==adam_task)
|
||||
"%s",st;
|
||||
else if (!IsSingleUser)
|
||||
Adam("\"%%s\",%d;",st);
|
||||
Free(st);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 XTalk(CTask *task,U8 *fmt,...)
|
||||
{//Sends text to other task. See $LK,"::/Misc/OSTestSuite.HC"$.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf),
|
||||
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
|
||||
TaskText(task,NULL,st2,0);
|
||||
Free(st2);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 XTalkWait(CTask *task,U8 *fmt,...)
|
||||
{//Send text to other task and wait for it to idle.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf),
|
||||
*st2=MStrPrint("\"%%s\",%d;Free(%d);",st,st);
|
||||
TaskText(task,NULL,st2,0);
|
||||
Free(st2);
|
||||
Free(buf);
|
||||
TaskWait(task);
|
||||
}
|
||||
|
||||
U0 InStr(U8 *fmt,...)
|
||||
{//Send InFile code to self.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK))
|
||||
ExePrint("%s",buf);
|
||||
else
|
||||
TaskText(Fs,NULL,buf,1<<JOBf_HIGHEST_PRIORITY);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 InFile(U8 *filename)
|
||||
{//Send InFile code file to self.
|
||||
U8 *name=DftExt(filename,"IN.Z");
|
||||
InStr("Cd(\"%C:%s\");;#include \"%s\"",
|
||||
Drv2Let(Fs->cur_dv),Fs->cur_dir,name);
|
||||
Free(name);
|
||||
}
|
||||
|
||||
U0 In(U8 *fmt,...)
|
||||
{//Send text to own input buffer. See $LK,"::/Demo/AcctExample/TOS/TOSDistro.HC"$.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv),*st=AStrNew(buf);
|
||||
InStr("\"%%s\",%d;Free(%d);",st,st);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 XTalkStr(CTask *task,U8 *fmt,...)
|
||||
{//Send InFile code to other task.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
TaskText(task,NULL,buf,0);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 XTalkStrWait(CTask *task,U8 *fmt,...)
|
||||
{//Send InFile code to other task and wait for it to idle.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
TaskText(task,NULL,buf,0);
|
||||
Free(buf);
|
||||
TaskWait(task);
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
//This is run in a $LK,"#exe",A="FF:::/Kernel/Kernel.PRJ,KCfg"${}.
|
||||
|
||||
U8 *kernel_cfg_options="MemInit\0HeapInit\0VarInit\0StaffMode\0"
|
||||
"HomeDir\0NoMP\0TextMode\0DontProbe\0AutoMountIDE\0DbgDistro\0Help\0";
|
||||
|
||||
#define CFG_MEM_INIT 0
|
||||
#define CFG_HEAP_INIT 1
|
||||
#define CFG_VAR_INIT 2
|
||||
#define CFG_STAFF_MODE 3
|
||||
#define CFG_HOME_DIR 4
|
||||
#define CFG_NO_MP 5
|
||||
#define CFG_TEXT_MODE 6
|
||||
#define CFG_DONT_PROBE 7
|
||||
#define CFG_AUTO_MOUNT_IDE 8
|
||||
#define CFG_DBG_DISTRO 9
|
||||
#define CFG_OPTIONS_NUM 10
|
||||
|
||||
#define CFG_HELP 10
|
||||
|
||||
class CKCfg
|
||||
{
|
||||
U8 *dsk_cache_size_exp;
|
||||
CDoc *add_dev;
|
||||
U8 *dbg_distro_file,*dbg_distro_start;
|
||||
U8 *home_dir;
|
||||
Bool opts[CFG_OPTIONS_NUM];
|
||||
U8 mem_init_val,heap_init_val,var_init_val,
|
||||
boot_drv_let,auto_mount_ide_hd_let,auto_mount_ide_cd_let;
|
||||
};
|
||||
|
||||
CDoc *KCfgAddDev(CKCfg *c)
|
||||
{
|
||||
I64 ch;
|
||||
CDoc *doc=DocNew;
|
||||
"\n\nIn anticipation of the drives you will\n"
|
||||
"define shortly, enter the drive letter\n"
|
||||
"of the drive with the account directory.\n"
|
||||
"\n($$PURPLE$$<ENTER>$$FG$$ for cur drv) Boot Drv:";
|
||||
ch=Let2Let(GetChar);
|
||||
if ('A'<=ch<='Z')
|
||||
c->boot_drv_let=ch;
|
||||
else
|
||||
c->boot_drv_let=Drv2Let(Fs->cur_dv);
|
||||
"\n\n$$BK,1$$$$PURPLE$$Mount drives so they will be present when "
|
||||
"you boot.$$FG$$$$BK,0$$\n";
|
||||
Mount2(c->boot_drv_let,doc,FALSE);
|
||||
return doc;
|
||||
}
|
||||
|
||||
U0 KCfgOptions(CKCfg *c)
|
||||
{
|
||||
I64 i;
|
||||
U8 *st=NULL,*st2,*st3;
|
||||
Bool state;
|
||||
do {
|
||||
Free(st);
|
||||
for (i=0;i<CFG_OPTIONS_NUM;i++)
|
||||
if (i==CFG_HOME_DIR)
|
||||
"$$PURPLE$$%13tz$$FG$$:\"%s\"\n",i,kernel_cfg_options,c->home_dir;
|
||||
else
|
||||
"$$PURPLE$$%13tz$$FG$$:%Z\n",i,kernel_cfg_options,c->opts[i],"ST_OFF_ON";
|
||||
"\nType '$$PURPLE$$Help$$FG$$' for help.\n";
|
||||
st=GetStr("Option ($$PURPLE$$<ENTER>$$FG$$ when done):","");
|
||||
i=LstMatch(st,kernel_cfg_options,LMF_IGNORE_CASE);
|
||||
if (i==CFG_HELP)
|
||||
"\n"
|
||||
"$$PURPLE$$MemInit$$FG$$ Initializes memory above 0x100000 "
|
||||
"to a val at boot.\n"
|
||||
"$$PURPLE$$HeapInit$$FG$$ Initializes MAlloc() memory to a val.\n"
|
||||
"$$PURPLE$$VarInit$$FG$$ Initializes glbl var memory to a val.\n"
|
||||
"$$PURPLE$$HomeDir$$FG$$ Set home dir.\n"
|
||||
"$$PURPLE$$NoMP$$FG$$ No multicore.\n"
|
||||
"$$PURPLE$$TextMode$$FG$$ Text Mode (requires hard reboot).\n"
|
||||
"$$PURPLE$$DontProbe$$FG$$ Just prompt CD/DVD ports, don't probe.\n"
|
||||
"$$PURPLE$$AutoMountIDE$$FG$$ AutoMount IDE drives to 'C' and 'T'.\n"
|
||||
"$$PURPLE$$DbgDistro$$FG$$ Include RAM Drv in Kernel.BIN.\n"
|
||||
"\n";
|
||||
else
|
||||
if (0<=i<CFG_OPTIONS_NUM) {
|
||||
state=c->opts[i]=!c->opts[i];
|
||||
switch (i) {
|
||||
case CFG_MEM_INIT:
|
||||
if (state)
|
||||
c->mem_init_val=GetI64("Val (0-255):",255,0,255);
|
||||
break;
|
||||
case CFG_HEAP_INIT:
|
||||
if (state)
|
||||
c->heap_init_val=GetI64("Val (0-255):",255,0,255);
|
||||
break;
|
||||
case CFG_VAR_INIT:
|
||||
if (state)
|
||||
c->var_init_val=GetI64("Val (0-255):",255,0,255);
|
||||
break;
|
||||
case CFG_HOME_DIR:
|
||||
st2=GetStr("Home Dir(\"%s\"):",c->home_dir);
|
||||
if (!*st2)
|
||||
st2=StrNew("::/Home");
|
||||
else if (st2[1]!=':') {
|
||||
st3=MStrPrint("::%s",st2);
|
||||
Free(st2);
|
||||
st2=st3;
|
||||
}
|
||||
Free(c->home_dir);
|
||||
c->home_dir=st2;
|
||||
if (StrCmp(c->home_dir,"::/Home"))
|
||||
c->opts[i]=TRUE;
|
||||
else
|
||||
c->opts[i]=FALSE;
|
||||
break;
|
||||
case CFG_AUTO_MOUNT_IDE:
|
||||
if (state) {
|
||||
"First HD Drive Let:";
|
||||
c->auto_mount_ide_hd_let=Let2Let(GetChar);
|
||||
if (!('A'<=c->auto_mount_ide_hd_let<='Z'))
|
||||
c->auto_mount_ide_hd_let=0;
|
||||
'\n';
|
||||
if (c->auto_mount_ide_hd_let)
|
||||
"First HD Drive:%C\n",c->auto_mount_ide_hd_let;
|
||||
else
|
||||
"First HD Drive:%C\n",'C';
|
||||
|
||||
"First CD Drive Let:";
|
||||
c->auto_mount_ide_cd_let=Let2Let(GetChar);
|
||||
if (!('A'<=c->auto_mount_ide_cd_let<='Z'))
|
||||
c->auto_mount_ide_cd_let=0;
|
||||
'\n';
|
||||
if (c->auto_mount_ide_cd_let)
|
||||
"First CD Drive:%C\n",c->auto_mount_ide_cd_let;
|
||||
else
|
||||
"First CD Drive:%C\n",'T';
|
||||
} else {
|
||||
c->auto_mount_ide_hd_let=0;
|
||||
c->auto_mount_ide_cd_let=0;
|
||||
}
|
||||
break;
|
||||
case CFG_DBG_DISTRO:
|
||||
Free(c->dbg_distro_file);
|
||||
c->dbg_distro_file=0;
|
||||
c->dbg_distro_start=0;
|
||||
if (state) {
|
||||
c->dbg_distro_file=GetStr("Dbg Distro File:");
|
||||
c->dbg_distro_start=GetI64("Dbg Distro Start:");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (*st);
|
||||
Free(st);
|
||||
}
|
||||
|
||||
CKCfg *KCfgNew()
|
||||
{
|
||||
CKCfg *c=CAlloc(sizeof(CKCfg));
|
||||
|
||||
c->add_dev=KCfgAddDev(c);
|
||||
c->home_dir=StrNew("::/Home");
|
||||
c->dsk_cache_size_exp=GetStr(
|
||||
"Disk Cache Size in Bytes,\n"
|
||||
"gets rounded-up funny,\n"
|
||||
"($$PURPLE$$<ENTER>$$FG$$ will use default.):",
|
||||
"Scale2Mem(0x80000,0x8000000)");
|
||||
KCfgOptions(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
U0 KCfgDel(CKCfg *c)
|
||||
{
|
||||
DocDel(c->add_dev);
|
||||
Free(c->dbg_distro_file);
|
||||
Free(c->home_dir);
|
||||
Free(c->dsk_cache_size_exp);
|
||||
Free(c);
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
U0 LinkedLstDel(U8 **_lst)
|
||||
{//Free entire linked-list.
|
||||
U8 **tmpl;
|
||||
while (_lst) {
|
||||
tmpl=*_lst;
|
||||
Free(_lst);
|
||||
_lst=tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
U8 *LinkedLstCopy(U8 **_lst,CTask *mem_task=NULL)
|
||||
{//MAlloc ident copy of entire linked-list.
|
||||
U8 *res=NULL,**tmpl=&res;
|
||||
while (_lst) {
|
||||
tmpl=*tmpl=MAllocIdent(_lst,mem_task);
|
||||
_lst=*_lst;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 LinkedLstCnt(U8 **_lst)
|
||||
{//Count of nodes in linked-list.
|
||||
I64 res=0;
|
||||
while (_lst) {
|
||||
res++;
|
||||
_lst=*_lst;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 LinkedLstSize(U8 **_lst)
|
||||
{//Mem size of all nodes in linked-list.
|
||||
I64 res=0;
|
||||
while (_lst) {
|
||||
res+=MSize2(_lst);
|
||||
_lst=*_lst;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 QueDel(CQue *head,Bool querem=FALSE)
|
||||
{//Free entries in queue, not head.
|
||||
CQue *tmpq=head->next,*tmpq1;
|
||||
while (tmpq!=head) {
|
||||
tmpq1=tmpq->next;
|
||||
if (querem)
|
||||
QueRem(tmpq);
|
||||
Free(tmpq);
|
||||
tmpq=tmpq1;
|
||||
}
|
||||
}
|
||||
|
||||
CQue *QueCopy(CQue *head,CTask *mem_task=NULL)
|
||||
{//MAlloc ident copy of entire queue and head.
|
||||
CQue *res=MAllocIdent(head,mem_task),*tmpq=head->next,*tmpq1;
|
||||
QueInit(res);
|
||||
while (tmpq!=head) {
|
||||
tmpq1=MAllocIdent(tmpq,mem_task);
|
||||
QueIns(tmpq1,res->last);
|
||||
tmpq=tmpq->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 QueCnt(CQue *head)
|
||||
{//Count of nodes in queue, not head.
|
||||
CQue *tmpq=head->next;
|
||||
I64 res=0;
|
||||
while (tmpq!=head) {
|
||||
res++;
|
||||
tmpq=tmpq->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 QueSize(CQue *head)
|
||||
{//Mem size of all nodes in queue, not head.
|
||||
CQue *tmpq=head->next;
|
||||
I64 res=0;
|
||||
while (tmpq!=head) {
|
||||
res+=MSize2(tmpq);
|
||||
tmpq=tmpq->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CQueVectU8 *QueVectU8New(I64 min_idx=0)
|
||||
{//Create new queue vecter.
|
||||
CQueVectU8 *res=MAlloc(sizeof(CQueVectU8));
|
||||
QueInit(res);
|
||||
res->total_cnt=res->node_cnt=0;
|
||||
res->min_idx=min_idx;
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 QueVectU8Put(CQueVectU8 *v,I64 idx,U8 ch)
|
||||
{//Put U8 at idx i.
|
||||
CQueVectU8 *tmpv;
|
||||
idx-=v->min_idx;
|
||||
if (idx<0) return;
|
||||
if (idx<v->total_cnt) {
|
||||
tmpv=v;
|
||||
do {
|
||||
idx-=tmpv->node_cnt;
|
||||
if (idx<0) {
|
||||
tmpv->body[idx+tmpv->node_cnt]=ch;
|
||||
return;
|
||||
}
|
||||
tmpv=tmpv->next;
|
||||
} while (tmpv!=v);
|
||||
} else
|
||||
idx-=v->total_cnt;
|
||||
|
||||
while (TRUE) {
|
||||
tmpv=v->last;
|
||||
if (tmpv->node_cnt>=QUE_VECT_U8_CNT) {
|
||||
tmpv=MAlloc(sizeof(CQueVectU8));
|
||||
tmpv->node_cnt=0;
|
||||
QueIns(tmpv,v->last);
|
||||
}
|
||||
if (idx--) {
|
||||
tmpv->body[tmpv->node_cnt++]=0;
|
||||
v->total_cnt++;
|
||||
} else {
|
||||
tmpv->body[tmpv->node_cnt++]=ch;
|
||||
v->total_cnt++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 QueVectU8Del(CQueVectU8 *v)
|
||||
{//Free entire queue vector.
|
||||
if (v) {
|
||||
QueDel(v);
|
||||
Free(v);
|
||||
}
|
||||
}
|
||||
|
||||
I64 QueVectU8Get(CQueVectU8 *v,I64 idx)
|
||||
{//Get U8 at idx i.
|
||||
CQueVectU8 *tmpv;
|
||||
idx-=v->min_idx;
|
||||
if (!(0<=idx<v->total_cnt)) return 0;
|
||||
tmpv=v;
|
||||
do {
|
||||
idx-=tmpv->node_cnt;
|
||||
if (idx<0)
|
||||
return tmpv->body[idx+tmpv->node_cnt];
|
||||
tmpv=tmpv->next;
|
||||
} while (tmpv!=v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFifoU8 *FifoU8New(I64 size,CTask *mem_task=NULL)
|
||||
{//Create new fifo.
|
||||
CFifoU8 *f;
|
||||
if (!mem_task) mem_task=Fs;
|
||||
f=MAlloc(sizeof(CFifoU8),mem_task);
|
||||
f->buf=MAlloc(size,mem_task);
|
||||
f->mask=size-1;
|
||||
f->in_ptr=0;
|
||||
f->out_ptr=0;
|
||||
return f;
|
||||
}
|
||||
|
||||
U0 FifoU8Del(CFifoU8 *f)
|
||||
{//Free fifo.
|
||||
Free(f->buf);
|
||||
Free(f);
|
||||
}
|
||||
|
||||
Bool FifoU8Ins(CFifoU8 *f,U8 b)
|
||||
{//Insert U8 into fifo.
|
||||
I64 new_in_ptr;
|
||||
PUSHFD
|
||||
CLI
|
||||
new_in_ptr=(f->in_ptr+1)&f->mask;
|
||||
if (new_in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
f->buf[f->in_ptr]=b;
|
||||
f->in_ptr=new_in_ptr;
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Bool FifoU8Rem(CFifoU8 *f,U8 *_b)
|
||||
{//Remove U8 from fifo.
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
*_b=f->buf[f->out_ptr];
|
||||
f->out_ptr=(f->out_ptr+1)&f->mask;
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Bool FifoU8Peek(CFifoU8 *f,U8 *_b)
|
||||
{//Peek at front of fifo and don't remove.
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
*_b=f->buf[f->out_ptr];
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 FifoU8Flush(CFifoU8 *f)
|
||||
{//Flush fifo getting rid of all U8's.
|
||||
PUSHFD
|
||||
CLI
|
||||
f->out_ptr=f->in_ptr;
|
||||
POPFD
|
||||
}
|
||||
|
||||
I64 FifoU8Cnt(CFifoU8 *f)
|
||||
{//Count of U8's in fifo.
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->out_ptr>f->in_ptr)
|
||||
res=f->mask+1-(f->out_ptr-f->in_ptr);
|
||||
else
|
||||
res=f->in_ptr-f->out_ptr;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
CFifoI64 *FifoI64New(I64 size,CTask *mem_task=NULL)
|
||||
{//Create new fifo.
|
||||
CFifoI64 *f;
|
||||
if (!mem_task) mem_task=Fs;
|
||||
f=MAlloc(sizeof(CFifoI64),mem_task);
|
||||
f->buf=MAlloc(size*sizeof(I64),mem_task);
|
||||
f->mask=size-1;
|
||||
f->in_ptr=0;
|
||||
f->out_ptr=0;
|
||||
return f;
|
||||
}
|
||||
|
||||
U0 FifoI64Del(CFifoI64 *f)
|
||||
{//Free fifo.
|
||||
Free(f->buf);
|
||||
Free(f);
|
||||
}
|
||||
|
||||
Bool FifoI64Ins(CFifoI64 *f,I64 q)
|
||||
{//Insert I64 into fifo.
|
||||
I64 new_in_ptr;
|
||||
PUSHFD
|
||||
CLI
|
||||
new_in_ptr=(f->in_ptr+1)&f->mask;
|
||||
if (new_in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
f->buf[f->in_ptr]=q;
|
||||
f->in_ptr=new_in_ptr;
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Bool FifoI64Rem(CFifoI64 *f,I64 *_q)
|
||||
{//Remove I64 from fifo.
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
*_q=f->buf[f->out_ptr];
|
||||
f->out_ptr=(f->out_ptr+1)&f->mask;
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
Bool FifoI64Peek(CFifoI64 *f,I64 *_q)
|
||||
{//Peek at front of fifo and don't remove.
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->in_ptr==f->out_ptr) {
|
||||
POPFD
|
||||
return FALSE;
|
||||
} else {
|
||||
*_q=f->buf[f->out_ptr];
|
||||
POPFD
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 FifoI64Flush(CFifoI64 *f)
|
||||
{//Flush fifo getting rid of all I64's.
|
||||
PUSHFD
|
||||
CLI
|
||||
f->out_ptr=f->in_ptr;
|
||||
POPFD
|
||||
}
|
||||
|
||||
I64 FifoI64Cnt(CFifoI64 *f)
|
||||
{//Count of I64's in fifo.
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (f->out_ptr>f->in_ptr)
|
||||
res=f->mask+1-(f->out_ptr-f->in_ptr);
|
||||
else
|
||||
res=f->in_ptr-f->out_ptr;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
//See $LK,"::/Doc/TimeDate.DD"$
|
||||
|
||||
U16 mon_start_days1[12]={
|
||||
0,31,59,90,120,151,181,212,243,273,304,334};
|
||||
U16 mon_start_days2[12]={
|
||||
0,31,60,91,121,152,182,213,244,274,305,335};
|
||||
|
||||
I64 YearStartDate(I64 year)
|
||||
{//32-bit day since AD 0, given year number.
|
||||
I64 y1=year-1,yd4000=y1/4000,yd400=y1/400,yd100=y1/100,yd4=y1/4;
|
||||
return year*365+yd4-yd100+yd400-yd4000;
|
||||
}
|
||||
|
||||
CDate Struct2Date(CDateStruct *_ds)
|
||||
{//Cvt CDateStruct to CDate.
|
||||
CDate cdt;
|
||||
I64 i1,i2;
|
||||
i1=YearStartDate(_ds->year);
|
||||
i2=YearStartDate(_ds->year+1);
|
||||
if (i2-i1==365)
|
||||
i1+=mon_start_days1[_ds->mon-1];
|
||||
else
|
||||
i1+=mon_start_days2[_ds->mon-1];
|
||||
cdt.date=i1+_ds->day_of_mon-1;
|
||||
cdt.time=(_ds->sec10000+100*(_ds->sec100+100*(_ds->sec
|
||||
+60*(_ds->min+60*_ds->hour))))<<21/(15*15*3*625);
|
||||
return cdt;
|
||||
}
|
||||
|
||||
I64 DayOfWeek(I64 i)
|
||||
{//Day of week, given 32-bit day since AD 0.
|
||||
i+=CDATE_BASE_DAY_OF_WEEK;
|
||||
if (i>=0)
|
||||
return i % 7;
|
||||
else
|
||||
return 6-(6-i)%7;
|
||||
}
|
||||
|
||||
U0 Date2Struct(CDateStruct *_ds,CDate cdt)
|
||||
{//Cvt CDate to CDateStruct.
|
||||
I64 i,k,date=cdt.date;
|
||||
_ds->day_of_week=DayOfWeek(date);
|
||||
_ds->year=(date+1)*100000/CDATE_YEAR_DAYS_INT;
|
||||
i=YearStartDate(_ds->year);
|
||||
while (i>date) {
|
||||
_ds->year--;
|
||||
i=YearStartDate(_ds->year);
|
||||
}
|
||||
date-=i;
|
||||
if (YearStartDate(_ds->year+1)-i==365) {
|
||||
k=0;
|
||||
while (date>=mon_start_days1[k+1] && k<11)
|
||||
k++;
|
||||
date-=mon_start_days1[k];
|
||||
} else {
|
||||
k=0;
|
||||
while (date>=mon_start_days2[k+1] && k<11)
|
||||
k++;
|
||||
date-=mon_start_days2[k];
|
||||
}
|
||||
_ds->mon=k+1;
|
||||
_ds->day_of_mon=date+1;
|
||||
k=(625*15*15*3*cdt.time)>>21+1;
|
||||
_ds->sec10000=ModU64(&k,100);
|
||||
_ds->sec100=ModU64(&k,100);
|
||||
_ds->sec=ModU64(&k,60);
|
||||
_ds->min=ModU64(&k,60);
|
||||
_ds->hour =k;
|
||||
}
|
||||
|
||||
I64 FirstDayOfMon(I64 i)
|
||||
{//First day of month, given 32-bit day since AD 0.
|
||||
CDateStruct ds;
|
||||
CDate cdt=0;
|
||||
cdt.date=i;
|
||||
Date2Struct(&ds,cdt);
|
||||
ds.day_of_mon=1;
|
||||
cdt=Struct2Date(&ds);
|
||||
return cdt.date;
|
||||
}
|
||||
|
||||
I64 LastDayOfMon(I64 i)
|
||||
{//Last day of month, given 32-bit day since AD 0.
|
||||
CDateStruct ds;
|
||||
CDate cdt=0;
|
||||
cdt.date=i;
|
||||
Date2Struct(&ds,cdt);
|
||||
ds.mon++;
|
||||
if (ds.mon==13) {
|
||||
ds.mon=0;
|
||||
ds.year++;
|
||||
}
|
||||
ds.day_of_mon=1;
|
||||
cdt=Struct2Date(&ds);
|
||||
return cdt.date-1;
|
||||
}
|
||||
|
||||
I64 FirstDayOfYear(I64 i)
|
||||
{//First day of year, given 32-bit day since AD 0.
|
||||
CDateStruct ds;
|
||||
CDate cdt=0;
|
||||
cdt.date=i;
|
||||
Date2Struct(&ds,cdt);
|
||||
ds.day_of_mon=1;
|
||||
ds.mon=1;
|
||||
cdt=Struct2Date(&ds);
|
||||
return cdt.date;
|
||||
}
|
||||
|
||||
I64 LastDayOfYear(I64 i)
|
||||
{//Last day of year, given 32-bit day since AD 0.
|
||||
CDateStruct ds;
|
||||
CDate cdt=0;
|
||||
cdt.date=i;
|
||||
Date2Struct(&ds,cdt);
|
||||
ds.day_of_mon=1;
|
||||
ds.mon=1;
|
||||
ds.year++;
|
||||
cdt=Struct2Date(&ds);
|
||||
return cdt.date-1;
|
||||
}
|
||||
|
||||
I64 Bcd2Bin(U64 b)
|
||||
{
|
||||
I64 i,res=0;
|
||||
for (i=0;i<16;i++) {
|
||||
res=res*10+b>>60;
|
||||
b<<=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 NowDateTimeStruct(CDateStruct *_ds)
|
||||
{
|
||||
I64 i;
|
||||
U8 *b=_ds;
|
||||
Bool is_bcd;
|
||||
|
||||
MemSet(_ds,0,sizeof(CDateStruct));
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_SYS_DATE],0))
|
||||
PAUSE
|
||||
|
||||
OutU8(0x70,0x0A);
|
||||
do {
|
||||
while (InU8(0x71) & 0x80)
|
||||
PAUSE
|
||||
|
||||
OutU8(0x70,0);
|
||||
b[2]=InU8(0x71);
|
||||
OutU8(0x70,2);
|
||||
b[3]=InU8(0x71);
|
||||
OutU8(0x70,4);
|
||||
b[4]=InU8(0x71);
|
||||
|
||||
OutU8(0x70,6);
|
||||
b[5]=InU8(0x71);
|
||||
OutU8(0x70,7);
|
||||
b[6]=InU8(0x71);
|
||||
OutU8(0x70,8);
|
||||
b[7]=InU8(0x71);
|
||||
OutU8(0x70,9);
|
||||
b[8]=InU8(0x71);
|
||||
|
||||
OutU8(0x70,0x0A);
|
||||
} while (InU8(0x71) & 0x80);
|
||||
|
||||
OutU8(0x70,0x0B);
|
||||
if (InU8(0x71) & 4)
|
||||
is_bcd=FALSE;
|
||||
else
|
||||
is_bcd=TRUE;
|
||||
|
||||
LBtr(&sys_semas[SEMA_SYS_DATE],0);
|
||||
POPFD
|
||||
if (is_bcd)
|
||||
for (i=2;i<9;i++)
|
||||
b[i]=Bcd2Bin(b[i]);
|
||||
|
||||
if (_ds->year>255) _ds->year=255;
|
||||
_ds->year+=2000;
|
||||
if (_ds->mon>12) _ds->mon=12;
|
||||
if (_ds->day_of_mon>31) _ds->day_of_mon=31;
|
||||
if (_ds->day_of_week>6) _ds->day_of_week=6;
|
||||
if (_ds->hour>23) _ds->hour=23;
|
||||
if (_ds->min>59) _ds->min=59;
|
||||
if (_ds->sec>59) _ds->sec=59;
|
||||
}
|
||||
|
||||
CDate Now()
|
||||
{//Current datetime.
|
||||
CDateStruct ds;
|
||||
NowDateTimeStruct(&ds);
|
||||
return Struct2Date(&ds)-local_time_offset;
|
||||
}
|
||||
@@ -0,0 +1,652 @@
|
||||
Bool ChkPtr(U8 *ptr)
|
||||
{//Check if addr is valid ptr.
|
||||
if (mem_heap_base<=ptr<=mem_mapped_space) {
|
||||
if (*MemPageTable(ptr)&1)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
} else if (ptr<mem_boot_base)
|
||||
return FALSE;
|
||||
else if (ptr<VGAM_GRAPHICS)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ChkCodePtr(U8 *ptr)
|
||||
{//Check if addr is valid code addr.
|
||||
if (mem_heap_base<=ptr<=mem_heap_limit) {
|
||||
if (*MemPageTable(ptr)&1)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
} else if (ptr<mem_boot_base)
|
||||
return FALSE;
|
||||
else if (ptr<VGAM_GRAPHICS)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ChkOnStk(U8 *ptr,CTask *task=NULL)
|
||||
{//Check if addr is valid stk addr.
|
||||
Bool res=FALSE;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (task) {
|
||||
if (&task->stk->stk_base<=ptr<=
|
||||
(&task->stk->stk_base)(U8 *)+task->stk->stk_size)
|
||||
res=TRUE;
|
||||
} else if (mem_heap_base<=ptr<=mem_heap_limit)
|
||||
res=TRUE;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 UnusedStk(CTask *task=NULL)
|
||||
{//Count of usused bytes in task's stk.
|
||||
I64 res;
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (task==Fs)
|
||||
res=GetRSP()(U8 *)-(&task->stk->stk_base)(U8 *);
|
||||
else
|
||||
res=task->rsp(U8 *)-(&task->stk->stk_base)(U8 *);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *Caller(I64 num=1)
|
||||
{//Returns the addr of the fun which called this one,
|
||||
//or the caller of the caller, etc.
|
||||
U8 **rbp=GetRBP,**ptr;
|
||||
while (num--) {
|
||||
if (rbp>=*rbp)
|
||||
return NULL;
|
||||
rbp=*rbp;
|
||||
if (!ChkOnStk(rbp,Fs))
|
||||
return NULL;
|
||||
}
|
||||
ptr=rbp+1;
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
U8 *TaskCaller(CTask *task=NULL,I64 num=0,Bool saved_context=FALSE)
|
||||
{//Fetches addr of Nth caller on task's stk.
|
||||
U8 **ptr,**rbp,**rsp;
|
||||
if (!task) task=Fs;
|
||||
if (!saved_context && task==Fs)
|
||||
return Caller(num+1);
|
||||
if (!TaskValidate(task))
|
||||
return NULL;
|
||||
rbp=task->rbp;
|
||||
rsp=task->rsp;
|
||||
if (num) {
|
||||
while (ChkOnStk(rbp,task)) {
|
||||
ptr=rbp+1;
|
||||
if (! --num)
|
||||
return *ptr;
|
||||
if (rbp>=*rbp)
|
||||
break;
|
||||
rbp=*rbp;
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
if (task->rip==_RET)
|
||||
return *rsp;
|
||||
else
|
||||
return task->rip;
|
||||
}
|
||||
}
|
||||
#define STK_REP_LEN 32
|
||||
|
||||
U0 StkRep(CTask *task=NULL)
|
||||
{//Reports whats on the stk.
|
||||
I64 i,j,addr,
|
||||
**rbp,**rsp,*my_rsp[STK_REP_LEN];
|
||||
CHashTable *old_hash=Fs->hash_table;
|
||||
if (!task) task=Fs;
|
||||
if (!TaskValidate(task))
|
||||
return;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (task==Fs) {
|
||||
rbp=GetRBP;
|
||||
rsp=rbp+3;
|
||||
rbp=*rbp;
|
||||
} else {
|
||||
rsp=task->rsp;
|
||||
rbp=task->rbp;
|
||||
}
|
||||
if (task->rip==_RET)
|
||||
addr=*rsp;
|
||||
else
|
||||
addr=task->rip;
|
||||
MemCpy(my_rsp,rsp,STK_REP_LEN*sizeof(U8 *));
|
||||
POPFD
|
||||
Fs->hash_table=task->hash_table;
|
||||
for (i=0;i<STK_REP_LEN;i++) {
|
||||
"%08X [RSP+%04X]: %016X ",rsp+i,
|
||||
i*sizeof(U8 *),my_rsp[i];
|
||||
while (TRUE) {
|
||||
if (!(&task->stk->stk_base<=rbp<
|
||||
(&task->stk->stk_base)(U8 *)+task->stk->stk_size))
|
||||
break;
|
||||
j=rbp-rsp;
|
||||
if (j>=i)
|
||||
break;
|
||||
addr=my_rsp[j+1];
|
||||
if (rbp>=my_rsp[j])
|
||||
break;
|
||||
rbp=my_rsp[j];
|
||||
}
|
||||
if (my_rsp[i]==addr)
|
||||
"$$RED$$";
|
||||
"%P$$FG$$\n",my_rsp[i];
|
||||
}
|
||||
'\n';
|
||||
Fs->hash_table=old_hash;
|
||||
}
|
||||
|
||||
U0 CallerRep(U8 **rbp=NULL,CTask *task=NULL)
|
||||
{//Prints a report of calling routines.
|
||||
I64 **ptr;
|
||||
if (!task) task=Fs;
|
||||
if (!rbp) {
|
||||
if (task==Fs)
|
||||
rbp=GetRBP;
|
||||
else
|
||||
rbp=task->rbp;
|
||||
}
|
||||
"CallerRep:\n";
|
||||
while (ChkOnStk(rbp,task)) {
|
||||
ptr=rbp+1;
|
||||
"%08X:%08tX:%P\n",ptr,*ptr,*ptr;
|
||||
if (rbp>=*rbp)
|
||||
break;
|
||||
rbp=*rbp;
|
||||
}
|
||||
}
|
||||
|
||||
U0 D(U8 *addr,I64 cnt=0x80,Bool show_offset=TRUE)
|
||||
{//Dump mem, showing offsets.
|
||||
//See $LK,"DocD",A="MN:DocD"$() for a live dump.
|
||||
I64 i,j,ch;
|
||||
U8 *ptr=addr;
|
||||
while (cnt) {
|
||||
if (show_offset)
|
||||
"%08X ",ptr-addr;
|
||||
else
|
||||
"%010X ",ptr;
|
||||
if (cnt>16)
|
||||
j=16;
|
||||
else
|
||||
j=cnt;
|
||||
for (i=0;i<j;i++)
|
||||
"%02X ",ptr[i];
|
||||
for (;i<16;i++)
|
||||
" ";
|
||||
for (i=0;i<j;i++) {
|
||||
ch=ptr[i];
|
||||
if (ch<CH_SHIFT_SPACE || ch==CH_BACKSPACE)
|
||||
ch='.';
|
||||
'' ch;
|
||||
if (ch=='$$')
|
||||
'' ch;
|
||||
}
|
||||
'\n';
|
||||
cnt-=j;
|
||||
ptr+=j;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Dm(U8 *addr,I64 cnt=0x80)
|
||||
{//Show mem addr, not offsets.
|
||||
D(addr,cnt,FALSE);
|
||||
}
|
||||
|
||||
U0 Da(U8 **addr,I64 cnt=0x10)
|
||||
{//Dump mem, showing symbolic addresses.
|
||||
while (cnt-->0) {
|
||||
"%08X:%08X,%P\n",addr,*addr,*addr;
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
U0 RawPrint(I64 mS=100,U8 *fmt,...)
|
||||
{//Print using $LK,"Raw",A="MN:Raw"$ scrn output for a length of time.
|
||||
//$BK,1$Your heap must be good.$BK,0$
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
Bool old_raw,old_input_filter;
|
||||
PUSHFD
|
||||
CLI
|
||||
old_raw=Raw(ON);
|
||||
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
|
||||
"%s",buf;
|
||||
Busy(mS<<10);
|
||||
POPFD
|
||||
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
|
||||
Raw(old_raw);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 RawD(I64 mS=100,U8 *addr,I64 cnt=0x80)
|
||||
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
|
||||
//scrn output for a fixed length
|
||||
//of time.
|
||||
Bool old_raw,old_input_filter;
|
||||
PUSHFD
|
||||
CLI
|
||||
old_raw=Raw(ON);
|
||||
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
|
||||
D(addr,cnt);
|
||||
Busy(mS<<10);
|
||||
POPFD
|
||||
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
|
||||
Raw(old_raw);
|
||||
}
|
||||
|
||||
U0 RawDm(I64 mS=100,U8 *addr,I64 cnt=0x80)
|
||||
{//Dumps a block of mem using $LK,"Raw",A="MN:Raw"$
|
||||
//scrn output for a fixed length
|
||||
//of time.
|
||||
Bool old_raw,old_input_filter;
|
||||
PUSHFD
|
||||
CLI
|
||||
old_raw=Raw(ON);
|
||||
old_input_filter=LBtr(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
|
||||
Dm(addr,cnt);
|
||||
Busy(mS<<10);
|
||||
POPFD
|
||||
LBEqu(&Fs->task_flags,TASKf_INPUT_FILTER_TASK,old_input_filter);
|
||||
Raw(old_raw);
|
||||
}
|
||||
|
||||
I64 *TaskRegAddr(CTask *task,I64 reg_num)
|
||||
{
|
||||
switch (reg_num) {
|
||||
case REG_RAX: return &task->rax;
|
||||
case REG_RCX: return &task->rcx;
|
||||
case REG_RDX: return &task->rdx;
|
||||
case REG_RBX: return &task->rbx;
|
||||
case REG_RSP: return &task->rsp;
|
||||
case REG_RBP: return &task->rbp;
|
||||
case REG_RSI: return &task->rsi;
|
||||
case REG_RDI: return &task->rdi;
|
||||
case 8 : return &task->r8;
|
||||
case 9 : return &task->r9;
|
||||
case 10: return &task->r10;
|
||||
case 11: return &task->r11;
|
||||
case 12: return &task->r12;
|
||||
case 13: return &task->r13;
|
||||
case 14: return &task->r14;
|
||||
case 15: return &task->r15;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define RAWDR_COL 40
|
||||
|
||||
U0 RawDr(CTask *task=NULL)
|
||||
{
|
||||
I64 i,j,old_col=text.raw_col;
|
||||
Bool old_raw=Raw(ON);
|
||||
U8 buf[200];
|
||||
|
||||
if (!task) task=Fs;
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
text.raw_col=i*text.cols+RAWDR_COL;
|
||||
"º%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
|
||||
}
|
||||
|
||||
text.raw_col=i++*text.cols+RAWDR_COL;
|
||||
"ºRIP:%016X\n",task->rip;
|
||||
|
||||
text.raw_col=i++*text.cols+RAWDR_COL;
|
||||
"º%-*tp\n",text.cols-(RAWDR_COL+1)-1,Fs->rip;
|
||||
|
||||
text.raw_col=i++*text.cols+RAWDR_COL;
|
||||
'º';
|
||||
if (Bt(&sys_run_level,RLf_COMPILER)) {
|
||||
j=Fs->rip;
|
||||
Ui(buf,&j,,,TRUE);
|
||||
"%s",buf;
|
||||
} else
|
||||
'\n';
|
||||
|
||||
text.raw_col=i*text.cols+RAWDR_COL;
|
||||
'È';
|
||||
for (j=0;j<text.cols-RAWDR_COL-1;j++)
|
||||
'Í';
|
||||
|
||||
text.raw_col=old_col;
|
||||
Raw(old_raw);
|
||||
}
|
||||
|
||||
U0 Dr(CTask *task=NULL)
|
||||
{//Dump regs
|
||||
I64 i;
|
||||
if (!task) task=Fs;
|
||||
for (i=0;i<16;i++)
|
||||
"%3Z:%016X\n",i,"ST_U64_REGS",*TaskRegAddr(task,i);
|
||||
"RIP:%016X\n",task->rip;
|
||||
}
|
||||
|
||||
U8 *SysGetStr2(I64)
|
||||
{
|
||||
U8 buf[512];
|
||||
GetS(buf,512,FALSE);
|
||||
return StrNew(buf);
|
||||
}
|
||||
|
||||
CBpt *BptFind(U8 *needle_addr,CTask *haystack_task=NULL,Bool rem=FALSE)
|
||||
{
|
||||
CBpt *res=NULL,*tmpb,*tmpb1,*tmpb2;
|
||||
if (!haystack_task) haystack_task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
tmpb1=&haystack_task->bpt_lst;
|
||||
tmpb=haystack_task->bpt_lst;
|
||||
while (tmpb) {
|
||||
tmpb2=tmpb->next;
|
||||
if (tmpb->addr==needle_addr) {
|
||||
res=tmpb;
|
||||
if (rem)
|
||||
tmpb1->next=tmpb2;
|
||||
else
|
||||
tmpb1=&tmpb->next;
|
||||
} else
|
||||
tmpb1=&tmpb->next;
|
||||
tmpb=tmpb2;
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool BptS(U8 *addr,CTask *task=NULL,Bool live=TRUE)
|
||||
{//Set breakpoint.
|
||||
CBpt *tmpb;
|
||||
Bool res=TRUE;
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (!(tmpb=BptFind(addr,task,FALSE))) {
|
||||
tmpb=CAlloc(sizeof(CBpt),task);
|
||||
tmpb->addr=addr;
|
||||
tmpb->val=*addr;
|
||||
res=FALSE;
|
||||
tmpb->next=task->bpt_lst;
|
||||
task->bpt_lst=tmpb;
|
||||
if (task==Fs && live)
|
||||
*addr=OC_BPT;
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool BptR(U8 *addr,CTask *task=NULL,Bool live=TRUE,Bool rem=TRUE)
|
||||
{//Rem breakpoint.
|
||||
CBpt *tmpb;
|
||||
Bool res=FALSE;
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (tmpb=BptFind(addr,task,rem)) {
|
||||
if (task==Fs && live)
|
||||
*tmpb->addr=tmpb->val;
|
||||
res=TRUE;
|
||||
if (rem)
|
||||
Free(tmpb);
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool B(U8 *addr,CTask *task=NULL,Bool live=TRUE)
|
||||
{//Toggle breakpoint.
|
||||
//Return: TRUE if removed.
|
||||
Bool res=FALSE;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (BptFind(addr,task,FALSE)) {
|
||||
BptR(addr,task,live,TRUE);
|
||||
res=TRUE;
|
||||
} else
|
||||
BptS(addr,task,live);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 B2(CTask *task=NULL,Bool live=TRUE)
|
||||
{//Rem all breakpoints.
|
||||
//Return: cnt of removed.
|
||||
I64 res=0;
|
||||
CBpt *tmpb,*tmpb1;
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
tmpb=task->bpt_lst;
|
||||
task->bpt_lst=NULL;
|
||||
while (tmpb) {
|
||||
tmpb1=tmpb->next;
|
||||
if (task==Fs && live)
|
||||
*tmpb->addr=tmpb->val;
|
||||
Free(tmpb);
|
||||
tmpb=tmpb1;
|
||||
res++;
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 G(U8 *ip=INVALID_PTR,CTask *task=NULL)
|
||||
{//Go
|
||||
if (!task) task=Fs;
|
||||
if (ip!=INVALID_PTR) task->rip=ip;
|
||||
if (BptFind(task->rip,task))
|
||||
"\nDo one of the following, first:\n"
|
||||
">S;\t\t\t//Single step\n"
|
||||
">B2;\t\t\t//Clear all break points\n"
|
||||
">G2;\t\t\t//Clear all break points and Go\n\n"
|
||||
"After resuming, <CTRL-ALT-n> next focus task\n"
|
||||
"After resuming, <CTRL-ALT-v> flushes scrn VGA cache\n";
|
||||
else {
|
||||
LBtr(&task->task_flags,TASKf_DISABLE_BPTS);
|
||||
LBtr(&task->rflags,RFLAGf_TRAP);//No single step
|
||||
Suspend(task,FALSE);
|
||||
if (task==Fs) {
|
||||
if (IsDbgMode && task->next_cc!=&task->next_cc) {
|
||||
"Exit Dbg\n";
|
||||
Btr(&task->last_cc->flags,CCf_PMT);
|
||||
}
|
||||
} else
|
||||
Exit;
|
||||
}
|
||||
}
|
||||
|
||||
U0 G2(U8 *ip=INVALID_PTR,CTask *task=NULL)
|
||||
{//Rem all breakpoints and Go.
|
||||
if (!task) task=Fs;
|
||||
B2(task);
|
||||
if (ext[EXT_WIN_FOCUS])
|
||||
CallExtNum(EXT_WIN_FOCUS,dbg.focus_task);
|
||||
VGAFlush;
|
||||
G(ip,task);
|
||||
}
|
||||
|
||||
public U0 S(U8 *ip=INVALID_PTR,CTask *task=NULL) //Single-step.
|
||||
{//Single step.
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (ip!=INVALID_PTR) task->rip=ip;
|
||||
LBts(&task->task_flags,TASKf_DISABLE_BPTS);
|
||||
LBts(&task->rflags,RFLAGf_TRAP);
|
||||
Suspend(task,FALSE);
|
||||
if (task==Fs) {
|
||||
if (IsDbgMode) {
|
||||
if (task->next_cc!=&task->next_cc)
|
||||
Btr(&task->last_cc->flags,CCf_PMT);
|
||||
}
|
||||
} else
|
||||
Exit;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 DbgHelp()
|
||||
{
|
||||
"\n"
|
||||
"The cmd line is basically the same as normal. Here are some common\n"
|
||||
"debugging commands.\n\n"
|
||||
">EdLite(\"FileName\");\t\t//Edit file.\n"
|
||||
">D(0x100000);\t\t\t//Dump page tables.\n"
|
||||
">Dm(0x100000);\t\t\t//Dump page tables.\n"
|
||||
">Dm(Fs,sizeof(CTask));\t\t//Dump current task record.\n"
|
||||
">ClassRep(Fs,\"CTask\",1);\t//Dump current task record.\n"
|
||||
">ClassRep(Fs,,1);\t\t//(It knows lastclass.)\n"
|
||||
">CallerRep;\t\t\t//Stack trace report.\n"
|
||||
">Da(_RSP);\t\t\t//Dump stk.\n"
|
||||
">Dr;\t\t\t\t//Dump Regs.\n"
|
||||
">1+2*3+&Print;\t\t\t//Show calculation res.\n"
|
||||
">*(0x70000)(I64 *)=0x123456789;\t//Assign value to 0x70000-0x70007.\n"
|
||||
">_RAX=0x1234;\t\t\t//Set RAX to 0x1234.\n"
|
||||
">_RIP=&Break;\t\t//Set RIP.\n"
|
||||
">I64 i;\t\t\t\t//Declare variable.\n"
|
||||
">i=_RCX+_RDX;\t\t\t//Assign to variable.\n"
|
||||
">U(&Print+0x8);\t\t\t//Unassemble Print.\n"
|
||||
">Uf(\"Print\");\t\t\t//Unassembler function \"Print\".\n"
|
||||
">Man(\"Print\");\t\t\t//Edit Src for \"Print\".\n"
|
||||
">E(_RIP);\t\t\t//Edit Src Code.\n"
|
||||
">Fix;\t\t\t\t//Edit Last Err Src Code.\n"
|
||||
">B(&Main+0x20);\t\t\t//Toggle break point.\n"
|
||||
">B2;\t\t\t\t//Clear all break points.\n"
|
||||
">S;\t\t\t\t//Single step.\n"
|
||||
">G;\t\t\t\t//Resume execution.\n"
|
||||
">G2;\t\t\t\t//B2;VGAFlush;WinFocus;G;\n"
|
||||
">Exit;\t\t\t\t//Exit (kill) task.\n\n"
|
||||
"After resuming, <CTRL-ALT-n> next focus task.\n"
|
||||
"After resuming, <CTRL-ALT-v> flushes scrn VGA cache.\n\n";
|
||||
}
|
||||
|
||||
U0 Dbg2()
|
||||
{
|
||||
Bool old_win_inhibit,old_waiting_msg,old_single;
|
||||
I64 i,old_getstr2;
|
||||
U8 buf[200];
|
||||
if (dbg.panic) {
|
||||
if (IsRaw) {
|
||||
i=Fs->rip;
|
||||
Ui(buf,&i);
|
||||
"%s",buf;
|
||||
} else
|
||||
U(Fs->rip,1);
|
||||
} else
|
||||
dbg.panic=TRUE;
|
||||
old_waiting_msg=LBtr(&Fs->task_flags,TASKf_AWAITING_MSG);
|
||||
old_win_inhibit=Fs->win_inhibit;
|
||||
Fs->win_inhibit=WIG_USER_TASK_DFT;
|
||||
sys_focus_task=Fs;
|
||||
kbd.scan_code=0;
|
||||
old_getstr2=fp_getstr2;
|
||||
fp_getstr2=&SysGetStr2;
|
||||
old_single=SingleUser(OFF);
|
||||
while (!ms_hard.install_attempts)
|
||||
Yield;
|
||||
SingleUser(old_single);
|
||||
UserTaskCont;
|
||||
fp_getstr2=old_getstr2;
|
||||
Fs->win_inhibit=old_win_inhibit;
|
||||
LBEqu(&Fs->task_flags,TASKf_AWAITING_MSG,old_waiting_msg);
|
||||
}
|
||||
|
||||
U0 Fault3(I64 fault_num,I64 fault_err_code)
|
||||
{
|
||||
no_warn fault_err_code;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (Gs->num && dbg.mp_crash) {
|
||||
mp_cnt=1;
|
||||
dbg.mp_crash->cpu_num=Gs->num;
|
||||
dbg.mp_crash->task=Fs;
|
||||
dbg.mp_crash->rip=Fs->rip;
|
||||
dbg.mp_crash->msg=dbg.msg;
|
||||
dbg.mp_crash->msg_num=dbg.msg_num;
|
||||
MPInt(I_MP_CRASH,0);
|
||||
SysHlt;
|
||||
}
|
||||
"\n\tTempleOS Debugger\n\n"
|
||||
">Help;\t//For help.\n\n";
|
||||
Beep(62,TRUE);
|
||||
if (fault_num==I_DBG) {
|
||||
if (dbg.msg) {
|
||||
"\n!!! %s",dbg.msg;
|
||||
if (dbg.msg_num)
|
||||
"%016X",dbg.msg_num;
|
||||
" !!!\n\n";
|
||||
}
|
||||
}
|
||||
if (dbg.panic)
|
||||
CallerRep;
|
||||
Dbg2;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 Fault2(I64 fault_num,I64 fault_err_code)
|
||||
{//Called from $LK,"Fault2",A="FF:::/Kernel/KInts.HC,Fault2"$.
|
||||
//$BK,1$Be careful not to swap-out and ruin the saved context$BK,0$
|
||||
Bool was_raw,was_single_user,was_silent,was_in_dbg;
|
||||
I64 i,old_raw_flags=text.raw_flags;
|
||||
was_single_user=SingleUser(ON);
|
||||
if (!IsDbgMode)
|
||||
dbg.focus_task=sys_focus_task;
|
||||
sys_focus_task=NULL;
|
||||
if (fault_num==I_BPT)
|
||||
Fs->rip--;
|
||||
if (Fs->dbg_task)
|
||||
CallExtNum(EXT_DBG_RESUME,fault_num,fault_err_code);
|
||||
else {
|
||||
was_raw=Raw(ON);
|
||||
was_silent=Silent(OFF);
|
||||
text.raw_flags|=RWF_SHOW_DOLLAR|RWF_SCROLL;
|
||||
|
||||
"Task \"";
|
||||
"%s",Fs->task_title;
|
||||
"\"\n";
|
||||
"Fault:0x%02X %Z\t\tErr Code:%08X\n",
|
||||
fault_num,fault_num,"ST_INT_NAMES",fault_err_code;
|
||||
was_in_dbg=DbgMode(ON);
|
||||
"RIP:%08X",Fs->rip; //Sometimes crashes on %p, so do this first
|
||||
":%p RSP:%08X\n",Fs->rip,Fs->rsp;
|
||||
if (fault_num==I_PAGE_FAULT) {
|
||||
MOV_RAX_CR2
|
||||
i=GetRAX;
|
||||
"Fault Addr:%08X:%p\n",i,i;
|
||||
}
|
||||
Fault3(fault_num,fault_err_code);
|
||||
DbgMode(was_in_dbg);
|
||||
Silent(was_silent);
|
||||
Raw(was_raw);
|
||||
text.raw_flags=old_raw_flags;
|
||||
}
|
||||
SingleUser(was_single_user);
|
||||
if (LBtr(&Fs->task_flags,TASKf_KILL_AFTER_DBG))
|
||||
Exit;
|
||||
}
|
||||
|
||||
U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE)
|
||||
{//Enter the debugger with panic?
|
||||
PUSHFD
|
||||
CLI
|
||||
dbg.msg=msg;
|
||||
dbg.msg_num=msg_num;
|
||||
dbg.panic=panic;
|
||||
INT I_DBG
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 Dbg(U8 *msg=NULL,I64 msg_num=0)
|
||||
{//Enter debugger, no panic.
|
||||
Panic(msg,msg_num,FALSE);
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
CHashDefineStr *DefineLoad(U8 *dname,U8 *st)
|
||||
{//Create DEFINE hash entry with string.
|
||||
CHashDefineStr *tmph=CAlloc(sizeof(CHashDefineStr));
|
||||
tmph->type=HTT_DEFINE_STR;
|
||||
tmph->str=StrNew(dname);
|
||||
tmph->data=StrNew(st);
|
||||
tmph->cnt=-1;
|
||||
tmph->src_link=MStrPrint("AD:0x%X",Caller);
|
||||
HashAdd(tmph,Fs->hash_table);
|
||||
return tmph;
|
||||
}
|
||||
|
||||
CHashDefineStr *DefineLstLoad(U8 *dname,U8 *lst)
|
||||
{//Create DEFINE list. Not efficient, but handy.
|
||||
I64 cnt=0;
|
||||
U8 *ptr,**idx;
|
||||
CHashDefineStr *tmph=CAlloc(sizeof(CHashDefineStr));
|
||||
tmph->type=HTT_DEFINE_STR;
|
||||
tmph->str=StrNew(dname);
|
||||
tmph->src_link=MStrPrint("AD:0x%X",Caller);
|
||||
ptr=lst;
|
||||
while (*ptr) {
|
||||
if (*ptr!='@')
|
||||
cnt++;
|
||||
while (*ptr++);
|
||||
}
|
||||
tmph->data=MAlloc(ptr+1-lst);
|
||||
MemCpy(tmph->data,lst,ptr+1-lst);
|
||||
tmph->cnt=cnt;
|
||||
|
||||
idx=tmph->sub_idx=MAlloc(cnt*sizeof(U8 *));
|
||||
ptr=lst;
|
||||
while (*ptr) {
|
||||
if (*ptr!='@')
|
||||
*idx++=ptr;
|
||||
while (*ptr++);
|
||||
}
|
||||
|
||||
HashAdd(tmph,Fs->hash_table);
|
||||
return tmph;
|
||||
}
|
||||
|
||||
U0 UndefinedDefine(U8 *dname)
|
||||
{
|
||||
ST_ERR_ST "Undefined Define: '%s'.\n",dname;
|
||||
throw('UndefDef');
|
||||
}
|
||||
|
||||
U8 *Define(U8 *dname)
|
||||
{//Look for DEFINE named in hash table, return ptr string.
|
||||
CHashDefineStr *tmph;
|
||||
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
|
||||
return tmph->data;
|
||||
else if (dname)
|
||||
UndefinedDefine(dname);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8 *DefineSub(I64 sub,U8 *dname)
|
||||
{//Return DEFINE list entry indexed by number.
|
||||
CHashDefineStr *tmph;
|
||||
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR)) {
|
||||
if (0<=sub<tmph->cnt)
|
||||
return tmph->sub_idx[sub];
|
||||
else
|
||||
return NULL;
|
||||
} else if (dname)
|
||||
UndefinedDefine(dname);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 DefineCnt(U8 *dname)
|
||||
{//Return cnt of entries in define list.
|
||||
CHashDefineStr *tmph;
|
||||
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
|
||||
return tmph->cnt;
|
||||
else if (dname)
|
||||
UndefinedDefine(dname);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0)
|
||||
{//Find match for string in define list.
|
||||
return LstMatch(needle,Define(haystack_lst_dname),flags);
|
||||
}
|
||||
|
||||
U0 DefinePrint(U8 *dname,U8 *src,...)
|
||||
{//Create DEFINE entry with $LK,"Print",A="FI:::/Doc/Print.DD"$()ed string.
|
||||
U8 *buf=StrPrintJoin(NULL,src,argc,argv);
|
||||
DefineLoad(dname,buf);
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 SysDefinesLoad()
|
||||
{
|
||||
DefineLstLoad("ST_OFF_ON","Off\0On\0");
|
||||
DefineLstLoad("ST_HTT_TYPES","ExportSysSym\0ImportSysSym\0DefineStr\0GlbVar\0"
|
||||
"Class\0IntType\0Funct\0Word\0DictWord\0KeyWord\0AsmKeyWord\0OpCode\0"
|
||||
"Reg\0File\0Module\0HelpFile\0Frame Ptr\0 \0 \0 \0 \0 \0 \0Private\0"
|
||||
"Public\0Export\0Import\0Imm\0Goto\0Res\0Unres\0Local\0");
|
||||
DefineLstLoad("ST_DAYS_OF_WEEK","Sunday\0Monday\0Tuesday\0Wednesday\0"
|
||||
"Thursday\0Friday\0Saturday\0");
|
||||
DefineLstLoad("ST_MONTHS","January\0February\0March\0April\0May\0"
|
||||
"June\0July\0August\0September\0October\0November\0December\0");
|
||||
DefineLstLoad("ST_FILE_ATTRS","R\0H\0S\0V\0D\0A\0 \0 \0X\0T\0Z\0C\0F\0");
|
||||
DefineLstLoad("ST_FILE_UTIL_FLAGS","r\0d\0i\0a\0c\0R\0p\0m\0x\0s\0"
|
||||
"D\0F\0T\0$$\0S\0A\0J\0G\0Z\0O\0P\0f\0l\0lb\0la\0");
|
||||
DefineLstLoad("ST_BLKDEV_TYPES",
|
||||
"NULL\0RAM\0ATA\0FILE_READ\0FILE_WRITE\0ATAPI\0");
|
||||
DefineLstLoad("ST_DRV_TYPES",
|
||||
"NULL\0REDSEA\0FAT32\0ISO9660\0ISO13490\0ISO13346\0NTFS\0UNKNOWN\0");
|
||||
DefineLstLoad("ST_COLORS","BLACK\0BLUE\0GREEN\0CYAN\0"
|
||||
"RED\0PURPLE\0BROWN\0LTGRAY\0DKGRAY\0LTBLUE\0LTGREEN\0"
|
||||
"LTCYAN\0LTRED\0LTPURPLE\0YELLOW\0WHITE\0");
|
||||
DefineLstLoad("ST_INT_NAMES","Divide Error\0SingleStep\0NMI\0Breakpoint\0"
|
||||
"Overflow\0BOUND Range Exceeded\0Invalid Opcode\0No Math Coprocessor\0"
|
||||
"Double Fault\0Coprocessor Segment Fault\0Invalid TASK\0"
|
||||
"Segment Not Present\0Stk Segment Fault\0General Protection\0"
|
||||
"Page Fault\0 \0Math Fault\0Alignment Check\0Machine Check\0"
|
||||
"SIMD Exception\0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0"
|
||||
" \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0MP Crash\0Wake\0Dbg\0");
|
||||
}
|
||||
|
||||
U8 *Color2Str(U8 *buf,CColorROPU32 c)
|
||||
{//$LK,"CColorROPU32",A="MN:CColorROPU32"$ with flags to $LK,"DCLighting",A="MN:DCLighting"$ str.
|
||||
*buf=0;
|
||||
if (c.c0.rop&ROPBF_TWO_SIDED)
|
||||
CatPrint(buf,"TWO|");
|
||||
if (c.c0.rop&ROPBF_HALF_RANGE_COLOR)
|
||||
CatPrint(buf,"HALF|");
|
||||
if (0<=c.c0.color<16)
|
||||
CatPrint(buf,DefineSub(c.c0.color,"ST_COLORS"));
|
||||
else if (c.c0.color==TRANSPARENT)
|
||||
CatPrint(buf,"TRANSPARENT");
|
||||
else
|
||||
CatPrint(buf,"INVALID");
|
||||
if (c&ROPF_DITHER) {
|
||||
CatPrint(buf,"/");
|
||||
if (c.c1.rop&ROPBF_TWO_SIDED)
|
||||
CatPrint(buf,"TWO|");
|
||||
if (c.c1.rop&ROPBF_HALF_RANGE_COLOR)
|
||||
CatPrint(buf,"HALF|");
|
||||
if (0<=c.c1.color<16)
|
||||
CatPrint(buf,DefineSub(c.c1.color,"ST_COLORS"));
|
||||
else if (c.c1.color==TRANSPARENT)
|
||||
CatPrint(buf,"TRANSPARENT");
|
||||
else
|
||||
CatPrint(buf,"INVALID");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
U8 *str2color_lst="/,)}>";
|
||||
|
||||
CColorROPU16 Str2ColorU16(U8 *st)
|
||||
{//$LK,"DCLighting",A="MN:DCLighting"$ color str with flags to $LK,"CColorROPU16",A="MN:CColorROPU16"$.
|
||||
CColorROPU16 res=COLOR_INVALID;
|
||||
I64 i;
|
||||
U8 *ptr,*ptr2,*st2;
|
||||
if (!st) return COLOR_INVALID;
|
||||
while (TRUE) {
|
||||
if (!*st||StrOcc(str2color_lst,*st))
|
||||
return res;
|
||||
if (Bt(char_bmp_alpha,*st)) {
|
||||
ptr=st;
|
||||
while (Bt(char_bmp_alpha_numeric,*ptr))
|
||||
ptr++;
|
||||
st2=ptr2=MAlloc(ptr-st+1);
|
||||
while (st<ptr)
|
||||
*ptr2++=*st++;
|
||||
*ptr2++=0;
|
||||
if (!StrICmp(st2,"TWO"))
|
||||
res.rop|=ROPBF_TWO_SIDED;
|
||||
else if (!StrICmp(st2,"HALF"))
|
||||
res.rop|=ROPBF_HALF_RANGE_COLOR;
|
||||
else if ((i=DefineMatch(st2,"ST_COLORS",LMF_IGNORE_CASE))>=0)
|
||||
res.color=i;
|
||||
else if (!StrICmp(st2,"TRANSPARENT"))
|
||||
res.color=TRANSPARENT;
|
||||
else {
|
||||
Free(st2);
|
||||
return COLOR_INVALID;
|
||||
}
|
||||
Free(st2);
|
||||
} else if (*st=='+'||*st=='|'||Bt(char_bmp_white_space,*st))
|
||||
st++;
|
||||
else if ('0'<=*st<='9') {
|
||||
i=Str2I64(st,10,&ptr);
|
||||
if (0<=i<=0xFF) {
|
||||
res.color=i;
|
||||
st=ptr;
|
||||
} else
|
||||
return COLOR_INVALID;
|
||||
} else
|
||||
return COLOR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
CColorROPU32 Str2ColorU32(U8 *st)
|
||||
{//$LK,"DCLighting",A="MN:DCLighting"$ color str with flags to $LK,"CColorROPU32",A="MN:CColorROPU32"$.
|
||||
U8 *st2;
|
||||
CColorROPU32 res=0;
|
||||
if (!st) return COLOR_INVALID;
|
||||
st2=MAlloc(StrLen(st)+1);
|
||||
StrFirstRem(st,str2color_lst,st2);
|
||||
res.c0=Str2ColorU16(st2);
|
||||
if (*st) {
|
||||
res.c1=Str2ColorU16(st);
|
||||
res|=ROPF_DITHER;
|
||||
}
|
||||
if (res.c0.color==COLOR_INVALID||res.c1.color==COLOR_INVALID)
|
||||
return COLOR_INVALID;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
U0 SysGlblsInit()
|
||||
{
|
||||
I64 i,j;
|
||||
CRAXRBCRCXRDX ee;
|
||||
|
||||
CPUId(0x1,&ee);
|
||||
sys_cache_line_width=ee.rbx.u8[1]*8;
|
||||
|
||||
sys_focus_task=Fs;
|
||||
QueInit(&sys_macro_head);
|
||||
|
||||
blkdev.dft_iso_filename =AStrNew(DFT_ISO_FILENAME);
|
||||
blkdev.dft_iso_c_filename =AStrNew(DFT_ISO_C_FILENAME);
|
||||
blkdev.tmp_filename =AStrNew("~/Tmp.DD.Z");
|
||||
blkdev.dvd_boot_is_good=TRUE;
|
||||
#exe {
|
||||
if (!kernel_cfg->auto_mount_ide_hd_let)
|
||||
kernel_cfg->auto_mount_ide_hd_let='C';
|
||||
if (!kernel_cfg->auto_mount_ide_cd_let)
|
||||
kernel_cfg->auto_mount_ide_cd_let='T';
|
||||
StreamPrint("blkdev.first_hd_drv_let=%d;",
|
||||
kernel_cfg->auto_mount_ide_hd_let);
|
||||
StreamPrint("blkdev.first_dvd_drv_let=%d;",
|
||||
kernel_cfg->auto_mount_ide_cd_let);
|
||||
}
|
||||
|
||||
DbgMode(ON);
|
||||
rev_bits_table=CAlloc(256);
|
||||
set_bits_table=CAlloc(256);
|
||||
for (i=0;i<256;i++)
|
||||
for (j=0;j<8;j++) {
|
||||
if (Bt(&i,7-j)) LBts(rev_bits_table+i,j);
|
||||
if (Bt(&i,j)) set_bits_table[i]++;
|
||||
}
|
||||
|
||||
ext=CAlloc(EXT_EXTS_NUM*sizeof(U8 *));
|
||||
fp_getstr2=&SysGetStr2;
|
||||
KeyDevInit;
|
||||
|
||||
#exe {
|
||||
StreamPrint("blkdev.boot_drv_let='%C';",kernel_cfg->boot_drv_let);
|
||||
StreamPrint("#exe{Option(OPTf_WARN_PAREN,OFF);}");
|
||||
StreamPrint("DskCacheInit(%s);",kernel_cfg->dsk_cache_size_exp);
|
||||
StreamPrint("#exe{Option(OPTf_WARN_PAREN,ON);}");
|
||||
};
|
||||
|
||||
pow10_I64=CAlloc(sizeof(F64)*(308+308+1));
|
||||
for (i=-308;i<309;i++)
|
||||
pow10_I64[i+309]=Pow10(i);
|
||||
|
||||
snd.ona=ONA_REST;
|
||||
QueInit(&snd.record_head);
|
||||
snd.record_head.time=tS;
|
||||
|
||||
ProgressBarsRst;
|
||||
|
||||
QueInit(&dev.pci_head);
|
||||
dev.mem64_ptr=mem_mapped_space;
|
||||
|
||||
dbg.fun_seg_cache=CAlloc(FUN_SEG_CACHE_SIZE*sizeof(CFunSegCache));
|
||||
dbg.int_fault_code=IntFaultHndlrsNew;
|
||||
}
|
||||
|
||||
U0 SysGrInit()
|
||||
{
|
||||
text.font=sys_font_std;
|
||||
text.aux_font=sys_font_cyrillic;
|
||||
text.vga_alias =dev.uncached_alias+VGAM_GRAPHICS;
|
||||
text.vga_text_alias =dev.uncached_alias+VGAM_TEXT;
|
||||
if (!Bt(&sys_run_level,RLf_VGA)) { //if text mode
|
||||
text.cols=80;
|
||||
text.rows=25;
|
||||
MemSet(text.vga_text_alias,0,text.rows*text.cols<<1);
|
||||
text.border_chars[2] (I64)='ÄͳºÚÉ¿»';
|
||||
text.border_chars[10](U32)='ÀÈÙ¼';
|
||||
} else { //if 640x480 16 color
|
||||
text.cols=GR_WIDTH/FONT_WIDTH;
|
||||
text.rows=GR_HEIGHT/FONT_HEIGHT;
|
||||
OutU8(VGAP_IDX,VGAR_MAP_MASK);
|
||||
OutU8(VGAP_DATA,0x0F);
|
||||
MemSet(text.vga_alias,0,GR_WIDTH*GR_HEIGHT>>3);
|
||||
text.raw_scrn_image=CAlloc(GR_WIDTH*GR_HEIGHT/8);
|
||||
text.border_chars[2] (I64)=0x0908070605040302;
|
||||
text.border_chars[10](U32)=0x0D0C0B0A;
|
||||
}
|
||||
}
|
||||
|
||||
U0 TimersInit()
|
||||
{
|
||||
I64 i,*_q;
|
||||
U32 *_d;
|
||||
|
||||
OutU8(0x43,0x34);
|
||||
OutU8(0x40,SYS_TIMER0_PERIOD);
|
||||
OutU8(0x40,SYS_TIMER0_PERIOD>>8);
|
||||
|
||||
//High Precision Event Timer
|
||||
if (PCIReadU16(0,31,0,0)==0x8086) {//Intel?
|
||||
//D31 F0, cfg 0xF0=RCBA of PCI-LPC Bridge
|
||||
_d=PCIReadU32(0,31,0,0xF0)(U8 *)&~0x3FFF+0x3404; //HPET cfg
|
||||
//7 enable
|
||||
//1:0 HPET is at 0xFED00000,0xFED01000, 0xFED02000 or 0xFED03000.
|
||||
*_d=*_d&3|0x80;
|
||||
}
|
||||
|
||||
_q=dev.uncached_alias+HPET_GCAP_ID;
|
||||
i=*_q; //i.u32[1]= period in femtoS (10e-15)
|
||||
if (100000<i.u32[1]<1000000000) {
|
||||
cnts.HPET_freq =1000000000000000/i.u32[1];
|
||||
cnts.HPET_kHz_freq=1000000000000/i.u32[1];
|
||||
_q=dev.uncached_alias+HPET_GEN_CONF;
|
||||
*_q|=1; //Enable counting
|
||||
cnts.HPET_initial=HPET;
|
||||
} else {
|
||||
cnts.HPET_freq=0;
|
||||
cnts.HPET_kHz_freq=0;
|
||||
cnts.HPET_initial=0;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Reboot()
|
||||
{//Hardware reset.
|
||||
CLI
|
||||
if (mp_cnt>1)
|
||||
MPHalt;
|
||||
*0x472(U16 *)=0;
|
||||
OutU8(0x70,0x8F);
|
||||
OutU8(0x71,0x00);
|
||||
OutU8(0x70,0x00);
|
||||
OutU8(0x92,InU8(0x92)|1);
|
||||
SysHlt;
|
||||
}
|
||||
|
||||
U0 KMain()
|
||||
{//Continued from $LK,"KStart64.HC",A="FF:::/Kernel/KStart64.HC,I32 &KMain"$
|
||||
CBlkDev *bd;
|
||||
OutU8(0x61,InU8(0x61)&~3); //Snd;
|
||||
adam_task=Fs;
|
||||
BlkPoolsInit;
|
||||
SysGlblsInit;
|
||||
Mem32DevInit;
|
||||
UncachedAliasAlloc;
|
||||
LoadKernel;
|
||||
SysGrInit;
|
||||
StrCpy(Fs->task_name,"Adam Task CPU00");
|
||||
StrCpy(Fs->task_title,Fs->task_name);
|
||||
Fs->title_src=TTS_TASK_NAME;
|
||||
Fs->win_right=text.cols-2;
|
||||
Fs->win_top++;
|
||||
TaskDerivedValsUpdate;
|
||||
|
||||
SysDefinesLoad;
|
||||
Core0Init;
|
||||
IntInit1;
|
||||
|
||||
//Before this point use $LK,"Snd",A="MN:Snd"$() and $LK,"Busy",A="MN:Busy"$()
|
||||
//to debug. After this point, use $LK,"RawPrint",A="MN:RawPrint"$()
|
||||
LBts(&sys_run_level,RLf_RAW);
|
||||
"TempleOS V%5.3f\t%D %T\n\n",
|
||||
sys_os_version,sys_compile_time,sys_compile_time;
|
||||
|
||||
TimersInit;
|
||||
if (BIOSTotalMem<ToI64(0.95*MEM_MIN_MEG*0x100000))
|
||||
RawPrint(4000,"!!! Requires $TX,"512Meg",D="DD_MEM_MIN_MEG"$ of RAM Memory !!!");
|
||||
|
||||
IntsInit;
|
||||
"Enable IRQ's\n";
|
||||
SetRFlags(RFLAGG_NORMAL);
|
||||
Busy(2000);
|
||||
IntInit2;
|
||||
LBts(&sys_run_level,RLf_INTERRUPTS);
|
||||
|
||||
TimeStampFreqCal;
|
||||
BlkDevsInitAll;
|
||||
"ChgDsk(':');\n";
|
||||
ChgDsk(':');
|
||||
#exe {
|
||||
StreamPrint("HomeSet(\"%s\");\n"
|
||||
"blkdev.ins_base0=%d;blkdev.ins_base1=%d;blkdev.ins_unit =%d;\n",
|
||||
kernel_cfg->home_dir,
|
||||
blkdev.ins_base0,blkdev.ins_base1,blkdev.ins_unit);
|
||||
}
|
||||
Gs->idle_task->cur_dv=blkdev.let_to_drv[*blkdev.home_dir-'A'];
|
||||
DrvRep;
|
||||
if (blkdev.dvd_boot_is_good) {
|
||||
bd=Let2BlkDev(':');
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
blkdev.ins_base0=bd->base0;
|
||||
blkdev.ins_base1=bd->base1;
|
||||
blkdev.ins_unit =bd->unit;
|
||||
}
|
||||
}
|
||||
LBts(&sys_run_level,RLf_BLKDEV);
|
||||
|
||||
#exe {
|
||||
if (!kernel_cfg->opts[CFG_NO_MP])
|
||||
StreamPrint("\"MultiCore Start\\n\\n\";"
|
||||
"Core0StartMP;"
|
||||
"LBts(&sys_run_level,RLf_MP);");
|
||||
};
|
||||
|
||||
KbdMsInit;
|
||||
MsInit;
|
||||
KbdInit;
|
||||
Spawn(&MsHardDrvrInstall);
|
||||
|
||||
"Loading Compiler\n";
|
||||
Cd("/Compiler");
|
||||
Load("Compiler",LDF_SILENT);
|
||||
LBts(&sys_run_level,RLf_COMPILER);
|
||||
|
||||
DbgMode(OFF);
|
||||
cnts.time_stamp_freq_initial=TimeStampFreqCal;
|
||||
Cd("/");
|
||||
try ExeFile("StartOS"); //Continues $LK,"/StartOS.HC",A="FL:/StartOS.HC,1"$
|
||||
catch {
|
||||
Raw(ON);
|
||||
Silent(OFF);
|
||||
GetOutOfDollar;
|
||||
PutExcept;
|
||||
Dbg;
|
||||
}
|
||||
|
||||
LBts(&sys_run_level,RLf_ADAM_SERVER);
|
||||
SrvTaskCont; //Never to return
|
||||
}
|
||||
|
||||
asm { ALIGN 16,OC_NOP
|
||||
SYS_KERNEL_END::
|
||||
#exe {
|
||||
if (kernel_cfg->opts[CFG_DBG_DISTRO])
|
||||
StreamPrint("DU8 0x%X-(SYS_KERNEL_END-SYS_KERNEL+"
|
||||
"BOOT_RAM_BASE+sizeof(CBinFile)) DUP (0);"
|
||||
"BINFILE \"%s\";",kernel_cfg->dbg_distro_start,
|
||||
kernel_cfg->dbg_distro_file);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
asm {
|
||||
#assert !((REGG_LOCAL_NON_PTR_VARS|REGG_LOCAL_VARS)&~0xFCC0)
|
||||
_TEST_EXCEPT::
|
||||
XOR RAX,RAX
|
||||
MOV RAX,FS:U64 CTask.last_except[RAX]
|
||||
MOV RBP,U64 CExcept.rbp[RAX]
|
||||
MOV RSI,U64 CExcept.rsi[RAX]
|
||||
MOV RDI,U64 CExcept.rdi[RAX]
|
||||
MOV R10,U64 CExcept.r10[RAX]
|
||||
MOV R11,U64 CExcept.r11[RAX]
|
||||
MOV R12,U64 CExcept.r12[RAX]
|
||||
MOV R13,U64 CExcept.r13[RAX]
|
||||
MOV R14,U64 CExcept.r14[RAX]
|
||||
MOV R15,U64 CExcept.r15[RAX]
|
||||
PUSH U64 CExcept.rflags[RAX]
|
||||
POPFD
|
||||
JMP U64 CExcept.hndlr_catch[RAX]
|
||||
|
||||
_TAKE_EXCEPT::
|
||||
XOR RAX,RAX
|
||||
MOV RAX,FS:U64 CTask.last_except[RAX]
|
||||
MOV RSP,U64 CExcept.rsp[RAX]
|
||||
JMP U64 CExcept.hndlr_untry[RAX]
|
||||
|
||||
_SAVE_EXCEPT_REGS::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV U64 CExcept.rsi[RAX],RSI
|
||||
MOV U64 CExcept.rdi[RAX],RDI
|
||||
MOV U64 CExcept.r10[RAX],R10
|
||||
MOV U64 CExcept.r11[RAX],R11
|
||||
MOV U64 CExcept.r12[RAX],R12
|
||||
MOV U64 CExcept.r13[RAX],R13
|
||||
MOV U64 CExcept.r14[RAX],R14
|
||||
MOV U64 CExcept.r15[RAX],R15
|
||||
POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
_extern _TEST_EXCEPT U0 TestExcept();
|
||||
_extern _TAKE_EXCEPT U0 TakeExcept();
|
||||
_extern _SAVE_EXCEPT_REGS U0 SaveExceptRegs(CExcept *t);
|
||||
|
||||
U0 PutExcept(Bool catch_it=TRUE)
|
||||
{//Print exception msg and catch exception.
|
||||
"Except:%c:",Fs->except_ch;
|
||||
"%P:%P:%P:%P:%P:%P\n",Fs->except_callers[0],Fs->except_callers[1],
|
||||
Fs->except_callers[2],Fs->except_callers[3],Fs->except_callers[4],
|
||||
Fs->except_callers[5],Fs->except_callers[6],Fs->except_callers[7];
|
||||
Fs->catch_except=catch_it;
|
||||
}
|
||||
|
||||
#exe {Option(OPTf_NO_REG_VAR,ON);};
|
||||
|
||||
class CTryStk
|
||||
{
|
||||
I64 rbp;
|
||||
I64 ret_rip;
|
||||
I64 arg1;
|
||||
I64 arg2;
|
||||
};
|
||||
|
||||
U0 SysTry(U8 *catch_start,U8 *untry_start)
|
||||
{
|
||||
I64 *rbp=GetRBP;
|
||||
CExcept *tmpt=MAlloc(sizeof(CExcept));
|
||||
tmpt->hndlr_catch=catch_start;
|
||||
tmpt->hndlr_untry=untry_start;
|
||||
tmpt->rsp=rbp(U8 *)+sizeof(CTryStk);
|
||||
tmpt->rbp=*rbp;
|
||||
tmpt->rflags=GetRFlags;
|
||||
SaveExceptRegs(tmpt);
|
||||
QueIns(tmpt,Fs->last_except);
|
||||
}
|
||||
|
||||
U0 SysUntry()
|
||||
{
|
||||
CExcept *tmpt=Fs->last_except;
|
||||
QueRem(tmpt);
|
||||
Free(tmpt);
|
||||
}
|
||||
|
||||
U0 throw(I64 ch=0,Bool no_log=FALSE)
|
||||
{//ch can be up to 8 chars like $LK,"PutChars",A="MN:PutChars"$().
|
||||
//In the catcher, fetch ch from Fs->except_ch.
|
||||
CExcept *tmpt=Fs->last_except;
|
||||
Bool was_raw;
|
||||
I64 i;
|
||||
Fs->except_ch=ch;
|
||||
for (i=0;i<TASK_EXCEPT_CALLERS;i++)
|
||||
Fs->except_callers[i]=Caller(i+1);
|
||||
Fs->except_rbp=GetRBP;
|
||||
Fs->catch_except=FALSE;
|
||||
if (!no_log)
|
||||
AdamLog("Except:%c:%p:%p:%p:%p:%p:%p\n",ch,Fs->except_callers[0],
|
||||
Fs->except_callers[1],Fs->except_callers[2],Fs->except_callers[3],
|
||||
Fs->except_callers[4],Fs->except_callers[5],Fs->except_callers[6],
|
||||
Fs->except_callers[7]);
|
||||
while (Fs->next_except!=&Fs->next_except) {
|
||||
TestExcept;
|
||||
if (Fs->catch_except)
|
||||
TakeExcept;
|
||||
SetRBP(Fs->except_rbp);
|
||||
tmpt=Fs->last_except;
|
||||
QueRem(tmpt);
|
||||
Free(tmpt);
|
||||
}
|
||||
was_raw=Raw(ON);
|
||||
PutExcept(FALSE);
|
||||
Panic("Unhandled Exception");
|
||||
Raw(was_raw);
|
||||
}
|
||||
|
||||
#exe {Option(OPTf_NO_REG_VAR,OFF);};
|
||||
|
||||
U0 Break()
|
||||
{//Send <CTRL-ALT-c>.
|
||||
if (Bt(&Fs->task_flags,TASKf_BREAK_TO_SHIFT_ESC))
|
||||
Msg(MSG_KEY_DOWN,CH_SHIFT_ESC,0x20100000201);
|
||||
else {
|
||||
Fs->wake_jiffy=0;
|
||||
TaskRstAwaitingMsg;
|
||||
DrvsRelease();
|
||||
BlkDevsRelease();
|
||||
FlushMsgs;
|
||||
throw('Break');
|
||||
}
|
||||
}
|
||||
|
||||
Bool BreakLock(CTask *task=NULL)
|
||||
{//Disables <CTRL-ALT-c>.
|
||||
if (!task) task=Fs;
|
||||
return !LBts(&task->task_flags,TASKf_BREAK_LOCKED);
|
||||
}
|
||||
|
||||
Bool BreakUnlock(CTask *task=NULL)
|
||||
{//Reenables <CTRL-ALT-c> and issues any pending breaks.
|
||||
Bool res;
|
||||
if (!task) task=Fs;
|
||||
res=LBtr(&task->task_flags,TASKf_BREAK_LOCKED);
|
||||
if (LBtr(&task->task_flags,TASKf_PENDING_BREAK)) {
|
||||
if (task==Fs)
|
||||
Break;
|
||||
else
|
||||
task->rip=&Break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
If you are sure a fun won't be called
|
||||
before import is resolved, you can use
|
||||
"import". Otherwise, use a fun pointer
|
||||
var and check it before calling.
|
||||
*/
|
||||
import U8 *DocSave(CDoc *doc,I64 *_size=NULL);
|
||||
import Bool DocUnlock(CDoc *doc);
|
||||
import Bool Ed(U8 *link_st,I64 edf_dof_flags=0);
|
||||
extern U0 AdamErr(U8 *fmt,...);
|
||||
extern U0 AdamLog(U8 *fmt,...);
|
||||
extern I64 BIOSTotalMem();
|
||||
extern I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
|
||||
Bool whole_drv,Bool make_free);
|
||||
extern CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE);
|
||||
extern Bool BlkDevLock(CBlkDev *bd);
|
||||
extern CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type);
|
||||
extern Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE);
|
||||
extern U0 BlkDevsRelease();
|
||||
extern U8 *Caller(I64 num=1);
|
||||
extern U8 *CatPrint(U8 *_dst,U8 *fmt,...);
|
||||
extern Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE);
|
||||
extern U0 DbgHelp();
|
||||
extern U8 *Define(U8 *dname);
|
||||
extern I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0);
|
||||
extern U8 *DefineSub(I64 sub,U8 *dname);
|
||||
extern I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
|
||||
Bool del_dir=FALSE,Bool print_msg=TRUE);
|
||||
extern U8 *DftExt(U8 *filename,U8 *extension);
|
||||
extern Bool Drv(U8 drv_let);
|
||||
extern U8 Drv2Let(CDrv *dv=NULL);
|
||||
extern U0 DrvBlkDevDel(CBlkDev *bd);
|
||||
extern CDrv *DrvChk(CDrv *dv,Bool except=TRUE);
|
||||
extern U8 DrvTextAttrGet(U8 drv_let=0);
|
||||
extern Bool DrvTypeSet(U8 drv_let,I64 type=FSt_REDSEA);
|
||||
extern U0 DrvsRelease();
|
||||
extern U0 DskCacheInvalidate(CDrv *dv);
|
||||
extern U0 Exit();
|
||||
extern I64 FAT32AllocClusters(CDrv *dv,I64 c,I64 cnt);
|
||||
extern I64 FAT32AllocContiguousClusters(CDrv *dv,I64 cnt);
|
||||
extern Bool FAT32DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,
|
||||
Bool free_old_chain);
|
||||
extern Bool FAT32FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0);
|
||||
extern U0 FAT32Init(CDrv *dv);
|
||||
extern U0 FClose(CFile *f);
|
||||
extern CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0);
|
||||
extern Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
|
||||
extern Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
|
||||
extern U8 *FileExtRem(U8 *src,U8 *dst=NULL);
|
||||
extern Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0);
|
||||
extern U8 *FileNameAbs(U8 *_filename,I64 fuf_flags=0);
|
||||
extern U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL);
|
||||
extern I64 FileWrite(U8 *filename,U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0);
|
||||
extern I64 FlushMsgs(CTask *task=NULL);
|
||||
extern I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,Bool raw_cursor=FALSE);
|
||||
extern I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE);
|
||||
extern CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,
|
||||
CTask *task=NULL,CBlkPool *bp);
|
||||
extern Bool ISO1FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0);
|
||||
extern Bool ISOInit(CDrv *dv,I64 blk);
|
||||
extern Bool IsDbgMode();
|
||||
extern Bool IsDir(U8 *dir_name);
|
||||
extern Bool IsRaw();
|
||||
extern U0 JobCtrlInit(CJobCtrl *ctrl);
|
||||
extern U0 JobDel(CJob *tmpc);
|
||||
extern U0 JobQueDel(CJob *head);
|
||||
extern I64 JobsHndlr(I64 run_flags,CTask *task=NULL);
|
||||
extern CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE);
|
||||
extern I64 Let2BlkDevType(U8 drv_let);
|
||||
extern CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE);
|
||||
extern U8 Let2Let(U8 drv_let=0);
|
||||
extern U0 MPInt(U8 num,I64 cpu_num=1);
|
||||
extern U8 *MStrPrint(U8 *fmt,...);
|
||||
extern Bool MkDir(U8 *filename,I64 entry_cnt=0);
|
||||
extern U0 MsHardSet(I64 x,I64 y,I64 z,I64 l,I64 r);
|
||||
extern U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
|
||||
extern U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE);
|
||||
extern I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL);
|
||||
extern U0 Print(U8 *fmt,...);
|
||||
extern U0 PutChars(U64 ch);
|
||||
extern U0 PutS(U8 *st); //Use $LK,"Print",A="MN:Print"$()
|
||||
extern Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
|
||||
extern I64 RedSeaAllocClusters(CDrv *dv,I64 cnt);
|
||||
extern Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,
|
||||
Bool free_old_chain);
|
||||
extern Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0);
|
||||
extern U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE);
|
||||
extern U0 RedSeaFreeFreeLst(CDrv *dv);
|
||||
extern U0 RedSeaInit(CDrv *dv);
|
||||
extern Bool RedSeaValidate(U8 drv_let);
|
||||
extern CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
|
||||
U8 *task_name=NULL,I64 target_cpu,CTask *parent=NULL, //NULL means adam
|
||||
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
|
||||
extern U8 *StrPrint(U8 *dst,U8 *fmt,...);
|
||||
extern U0 StrPrintFunSeg(U8 *buf,I64 addr,I64 field_len,I64 flags);
|
||||
extern Bool Suspend(CTask *task=NULL,Bool state=TRUE);
|
||||
extern CJob *TaskMsg(CTask *_srv,CTask *master,
|
||||
I64 msg_code,I64 arg1,I64 arg2,I64 flags);
|
||||
extern U0 TaskRstAwaitingMsg(CTask *task=NULL);
|
||||
extern Bool TaskValidate(CTask *task);
|
||||
extern U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE);
|
||||
extern CTask *User(U8 *fmt=NULL,...);
|
||||
extern U0 UserTaskCont();
|
||||
extern Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
|
||||
extern U0 XTalk(CTask *task,U8 *fmt,...);
|
||||
extern U0 throw(I64 ch=0,Bool no_log=FALSE);
|
||||
@@ -0,0 +1,35 @@
|
||||
//Compiler initializes glbls in AOT bin modules to zero.
|
||||
//$LK,"Globals Set to Zero Here",A="FF:::/Compiler/PrsStmt.HC,Init AOT glbl to zero"$.
|
||||
|
||||
CJob sys_macro_head;
|
||||
CTask *sys_macro_task;
|
||||
CDoc *sys_clipboard_doc;
|
||||
|
||||
CTask *adam_task;
|
||||
I64 sys_num_spawned_tasks;
|
||||
|
||||
CTask *sys_winmgr_task,*sys_task_being_scrn_updated;
|
||||
U8 *rev_bits_table, //Table with U8 bits revd
|
||||
*set_bits_table; //Table with count of set bits in a U8
|
||||
CDate local_time_offset;
|
||||
F64 *pow10_I64,
|
||||
sys_os_version=5.020;
|
||||
|
||||
CAutoCompleteDictGlbls acd;
|
||||
CAutoCompleteGlbls ac;
|
||||
CBlkDevGlbls blkdev;
|
||||
CCntsGlbls cnts={1,0,2676302000,2676302,2676302000,0,0,0,FALSE};
|
||||
CDbgGlbls dbg;
|
||||
CDevGlbls dev;
|
||||
CGridGlbls ms_grid; //See $LK,"::/Demo/Graphics/Grid.HC"$.
|
||||
CMsStateGlbls ms,ms_last;
|
||||
CKbdStateGlbls kbd;
|
||||
CKeyDevGlbls keydev;
|
||||
CMsHardStateGlbls ms_hard,ms_hard_last;
|
||||
CSndGlbls snd;
|
||||
CTextGlbls text;
|
||||
|
||||
U8 *(*fp_getstr2)(I64 flags=0);
|
||||
U0 (*fp_update_ctrls)(CTask *task);
|
||||
CDoc *(*fp_doc_put)(CTask *task=NULL);
|
||||
U0 (*fp_set_std_palette)();
|
||||
@@ -0,0 +1,265 @@
|
||||
asm {
|
||||
//************************************
|
||||
SYS_HASH_STR::
|
||||
// IN: RSI=Addr of string
|
||||
// OUT: RAX
|
||||
XOR RAX,RAX
|
||||
TEST RSI,RSI
|
||||
JZ @@15
|
||||
|
||||
PUSH RSI
|
||||
PUSH RBX
|
||||
XOR RBX,RBX
|
||||
JMP @@10
|
||||
|
||||
@@05: SHL1 RBX
|
||||
ADC RBX,RAX
|
||||
@@10: LODSB
|
||||
TEST AL,AL
|
||||
JNZ @@05
|
||||
|
||||
MOV RAX,RBX
|
||||
SHR RBX,16
|
||||
ADC RAX,RBX
|
||||
POP RBX
|
||||
POP RSI
|
||||
|
||||
@@15: RET
|
||||
//************************************
|
||||
SYS_HASH_SINGLE_TABLE_FIND1::
|
||||
// IN: RAX=HASHED STRING VAL
|
||||
// RSI=STR
|
||||
// RBX=TYPE MASK
|
||||
// RDI=TABLE
|
||||
// RCX=INSTANCE, NOT ZERO
|
||||
// OUT: RAX=ENTRY OR ZERO NOT FOUND
|
||||
// RDX=POINTER TO POINTER TO ENTRY
|
||||
// RCX IF NOT FOUND ENOUGH, DECREMENTED BY NUM MATCHES
|
||||
// ZERO FLAG SET NOT FOUND
|
||||
MOV RCX,1
|
||||
SYS_HASH_SINGLE_TABLE_FIND::
|
||||
TEST RCX,RCX
|
||||
JNZ @@05
|
||||
XOR RAX,RAX
|
||||
RET
|
||||
@@05: AND RAX,U64 CHashTable.mask[RDI]
|
||||
MOV RDX,U64 CHashTable.body[RDI]
|
||||
LEA RDX,U64 [RDX+RAX*8]
|
||||
@@10: MOV RAX,U64 [RDX]
|
||||
TEST RAX,RAX
|
||||
JNZ @@15
|
||||
RET
|
||||
|
||||
@@15: TEST U32 CHash.type[RAX],EBX
|
||||
JZ @@30
|
||||
PUSH RAX
|
||||
PUSH RDI
|
||||
PUSH RSI
|
||||
MOV RDI,U64 CHash.str[RAX]
|
||||
@@20: LODSB
|
||||
CMP U8 [RDI],AL
|
||||
JNE @@25
|
||||
INC RDI
|
||||
TEST AL,AL
|
||||
JNZ @@20
|
||||
POP RSI
|
||||
POP RDI
|
||||
POP RAX
|
||||
LOOP @@30
|
||||
INC U32 CHash.use_cnt[RAX]
|
||||
TEST RAX,RAX
|
||||
RET
|
||||
|
||||
@@25: POP RSI
|
||||
POP RDI
|
||||
POP RAX
|
||||
|
||||
@@30: LEA RDX,U64 CHash.next[RAX]
|
||||
JMP @@10
|
||||
//************************************
|
||||
SYS_HASH_FIND1::
|
||||
// IN: RSI=STR
|
||||
// RBX=TYPE MASK
|
||||
// RDI=TABLE
|
||||
// RCX=INSTANCE NUM
|
||||
// OUT: RAX=ENTRY OR ZERO NOT FOUND
|
||||
// ZERO FLAG SET NOT FOUND
|
||||
MOV RCX,1
|
||||
SYS_HASH_FIND::
|
||||
PUSH RDI
|
||||
CALL SYS_HASH_STR
|
||||
|
||||
@@05: PUSH RAX
|
||||
CALL SYS_HASH_SINGLE_TABLE_FIND
|
||||
JNZ @@15
|
||||
POP RAX
|
||||
@@10: MOV RDI,U64 CHashTable.next[RDI]
|
||||
TEST RDI,RDI
|
||||
JNZ @@05
|
||||
POP RDI
|
||||
XOR RAX,RAX
|
||||
RET
|
||||
|
||||
@@15: ADD RSP,8
|
||||
POP RDI
|
||||
TEST RAX,RAX
|
||||
RET
|
||||
//************************************
|
||||
SYS_HASH_BUCKET_FIND::
|
||||
// IN: RSI=STR
|
||||
// RDI=TABLE
|
||||
// OUT: RAX=BUCKET
|
||||
PUSH RDX
|
||||
CALL SYS_HASH_STR
|
||||
AND RAX,U64 CHashTable.mask[RDI]
|
||||
MOV RDX,U64 CHashTable.body[RDI]
|
||||
LEA RAX,U64 [RDX+RAX*8]
|
||||
POP RDX
|
||||
RET
|
||||
_HASH_STR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
CALL SYS_HASH_STR
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 8
|
||||
_HASH_FIND::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG4[RBP]
|
||||
CALL SYS_HASH_FIND
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 32
|
||||
_HASH_SINGLE_TABLE_FIND::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG4[RBP]
|
||||
CALL SYS_HASH_STR
|
||||
CALL SYS_HASH_SINGLE_TABLE_FIND
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 32
|
||||
_HASH_BUCKET_FIND::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
CALL SYS_HASH_BUCKET_FIND
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_HASH_ADD::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG1[RBP]
|
||||
MOV RSI,U64 CHash.str[RCX]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
CALL SYS_HASH_BUCKET_FIND
|
||||
MOV RCX,U64 SF_ARG1[RBP]
|
||||
PUSHFD
|
||||
CLI
|
||||
MOV RBX,U64 [RAX]
|
||||
MOV U64 CHash.next[RCX],RBX
|
||||
MOV U64 [RAX],RCX
|
||||
|
||||
POPFD
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_HASH_ADD_AFTER::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG3[RBP]
|
||||
PUSHFD
|
||||
CLI
|
||||
MOV RAX,SF_ARG2[RBP]
|
||||
MOV RBX,U64 [RAX]
|
||||
MOV U64 CHash.next[RCX],RBX
|
||||
MOV U64 [RAX],RCX
|
||||
|
||||
POPFD
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_HASH_REM_DEL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG1[RBP]
|
||||
TEST RCX,RCX
|
||||
JZ @@10
|
||||
MOV RSI,U64 CHash.str[RCX]
|
||||
XOR RBX,RBX
|
||||
MOV EBX,U32 CHash.type[RCX]
|
||||
AND EBX,~HTG_FLAGS_MASK&0xFFFFFFFF
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
CALL SYS_HASH_STR
|
||||
|
||||
PUSHFD
|
||||
CLI
|
||||
CALL SYS_HASH_SINGLE_TABLE_FIND
|
||||
JZ @@05
|
||||
CMP RAX,U64 SF_ARG1[RBP]
|
||||
JNE @@05
|
||||
|
||||
MOV RBX,U64 CHash.next[RAX]
|
||||
MOV U64 [RDX],RBX
|
||||
|
||||
POPFD
|
||||
|
||||
PUSH_C_REGS
|
||||
PUSH RAX
|
||||
CALL &HashDel
|
||||
POP_C_REGS
|
||||
|
||||
POP RDI
|
||||
POP RSI
|
||||
MOV RAX,1
|
||||
POP RBP
|
||||
RET1 24
|
||||
|
||||
@@05: POPFD
|
||||
@@10: POP RDI
|
||||
POP RSI
|
||||
XOR RAX,RAX
|
||||
POP RBP
|
||||
RET1 24
|
||||
}
|
||||
|
||||
_extern _HASH_STR I64 HashStr(U8 *st); //Hash a string.
|
||||
_extern _HASH_FIND CHash *HashFind(U8 *needle_str,CHashTable *haystack_table,
|
||||
I64 mask,I64 instance=1);//Find string in hash table.
|
||||
_extern _HASH_SINGLE_TABLE_FIND CHash *HashSingleTableFind(U8 *needle_str,
|
||||
CHashTable *haystack_table,
|
||||
I64 mask,I64 instance=1);//Find string in single hash table.
|
||||
_extern _HASH_BUCKET_FIND CHash **HashBucketFind(U8 *needle_str,
|
||||
CHashTable *haystack_table); //Find hash bucket.
|
||||
_extern _HASH_ADD U0 HashAdd(CHash *tmph,
|
||||
CHashTable *table); //Add entry to hash table.
|
||||
_extern _HASH_REM_DEL Bool HashRemDel(CHash *tmph,CHashTable *table,
|
||||
I64 instance=1);//Remove hash entry and del. Instance must match.
|
||||
@@ -0,0 +1,250 @@
|
||||
I64 HashTypeNum(CHash *tmph)
|
||||
{//Return bit num of hash type, limited to just types.
|
||||
if (tmph)
|
||||
return Bsf(tmph->type&HTG_TYPE_MASK);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
I64 HashVal(CHash *tmph)
|
||||
{//Returns most likely desired value.
|
||||
switch [HashTypeNum(tmph)] {
|
||||
case HTt_EXPORT_SYS_SYM:
|
||||
return tmph(CHashExport *)->val;
|
||||
case HTt_IMPORT_SYS_SYM:
|
||||
return tmph(CHashImport *)->module_base;
|
||||
case HTt_DEFINE_STR:
|
||||
case HTt_CLASS:
|
||||
case HTt_INTERNAL_TYPE:
|
||||
case HTt_WORD:
|
||||
case HTt_DICT_WORD:
|
||||
case HTt_OPCODE:
|
||||
case HTt_HELP_FILE:
|
||||
return tmph;
|
||||
case HTt_GLBL_VAR:
|
||||
if (tmph(CHashGlblVar *)->flags&GVF_EXTERN)
|
||||
return &tmph(CHashGlblVar *)->data_addr;
|
||||
else
|
||||
return tmph(CHashGlblVar *)->data_addr;
|
||||
case HTt_FUN:
|
||||
if (Bt(&tmph(CHashFun *)->flags,Cf_EXTERN))
|
||||
return tmph;
|
||||
else
|
||||
return tmph(CHashFun *)->exe_addr;
|
||||
case HTt_REG:
|
||||
return tmph(CHashReg *)->reg_num|tmph(CHashReg *)->reg_type<<8;
|
||||
case HTt_KEYWORD:
|
||||
case HTt_ASM_KEYWORD:
|
||||
case HTt_MODULE:
|
||||
case HTt_FILE:
|
||||
case HTt_FRAME_PTR:
|
||||
return tmph(CHashGeneric *)->user_data0;
|
||||
|
||||
case -1: //nobound switch
|
||||
case HTt_TYPES_NUM: //nobound switch
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
CHashTable *HashTableNew(I64 size,CTask *mem_task=NULL)
|
||||
{//New hash table, power-of-two in size.
|
||||
CHashTable *table;
|
||||
table=CAlloc(sizeof(CHashTable),mem_task);
|
||||
table->body=CAlloc(size<<3,mem_task);
|
||||
table->mask=size-1;
|
||||
return table;
|
||||
}
|
||||
|
||||
U0 HashDel(CHashSrcSym *tmph)
|
||||
{//Free a std TempleOS system hash entry.
|
||||
if (!tmph) return;
|
||||
if (!(tmph->type&HTT_DICT_WORD))
|
||||
Free(tmph->str);
|
||||
if (tmph->type & HTG_SRC_SYM) {
|
||||
Free(tmph->src_link);
|
||||
Free(tmph->idx);
|
||||
Free(tmph->import_name);
|
||||
LinkedLstDel(tmph->ie_lst);
|
||||
if (tmph->type & (HTT_FUN | HTT_EXPORT_SYS_SYM))
|
||||
Free(tmph->dbg_info);
|
||||
if (tmph->type & (HTT_FUN | HTT_CLASS))
|
||||
//Assumes code not on heap, so doesn't Free.
|
||||
//$LK,"ClassMemberLstDel",A="MN:ClassMemberLstDel"$() is an import to the Kernel module
|
||||
ClassMemberLstDel(tmph);
|
||||
else if (tmph->type&HTT_DEFINE_STR)
|
||||
Free(tmph(CHashDefineStr *)->data);
|
||||
else if (tmph->type & HTT_GLBL_VAR) {
|
||||
if (!(tmph(CHashGlblVar *)->flags&GVF_ALIAS))
|
||||
Free(tmph(CHashGlblVar *)->data_addr);
|
||||
LinkedLstDel(tmph(CHashGlblVar *)->dim.next);
|
||||
if (tmph(CHashGlblVar *)->fun_ptr)
|
||||
HashDel(tmph(CHashGlblVar *)->fun_ptr
|
||||
-tmph(CHashGlblVar *)->fun_ptr->ptr_stars_cnt);
|
||||
}
|
||||
} else if (tmph->type & HTT_FILE)
|
||||
Free(tmph(CHashGeneric *)->user_data0);
|
||||
Free(tmph);
|
||||
}
|
||||
|
||||
U0 HashTableDel(CHashTable *table)
|
||||
{//Free std system hash table, calling $LK,"HashDel",A="MN:HashDel"$() on entries.
|
||||
I64 i;
|
||||
CHashSrcSym *tmph,*tmph1;
|
||||
if (!table) return;
|
||||
for (i=0;i<=table->mask;i++) {
|
||||
tmph=table->body[i];
|
||||
while (tmph) {
|
||||
tmph1=tmph->next;
|
||||
HashDel(tmph);
|
||||
tmph=tmph1;
|
||||
}
|
||||
}
|
||||
Free(table->body);
|
||||
Free(table);
|
||||
}
|
||||
|
||||
I64 HashTablePurge(CHashTable *table)
|
||||
{//Eliminate ExportSysSyms that have been usurped.
|
||||
I64 i,res=0;
|
||||
CHashSrcSym *tmph,*tmph1,*tmph2;
|
||||
if (!table) return 0;
|
||||
PUSHFD
|
||||
CLI //Precaution
|
||||
for (i=0;i<=table->mask;i++) {
|
||||
tmph=table->body[i];
|
||||
while (tmph) {
|
||||
tmph1=tmph->next; //We delete only older ones
|
||||
if (tmph->type&(HTT_FUN|HTT_GLBL_VAR)) {
|
||||
tmph2=tmph->next; //Older always later in chain
|
||||
while (tmph2) {
|
||||
if ((tmph2->type&HTT_EXPORT_SYS_SYM ||
|
||||
tmph2->type&HTG_TYPE_MASK==HTT_INVALID) &&
|
||||
!StrCmp(tmph2->str,tmph->str)) {
|
||||
if (tmph2->type&HTG_TYPE_MASK==HTT_INVALID)
|
||||
tmph2->type=HTT_KEYWORD;//Won't delete HTT_INVALID
|
||||
HashRemDel(tmph2,table);
|
||||
res++;
|
||||
break;
|
||||
}
|
||||
tmph2=tmph2->next;
|
||||
}
|
||||
}
|
||||
tmph=tmph1;
|
||||
}
|
||||
}
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
CHashGeneric *HashGenericAdd(U8 *name,I64 type,
|
||||
I64 u0=0,I64 u1=0,I64 u2=0,CTask *task=NULL)
|
||||
{//Add any type to task hash_table, 3 user_data values.
|
||||
if (!task) task=Fs;
|
||||
CHashGeneric *res=CAlloc(sizeof(CHashGeneric),task);
|
||||
res->type=type;
|
||||
res->user_data0=u0;
|
||||
res->user_data1=u1;
|
||||
res->user_data2=u2;
|
||||
res->str=StrNew(name,task);
|
||||
HashAdd(res,task->hash_table);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 HashSrcFileSet(CCmpCtrl *cc,CHashSrcSym *h,I64 line_num_offset=0)
|
||||
{//Set $LK,"CHashSrcSym",A="MN:CHashSrcSym"$ link and help_index by cur cc pos.
|
||||
CLexFile *tmpf=cc->lex_include_stk;
|
||||
I64 line_num=tmpf->line_num+line_num_offset;
|
||||
if (line_num<1) line_num=1;
|
||||
Free(h->src_link);
|
||||
h->src_link=MStrPrint("FL:%s,%d",tmpf->full_name,line_num);
|
||||
if (Bt(&cc->opts,OPTf_KEEP_PRIVATE))
|
||||
h->type|=HTF_PRIVATE;
|
||||
Free(h->idx);
|
||||
if (cc->cur_help_idx && *cc->cur_help_idx)
|
||||
h->idx=StrNew(cc->cur_help_idx);
|
||||
else
|
||||
h->idx=NULL;
|
||||
}
|
||||
|
||||
CHashGeneric *HashPublic(U8 *st,I64 mask,Bool val=TRUE)
|
||||
{//Mark a hash entry as public and $LK,"HashSrcFileSet",A="MN:HashSrcFileSet"$().
|
||||
CHashGeneric *res;
|
||||
if (res=HashFind(st,Fs->hash_table,mask)) {
|
||||
if (val)
|
||||
res->type|=HTF_PUBLIC;
|
||||
else
|
||||
res->type&=~HTF_PUBLIC;
|
||||
if (res->type&HTG_SRC_SYM)
|
||||
HashSrcFileSet(Fs->last_cc,res);
|
||||
return res;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 HashLstAdd(U8 *lst,I64 type,CHashTable *table)
|
||||
{//Add a list to a hash table.
|
||||
I64 i=0;
|
||||
CHashGeneric *tmph;
|
||||
if (lst) {
|
||||
while (*lst) {
|
||||
if (*lst=='@')
|
||||
lst++;
|
||||
else
|
||||
i++;
|
||||
tmph=CAlloc(sizeof(CHashGeneric));
|
||||
tmph->user_data0=i-1;
|
||||
tmph->str=StrNew(lst);
|
||||
tmph->type=type;
|
||||
HashAdd(tmph,table);
|
||||
while (*lst++);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
I64 HashDefineLstAdd(U8 *dname,I64 type,CHashTable *table)
|
||||
{//Add define list to a hash table. See $LK,"::/Adam/DolDoc/DocInit.HC",A="FF:::/Adam/DolDoc/DocInit.HC,HashDefineLstAdd"$.
|
||||
CHashDefineStr *tmph;
|
||||
if (tmph=HashFind(dname,Fs->hash_table,HTT_DEFINE_STR))
|
||||
return HashLstAdd(tmph->data,type,table);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
I64 FramePtr(U8 *name,CTask *task=NULL)
|
||||
{//Find entry in task->hash_table, Return user_data.
|
||||
CHashGeneric *tmph;
|
||||
if (!task) task=Fs;
|
||||
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR))
|
||||
return tmph->user_data0;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHashGeneric *FramePtrAdd(U8 *name,I64 val=0,CTask *task=NULL)
|
||||
{//Add named value to task->hash_table.
|
||||
return HashGenericAdd(name,HTT_FRAME_PTR,val,0,0,task);
|
||||
}
|
||||
|
||||
I64 FramePtrSet(U8 *name,I64 val,CTask *task=NULL)
|
||||
{//Find hash entry in task->hash_table. Change user_data0.
|
||||
CHashGeneric *tmph;
|
||||
if (!task) task=Fs;
|
||||
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR))
|
||||
return LXchgI64(&tmph->user_data0,val);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
I64 FramePtrDel(U8 *name,CTask *task=NULL)
|
||||
{//Remove entry and delete.
|
||||
CHashGeneric *tmph;
|
||||
I64 res=0;
|
||||
if (!task) task=Fs;
|
||||
if (tmph=HashFind(name,task->hash_table,HTT_FRAME_PTR)) {
|
||||
res=tmph->user_data0;
|
||||
HashRemDel(tmph,task->hash_table);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
asm {
|
||||
INT_MP_CRASH_ADDR:: //Forward reference to work around compiler
|
||||
DU32 &IntMPCrash;
|
||||
|
||||
INT_WAKE::
|
||||
PUSH RDX
|
||||
PUSH RAX
|
||||
MOV EAX,&dev
|
||||
MOV EDX,U32 LAPIC_EOI
|
||||
MOV RAX,U64 CDevGlbls.uncached_alias[RAX]
|
||||
MOV U32 [RAX+RDX],0
|
||||
POP RAX
|
||||
POP RDX
|
||||
IRET
|
||||
|
||||
IRQ_TIMER:: //I_TIMER
|
||||
CALL TASK_CONTEXT_SAVE
|
||||
CLD
|
||||
|
||||
MOV RAX,U64 [RSP]
|
||||
MOV U64 CTask.rip[RSI],RAX
|
||||
MOV RAX,U64 16[RSP]
|
||||
MOV U64 CTask.rflags[RSI],RAX
|
||||
MOV RAX,U64 24[RSP]
|
||||
MOV U64 CTask.rsp[RSI],RAX
|
||||
|
||||
XOR RAX,RAX
|
||||
MOV RDI,U64 GS:CCPU.addr[RAX]
|
||||
LOCK
|
||||
INC U64 CCPU.total_jiffies[RDI]
|
||||
|
||||
BT U64 CTask.task_flags[RSI],TASKf_IDLE
|
||||
JNC @@05
|
||||
LOCK
|
||||
INC U64 CCPU.idle_pt_hits[RDI]
|
||||
|
||||
@@05: MOV RAX,U64 CCPU.profiler_timer_irq[RDI]
|
||||
TEST RAX,RAX
|
||||
JZ @@10
|
||||
PUSH RSI
|
||||
CALL RAX //See $LK,"ProfTimerInt",A="MN:ProfTimerInt"$().
|
||||
JMP @@15
|
||||
@@10: ADD RSP,8
|
||||
@@15: CLI
|
||||
MOV RAX,U64 CCPU.num[RDI]
|
||||
TEST RAX,RAX
|
||||
JZ @@20
|
||||
|
||||
MOV EAX,&dev
|
||||
MOV EDX,U32 LAPIC_EOI
|
||||
MOV RAX,U64 CDevGlbls.uncached_alias[RAX]
|
||||
MOV U32 [RAX+RDX],0
|
||||
JMP @@25
|
||||
|
||||
@@20: CALL &IntCore0TimerHndlr //Only Core 0 calls this.
|
||||
@@25: XOR RAX,RAX
|
||||
CMP RSI,U64 GS:CCPU.idle_task[RAX]
|
||||
JE I32 RESTORE_SETH_TASK_IF_READY
|
||||
JMP I32 RESTORE_RSI_TASK
|
||||
//************************************
|
||||
INT_FAULT::
|
||||
PUSH RBX
|
||||
PUSH RAX
|
||||
MOV BL,U8 16[RSP] //We pushed fault_num $LK,"IntFaultHndlrsNew",A="MN:IntFaultHndlrsNew"$().
|
||||
XOR RAX,RAX
|
||||
MOV FS:U8 CTask.fault_num[RAX],BL
|
||||
POP RAX
|
||||
POP RBX
|
||||
ADD RSP,8 //Pop fault_num
|
||||
|
||||
CALL TASK_CONTEXT_SAVE
|
||||
|
||||
XOR RDX,RDX
|
||||
MOV U64 CTask.fault_err_code[RSI],RDX
|
||||
MOV EDX,U32 CTask.fault_num[RSI]
|
||||
BT U64 [INT_FAULT_ERR_CODE_BITMAP],RDX
|
||||
JNC @@1
|
||||
POP U64 CTask.fault_err_code[RSI]
|
||||
|
||||
@@1: MOV RAX,U64 [RSP]
|
||||
MOV U64 CTask.rip[RSI],RAX
|
||||
MOV RAX,U64 16[RSP]
|
||||
MOV U64 CTask.rflags[RSI],RAX
|
||||
MOV RSP,U64 24[RSP]
|
||||
MOV U64 CTask.rsp[RSI],RSP
|
||||
MOV RBP,CTask.rbp[RSI]
|
||||
PUSH U64 CTask.fault_err_code[RSI]
|
||||
PUSH U64 CTask.fault_num[RSI]
|
||||
MOV RSI,CTask.rsi[RSI]
|
||||
CALL &Fault2 //See $LK,"Fault2",A="FF:::/Kernel/KDbg.HC,Fault2"$
|
||||
JMP I32 RESTORE_FS_TASK
|
||||
|
||||
INT_FAULT_ERR_CODE_BITMAP::
|
||||
DU32 0x00027D00,0,0,0,0,0,0,0;
|
||||
}
|
||||
|
||||
U8 *IntEntryGet(I64 irq)
|
||||
{//Get interrupt vector.
|
||||
U8 *res;
|
||||
I64 *src;
|
||||
src=dev.idt(U8 *)+irq*16;
|
||||
res(I64).u16[0]=*src(U16 *);
|
||||
src(U8 *)+=6;
|
||||
res(I64).u16[1]=*src(U16 *)++;
|
||||
res(I64).u32[1]=*src(U32 *);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *IntEntrySet(I64 irq,U0 (*fp_new_hndlr)(),I64 type=IDTET_IRQ,I64 dpl=0)
|
||||
{//Set interrupt vector. See $LK,"IDTET_IRQ",A="MN:IDTET_IRQ"$.
|
||||
//See $LK,"::/Demo/Lectures/InterruptDemo.HC"$.
|
||||
//See $LK,"::/Demo/MultiCore/Interrupts.HC"$.
|
||||
I64 fp=fp_new_hndlr;
|
||||
U8 *res,*dst;
|
||||
PUSHFD
|
||||
CLI
|
||||
res=IntEntryGet(irq);
|
||||
dst=dev.idt(U8 *)+irq*16;
|
||||
*dst(U16 *)++=fp.u16[0];
|
||||
*dst(U16 *)++=offset(CGDT.cs64);
|
||||
*dst(U16 *)++=0x8000+type<<8+dpl<<13;
|
||||
*dst(U16 *)++=fp.u16[1];
|
||||
*dst(U32 *)++=fp.u32[1];
|
||||
*dst(U32 *)=0;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 IntsInit()
|
||||
{//Init 8259
|
||||
OutU8(0x20,0x11); //IW1
|
||||
OutU8(0xA0,0x11); //IW1
|
||||
OutU8(0x21,0x20); //IW2
|
||||
OutU8(0xA1,0x28); //IW2
|
||||
OutU8(0x21,0x04); //IW3
|
||||
OutU8(0xA1,0x02); //IW3
|
||||
OutU8(0x21,0x0D); //IW4
|
||||
OutU8(0xA1,0x09); //IW4
|
||||
OutU8(0x21,0xFA); //Mask all but IRQ0 (timer) and IRQ2 Cascade.
|
||||
OutU8(0xA1,0xFF);
|
||||
}
|
||||
|
||||
interrupt U0 IntNop()
|
||||
{//Make unplanned IRQs stop by all means!
|
||||
OutU8(0xA0,0x20);
|
||||
OutU8(0x20,0x20);
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
}
|
||||
|
||||
interrupt U0 IntDivZero()
|
||||
{
|
||||
if (Gs->num) {
|
||||
mp_cnt=1;
|
||||
dbg.mp_crash->cpu_num=Gs->num;
|
||||
dbg.mp_crash->task=Fs;
|
||||
MOV RAX,U64 8[RBP] //Get RIP off of stk.
|
||||
dbg.mp_crash->rip=GetRAX;
|
||||
dbg.mp_crash->msg="Div Zero";
|
||||
dbg.mp_crash->msg_num=0;
|
||||
MPInt(I_MP_CRASH,0);
|
||||
SysHlt;
|
||||
}
|
||||
throw('DivZero');
|
||||
}
|
||||
|
||||
U8 *IntFaultHndlrsNew()
|
||||
{
|
||||
I64 i;
|
||||
U8 *res=MAlloc(256*7,Fs->code_heap),*dst=res;
|
||||
for (i=0;i<256;i++) {
|
||||
*dst++=0x6A; //PUSH I8 xx
|
||||
*dst(I8 *)++=i;
|
||||
*dst++=0xE9; //JMP I32 xxxxxxxx
|
||||
*dst(I32 *)=INT_FAULT-dst-4;
|
||||
dst+=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 IntInit1()
|
||||
{//Interrupt descriptor table part1.
|
||||
I64 i;
|
||||
CSysLimitBase tmp_ptr;
|
||||
if (!Gs->num) {//Gs cur $LK,"CCPU",A="MN:CCPU"$ struct
|
||||
dev.idt=CAlloc(16*256);
|
||||
for (i=0;i<256;i++)
|
||||
IntEntrySet(i,&IntNop);
|
||||
}
|
||||
tmp_ptr.limit=256*16-1;
|
||||
tmp_ptr.base =dev.idt;
|
||||
SetRAX(&tmp_ptr);
|
||||
LIDT U64 [RAX]
|
||||
}
|
||||
|
||||
U0 IntInit2()
|
||||
{//Interrupt descriptor table part2: Core 0 Only.
|
||||
I64 i;
|
||||
PUSHFD
|
||||
CLI
|
||||
IntEntrySet(I_DIV_ZERO,&IntDivZero);
|
||||
for (i=1;i<0x20;i++)
|
||||
IntEntrySet(i,&dbg.int_fault_code[7*i]);
|
||||
/*In theory, we use the PIC mask reg to insure we don't get
|
||||
anything but keyboard, mouse and timer IRQs. In practice, I've
|
||||
gotten IRQ 0x27, perhaps because I didn't initialize the APIC.
|
||||
I go ahead and ACK PIC in $LK,"IntNop",A="MN:IntNop"$().
|
||||
I have no idea why I got a IRQ 0x27.
|
||||
*/
|
||||
IntEntrySet(I_NMI,_SYS_HLT);
|
||||
IntEntrySet(I_TIMER,IRQ_TIMER);
|
||||
IntEntrySet(I_MP_CRASH,*INT_MP_CRASH_ADDR(U32 *));
|
||||
IntEntrySet(I_WAKE,INT_WAKE);
|
||||
IntEntrySet(I_DBG,&dbg.int_fault_code[7*I_DBG]);
|
||||
POPFD
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
U0 LoadOneImport(U8 **_src,U8 *module_base,I64 ld_flags)
|
||||
{
|
||||
U8 *src=*_src,*ptr2,*st_ptr;
|
||||
I64 i,etype;
|
||||
CHashExport *tmpex=NULL;
|
||||
CHashImport *tmpiss;
|
||||
Bool first=TRUE;
|
||||
|
||||
while (etype=*src++) {
|
||||
i=*src(U32 *)++;
|
||||
st_ptr=src;
|
||||
src+=StrLen(st_ptr)+1;
|
||||
if (*st_ptr) {
|
||||
if (!first) {
|
||||
*_src=st_ptr-5;
|
||||
return;
|
||||
} else {
|
||||
first=FALSE;
|
||||
if (!(tmpex=HashFind(st_ptr,
|
||||
Fs->hash_table,HTG_ALL-HTT_IMPORT_SYS_SYM))) {
|
||||
if (!(ld_flags & LDF_SILENT))
|
||||
"Unresolved Reference:%s\n",st_ptr;
|
||||
tmpiss=CAlloc(sizeof(CHashImport));
|
||||
tmpiss->str=StrNew(st_ptr);
|
||||
tmpiss->type=HTT_IMPORT_SYS_SYM;
|
||||
tmpiss->module_header_entry=st_ptr-5;
|
||||
tmpiss->module_base=module_base;
|
||||
HashAdd(tmpiss,Fs->hash_table);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tmpex) {
|
||||
ptr2=module_base+i;
|
||||
if (tmpex->type & HTT_FUN)
|
||||
i=tmpex(CHashFun *)->exe_addr;
|
||||
else if (tmpex->type & HTT_GLBL_VAR)
|
||||
i=tmpex(CHashGlblVar *)->data_addr;
|
||||
else
|
||||
i=tmpex->val;
|
||||
switch (etype) {
|
||||
case IET_REL_I8: *ptr2(U8 *) =i-ptr2-1; break;
|
||||
case IET_IMM_U8: *ptr2(U8 *) =i; break;
|
||||
case IET_REL_I16: *ptr2(U16 *)=i-ptr2-2; break;
|
||||
case IET_IMM_U16: *ptr2(U16 *)=i; break;
|
||||
case IET_REL_I32: *ptr2(U32 *)=i-ptr2-4; break;
|
||||
case IET_IMM_U32: *ptr2(U32 *)=i; break;
|
||||
case IET_REL_I64: *ptr2(I64 *)=i-ptr2-8; break;
|
||||
case IET_IMM_I64: *ptr2(I64 *)=i; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*_src=src-1;
|
||||
}
|
||||
|
||||
U0 SysSymImportsResolve(U8 *st_ptr,I64 ld_flags)
|
||||
{
|
||||
CHashImport *tmpiss;
|
||||
U8 *ptr;
|
||||
while (tmpiss=HashSingleTableFind(st_ptr,
|
||||
Fs->hash_table,HTT_IMPORT_SYS_SYM)) {
|
||||
ptr=tmpiss->module_header_entry;
|
||||
LoadOneImport(&ptr,tmpiss->module_base,ld_flags);
|
||||
tmpiss->type=HTT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
U0 LoadPass1(U8 *src,U8 *module_base,I64 ld_flags)
|
||||
{
|
||||
U8 *ptr2,*ptr3,*st_ptr;
|
||||
I64 i,j,cnt,etype;
|
||||
CHashExport *tmpex=NULL;
|
||||
while (etype=*src++) {
|
||||
i=*src(U32 *)++;
|
||||
st_ptr=src;
|
||||
src+=StrLen(st_ptr)+1;
|
||||
switch (etype) {
|
||||
case IET_REL32_EXPORT:
|
||||
case IET_IMM32_EXPORT:
|
||||
case IET_REL64_EXPORT:
|
||||
case IET_IMM64_EXPORT:
|
||||
tmpex=CAlloc(sizeof(CHashExport));
|
||||
tmpex->str=StrNew(st_ptr);
|
||||
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
|
||||
if (etype==IET_IMM32_EXPORT||etype==IET_IMM64_EXPORT)
|
||||
tmpex->val=i;
|
||||
else
|
||||
tmpex->val=i+module_base;
|
||||
HashAdd(tmpex,Fs->hash_table);
|
||||
SysSymImportsResolve(st_ptr,ld_flags);
|
||||
break;
|
||||
case IET_REL_I0...IET_IMM_I64:
|
||||
src=st_ptr-5;
|
||||
LoadOneImport(&src,module_base,ld_flags);
|
||||
break;
|
||||
case IET_ABS_ADDR:
|
||||
if (ld_flags & LDF_NO_ABSS)
|
||||
src+=i*sizeof(U32);
|
||||
else {
|
||||
cnt=i;
|
||||
for (j=0;j<cnt;j++) {
|
||||
ptr2=module_base+*src(U32 *)++;
|
||||
*ptr2(U32 *)+=module_base;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
start:
|
||||
case IET_CODE_HEAP:
|
||||
ptr3=MAlloc(*src(I32 *)++,Fs->code_heap);
|
||||
break;
|
||||
case IET_ZEROED_CODE_HEAP:
|
||||
ptr3=CAlloc(*src(I32 *)++,Fs->code_heap);
|
||||
break;
|
||||
end:
|
||||
if (*st_ptr) {
|
||||
tmpex=CAlloc(sizeof(CHashExport));
|
||||
tmpex->str=StrNew(st_ptr);
|
||||
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
|
||||
tmpex->val=ptr3;
|
||||
HashAdd(tmpex,Fs->hash_table);
|
||||
}
|
||||
cnt=i;
|
||||
for (j=0;j<cnt;j++) {
|
||||
ptr2=module_base+*src(U32 *)++;
|
||||
*ptr2(I32 *)+=ptr3;
|
||||
}
|
||||
break;
|
||||
|
||||
start:
|
||||
case IET_DATA_HEAP:
|
||||
ptr3=MAlloc(*src(I64 *)++);
|
||||
break;
|
||||
case IET_ZEROED_DATA_HEAP:
|
||||
ptr3=CAlloc(*src(I64 *)++);
|
||||
break;
|
||||
end:
|
||||
if (*st_ptr) {
|
||||
tmpex=CAlloc(sizeof(CHashExport));
|
||||
tmpex->str=StrNew(st_ptr);
|
||||
tmpex->type=HTT_EXPORT_SYS_SYM|HTF_IMM;
|
||||
tmpex->val=ptr3;
|
||||
HashAdd(tmpex,Fs->hash_table);
|
||||
}
|
||||
cnt=i;
|
||||
for (j=0;j<cnt;j++) {
|
||||
ptr2=module_base+*src(U32 *)++;
|
||||
*ptr2(I64 *)+=ptr3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 LoadPass2(U8 *src,U8 *module_base,I64)
|
||||
{
|
||||
U8 *st_ptr;
|
||||
I64 i,etype;
|
||||
while (etype=*src++) {
|
||||
i=*src(U32 *)++;
|
||||
st_ptr=src;
|
||||
src+=StrLen(st_ptr)+1;
|
||||
switch (etype) {
|
||||
case IET_MAIN:
|
||||
Call(i+module_base);
|
||||
break;
|
||||
case IET_ABS_ADDR:
|
||||
src+=sizeof(U32)*i;
|
||||
break;
|
||||
case IET_CODE_HEAP:
|
||||
case IET_ZEROED_CODE_HEAP:
|
||||
src+=4+sizeof(U32)*i;
|
||||
break;
|
||||
case IET_DATA_HEAP:
|
||||
case IET_ZEROED_DATA_HEAP:
|
||||
src+=8+sizeof(U32)*i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBinFile *Load(U8 *filename,I64 ld_flags=0,CBinFile *bfh_addr=INVALID_PTR)
|
||||
{//Load a .BIN file module into memory.
|
||||
//bfh_addr==INVALID_PTR means don't care what load addr.
|
||||
U8 *fbuf,*module_base,*absname;
|
||||
I64 size,module_align,misalignment;
|
||||
CBinFile *bfh;
|
||||
|
||||
fbuf=DftExt(filename,"BIN.Z");
|
||||
if (!(bfh=FileRead(fbuf,&size))) {
|
||||
Free(fbuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//See $LK,"Patch Table Generation",A="FF:::/Compiler/CMain.HC,IET_ABS_ADDR"$
|
||||
module_align=1<<bfh->module_align_bits;
|
||||
if (!module_align || bfh->bin_signature!=BIN_SIGNATURE_VAL) {
|
||||
Free(bfh);
|
||||
Free(fbuf);
|
||||
throw('BinModul');
|
||||
}
|
||||
|
||||
if (bfh_addr==INVALID_PTR) {
|
||||
if (bfh->module_org==INVALID_PTR) {
|
||||
misalignment=module_align-sizeof(CBinFile);
|
||||
if (misalignment<0)
|
||||
misalignment&=module_align-1;
|
||||
if (Fs->code_heap!=Fs->data_heap) {
|
||||
if (module_align<16)
|
||||
module_align=16;
|
||||
bfh_addr=MAllocAligned(size,module_align,Fs->code_heap,misalignment);
|
||||
} else if (module_align>8)
|
||||
bfh_addr=MAllocAligned(size,module_align,,misalignment);
|
||||
else {//Less than 2Gig system memory
|
||||
bfh_addr=bfh;
|
||||
goto lo_skip; //File is already in code heap area, don't copy.
|
||||
}
|
||||
} else
|
||||
bfh_addr=bfh->module_org;
|
||||
}
|
||||
MemCpy(bfh_addr,bfh,size);
|
||||
Free(bfh);
|
||||
|
||||
lo_skip:
|
||||
module_base=bfh_addr(U8 *)+sizeof(CBinFile);
|
||||
|
||||
absname=FileNameAbs(fbuf);
|
||||
Free(fbuf);
|
||||
fbuf=StrNew(absname);
|
||||
FileExtRem(fbuf);
|
||||
if (fbuf[1]==':' && StrLen(fbuf)>2)
|
||||
HashGenericAdd(fbuf+2,HTT_MODULE|HTF_PUBLIC,bfh_addr);
|
||||
LoadPass1(bfh_addr(U8 *)+bfh_addr->patch_table_offset,module_base,ld_flags);
|
||||
if (!(ld_flags&LDF_JUST_LOAD))
|
||||
LoadPass2(bfh_addr(U8 *)+bfh_addr->patch_table_offset,module_base,ld_flags);
|
||||
Free(absname);
|
||||
Free(fbuf);
|
||||
return bfh_addr;
|
||||
}
|
||||
|
||||
U0 LoadKernel()
|
||||
{
|
||||
HashGenericAdd(KERNEL_MODULE_NAME,HTT_MODULE|HTF_PUBLIC,
|
||||
mem_boot_base-sizeof(CBinFile));
|
||||
|
||||
//Abs patches done here $LK,"CPatchTableAbsAddr",A="FF:D:/Kernel/KStart32.HC,CPatchTableAbsAddr"$.
|
||||
LoadPass1(sys_boot_patch_table_base,mem_boot_base,LDF_NO_ABSS|LDF_SILENT);
|
||||
|
||||
//No main routines
|
||||
// LoadPass2(sys_boot_patch_table_base,mem_boot_base,0);
|
||||
}
|
||||
@@ -0,0 +1,648 @@
|
||||
asm {
|
||||
//************************************
|
||||
_D3_NORM::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
FLD U64 [RDX]
|
||||
FMUL ST0,ST0
|
||||
FLD U64 8[RDX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RDX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FSQRT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_D3_NORM_SQR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
FLD U64 [RDX]
|
||||
FMUL ST0,ST0
|
||||
FLD U64 8[RDX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RDX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_D3_DIST::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 [RDX]
|
||||
FSUB ST0,U64 [RBX]
|
||||
FMUL ST0,ST0
|
||||
FLD U64 8[RDX]
|
||||
FSUB ST0,U64 8[RBX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RDX]
|
||||
FSUB ST0,U64 16[RBX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FSQRT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_DIST_SQR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 [RDX]
|
||||
FSUB ST0,U64 [RBX]
|
||||
FMUL ST0,ST0
|
||||
FLD U64 8[RDX]
|
||||
FSUB ST0,U64 8[RBX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RDX]
|
||||
FSUB ST0,U64 16[RBX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_CROSS::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG2[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
|
||||
FLD U64 8[RDX]
|
||||
FMUL ST0,U64 16[RBX]
|
||||
FLD U64 16[RDX]
|
||||
FMUL ST0,U64 8[RBX]
|
||||
FSUBP ST1,ST0
|
||||
FSTP U64 [RAX]
|
||||
|
||||
FLD U64 [RDX]
|
||||
FMUL ST0,U64 16[RBX]
|
||||
FLD U64 16[RDX]
|
||||
FMUL ST0,U64 [RBX]
|
||||
FSUBRP ST1,ST0
|
||||
FSTP U64 8[RAX]
|
||||
|
||||
FLD U64 [RDX]
|
||||
FMUL ST0,U64 8[RBX]
|
||||
FLD U64 8[RDX]
|
||||
FMUL ST0,U64 [RBX]
|
||||
FSUBP ST1,ST0
|
||||
FSTP U64 16[RAX]
|
||||
|
||||
POP RBP
|
||||
RET1 24
|
||||
//************************************
|
||||
_D3_DOT::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 [RDX]
|
||||
FMUL ST0,U64 [RBX]
|
||||
FLD U64 8[RDX]
|
||||
FMUL ST0,U64 8[RBX]
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RDX]
|
||||
FMUL ST0,U64 16[RBX]
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_ADD::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG2[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
FLD U64 [RDX]
|
||||
FADD ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD U64 8[RDX]
|
||||
FADD ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FLD U64 16[RDX]
|
||||
FADD ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 24
|
||||
//************************************
|
||||
_D3_SUB::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG2[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
FLD U64 [RDX]
|
||||
FSUB ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD U64 8[RDX]
|
||||
FSUB ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FLD U64 16[RDX]
|
||||
FSUB ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 24
|
||||
//************************************
|
||||
_D3_MUL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG3[RBP]
|
||||
FLD U64 SF_ARG2[RBP]
|
||||
FLD ST0
|
||||
FMUL ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD ST0
|
||||
FMUL ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FMUL ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 24
|
||||
//************************************
|
||||
_D3_DIV::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 SF_ARG3[RBP]
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FDIVR ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 24
|
||||
//************************************
|
||||
_D3_ZERO::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
XOR RDX,RDX
|
||||
MOV U64 [RAX],RDX
|
||||
MOV U64 8[RAX],RDX
|
||||
MOV U64 16[RAX],RDX
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_D3_COPY::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
MOV RDX,U64 [RBX]
|
||||
MOV U64 [RAX],RDX
|
||||
MOV RDX,U64 8[RBX]
|
||||
MOV U64 8[RAX],RDX
|
||||
MOV RDX,U64 16[RBX]
|
||||
MOV U64 16[RAX],RDX
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_EQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG2[RBP]
|
||||
MOV U64 [RAX],RDX
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV U64 8[RAX],RDX
|
||||
MOV RDX,U64 SF_ARG4[RBP]
|
||||
MOV U64 16[RAX],RDX
|
||||
POP RBP
|
||||
RET1 32
|
||||
//************************************
|
||||
_D3_ADD_EQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 [RAX]
|
||||
FADD ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD U64 8[RAX]
|
||||
FADD ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FLD U64 16[RAX]
|
||||
FADD ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_SUB_EQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
FLD U64 [RAX]
|
||||
FSUB ST0,U64 [RBX]
|
||||
FSTP U64 [RAX]
|
||||
FLD U64 8[RAX]
|
||||
FSUB ST0,U64 8[RBX]
|
||||
FSTP U64 8[RAX]
|
||||
FLD U64 16[RAX]
|
||||
FSUB ST0,U64 16[RBX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_MUL_EQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
FLD U64 SF_ARG2[RBP]
|
||||
FLD ST0
|
||||
FMUL ST0,U64 [RAX]
|
||||
FSTP U64 [RAX]
|
||||
FLD ST0
|
||||
FMUL ST0,U64 8[RAX]
|
||||
FSTP U64 8[RAX]
|
||||
FMUL ST0,U64 16[RAX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_DIV_EQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
FLD U64 SF_ARG2[RBP]
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 [RAX]
|
||||
FSTP U64 [RAX]
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 8[RAX]
|
||||
FSTP U64 8[RAX]
|
||||
FDIVR ST0,U64 16[RAX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_D3_UNIT::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
FLD U64 [RAX]
|
||||
FMUL ST0,ST0
|
||||
FLD U64 8[RAX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FLD U64 16[RAX]
|
||||
FMUL ST0,ST0
|
||||
FADDP ST1,ST0
|
||||
FSQRT
|
||||
FST U64 SF_ARG1[RBP]
|
||||
MOV RBX,SF_ARG1[RBP]
|
||||
TEST RBX,RBX
|
||||
JZ @@05
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 [RAX]
|
||||
FSTP U64 [RAX]
|
||||
FLD ST0
|
||||
FDIVR ST0,U64 8[RAX]
|
||||
FSTP U64 8[RAX]
|
||||
FDIVR ST0,U64 16[RAX]
|
||||
FSTP U64 16[RAX]
|
||||
POP RBP
|
||||
RET1 8
|
||||
@@05: FFREE ST0
|
||||
FINCSTP
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_SQR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FMUL ST0,ST0
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_SIGN::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FTST
|
||||
FSTSW
|
||||
FFREE ST0
|
||||
FINCSTP
|
||||
MOV RDX,RAX
|
||||
XOR RAX,RAX
|
||||
BT RDX,14
|
||||
JC @@05
|
||||
MOV RAX,1.0
|
||||
BT RDX,8
|
||||
JNC @@05
|
||||
MOV RAX,-1.0
|
||||
@@05: POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_ARG::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLD U64 SF_ARG2[RBP]
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
@@05: FPATAN
|
||||
FSTSW
|
||||
TEST AX,0x400
|
||||
JNZ @@05
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_ROUND::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,8
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
AND AX,~0x0C00
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
_TRUNC::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,8
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
OR AX,0x0C00
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
_FLOOR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,8
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
AND AX,~0x0C00
|
||||
OR AX,0x0400
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
_CEIL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,8
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
AND AX,~0x0C00
|
||||
OR AX,0x0800
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,SF_ARG1[RBP]
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
SYS_POW::
|
||||
// RAX=RDX`RAX
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,24
|
||||
TEST RAX,RAX //To power of zero?
|
||||
JNZ @@05
|
||||
MOV RAX,1.0
|
||||
JMP @@20
|
||||
@@05: TEST RDX,RDX //zero to a power?
|
||||
JNZ @@10
|
||||
XOR RAX,RAX
|
||||
JMP @@20
|
||||
@@10: MOV RCX,RAX //RCX=pow
|
||||
MOV U64 -8[RBP],RDX
|
||||
MOV U64 -16[RBP],RAX
|
||||
FSTCW U16 -24[RBP]
|
||||
MOV AX,U16 -24[RBP]
|
||||
MOV U16 -22[RBP],AX
|
||||
OR AX,0x0C00
|
||||
MOV U16 -24[RBP],AX
|
||||
FLDCW U16 -24[RBP]
|
||||
FLD U64 -16[RBP]
|
||||
FLD U64 -8[RBP]
|
||||
FABS //base should be pos
|
||||
FYL2X // y*log2(x)
|
||||
FST U64 -8[RBP]
|
||||
FRNDINT
|
||||
FLD U64 -8[RBP]
|
||||
FSUBRP ST1,ST0
|
||||
F2XM1
|
||||
FLD1
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 -16[RBP]
|
||||
FLD U64 -8[RBP]
|
||||
FLD U64 -16[RBP]
|
||||
FSCALE // ST0<<ST1
|
||||
TEST RDX,RDX //was base neg?
|
||||
JGE @@15
|
||||
MOV U64 -16[RBP],RCX
|
||||
FLD U64 -16[RBP]
|
||||
FISTTP U64 -16[RBP]
|
||||
TEST U64 -16[RBP],1
|
||||
JZ @@15 //was pow odd?
|
||||
FCHS
|
||||
@@15: FSTP U64 -8[RBP]
|
||||
FFREE ST0
|
||||
FINCSTP
|
||||
FLDCW U16 -22[RBP]
|
||||
MOV RAX,U64 -8[RBP]
|
||||
@@20: LEAVE
|
||||
RET
|
||||
//************************************
|
||||
_POW::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
CALL SYS_POW
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_POW10::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,16
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
OR AX,0x0C00
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLDL2T
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FMULP ST1,ST0
|
||||
FST U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FSUBRP ST1,ST0
|
||||
F2XM1
|
||||
FLD1
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 -16[RBP]
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FLD U64 -16[RBP]
|
||||
FSCALE // ST0<<ST1
|
||||
FSTP U64 -16[RBP]
|
||||
FFREE ST0
|
||||
FINCSTP
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
MOV RAX,U64 -16[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
_EXP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,16
|
||||
FSTCW U16 -8[RBP]
|
||||
MOV AX,U16 -8[RBP]
|
||||
MOV U16 -6[RBP],AX
|
||||
OR AX,0x0C00
|
||||
MOV U16 -8[RBP],AX
|
||||
FLDCW U16 -8[RBP]
|
||||
|
||||
FLDL2E
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FMULP ST1,ST0
|
||||
FST U64 SF_ARG1[RBP]
|
||||
FRNDINT
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FSUBRP ST1,ST0
|
||||
F2XM1
|
||||
FLD1
|
||||
FADDP ST1,ST0
|
||||
FSTP U64 -16[RBP]
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FLD U64 -16[RBP]
|
||||
FSCALE // ST0<<ST1
|
||||
FSTP U64 -16[RBP]
|
||||
FFREE ST0
|
||||
FINCSTP
|
||||
|
||||
FLDCW U16 -6[RBP]
|
||||
MOV RAX,U64 -16[RBP]
|
||||
LEAVE
|
||||
RET1 8
|
||||
//************************************
|
||||
_LOG10::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLDLG2
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FYL2X // y*log2(x)
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_LOG2::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLD1
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FYL2X // y*log2(x)
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_LN::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLDLN2
|
||||
FLD U64 SF_ARG1[RBP]
|
||||
FYL2X // y*log2(x)
|
||||
FSTP U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_FLDCW::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
FLDCW U16 SF_ARG1[RBP]
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_FSTCW::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
SUB RSP,8
|
||||
FSTCW U16 -8[RBP]
|
||||
MOVZX RAX,U16 -8[RBP]
|
||||
LEAVE
|
||||
RET
|
||||
//************************************
|
||||
_FSTSW::
|
||||
XOR RAX,RAX
|
||||
FSTSW
|
||||
RET
|
||||
//************************************
|
||||
_FCLEX::
|
||||
FCLEX
|
||||
RET
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
F64 Clamp(F64 d,F64 lo,F64 hi)
|
||||
{//Clamp to F64 [] range.
|
||||
if (d<lo)
|
||||
return lo;
|
||||
if (d>hi)
|
||||
return hi;
|
||||
return d;
|
||||
}
|
||||
|
||||
F64 Min(F64 n1,F64 n2)
|
||||
{//Min of two F64s.
|
||||
if (n1<=n2)
|
||||
return n1;
|
||||
else
|
||||
return n2;
|
||||
}
|
||||
|
||||
F64 Max(F64 n1,F64 n2)
|
||||
{//Max of two F64s.
|
||||
if (n1>=n2)
|
||||
return n1;
|
||||
else
|
||||
return n2;
|
||||
}
|
||||
|
||||
F64 Pow10I64(I64 i)
|
||||
{//F64 int powers of ten.
|
||||
if (i>308)
|
||||
return ì;
|
||||
else if (i<-308)
|
||||
return 0.0;
|
||||
else
|
||||
return pow10_I64[i+309];
|
||||
}
|
||||
|
||||
U64 FloorU64(U64 num,U64 to)
|
||||
{//Int multiples of num.
|
||||
return num-num%to;
|
||||
}
|
||||
|
||||
U64 CeilU64(U64 num,U64 to)
|
||||
{//Int multiples of num.
|
||||
num+=to-1;
|
||||
return num-num%to;
|
||||
}
|
||||
|
||||
I64 RoundI64(I64 num,I64 to)
|
||||
{//Int multiples of num.
|
||||
return num-num%to;
|
||||
}
|
||||
|
||||
I64 FloorI64(I64 num,I64 to)
|
||||
{//Int multiples of num.
|
||||
if (num>=0)
|
||||
return num-num%to;
|
||||
else {
|
||||
num++;
|
||||
return num-num%to-to;
|
||||
}
|
||||
}
|
||||
|
||||
I64 CeilI64(I64 num,I64 to)
|
||||
{//Int multiples of num.
|
||||
if (num>=0) {
|
||||
num+=to-1;
|
||||
return num-num%to;
|
||||
} else {
|
||||
num+=to-1;
|
||||
return num-num%to-to;
|
||||
}
|
||||
}
|
||||
|
||||
//See $LK,"::/Doc/Credits.DD"$.
|
||||
#define LIN_CONGRUE_A 6364136223846793005
|
||||
#define LIN_CONGRUE_C 1442695040888963407
|
||||
|
||||
I16 RandI16()
|
||||
{//Random I16.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res.i16[0];
|
||||
}
|
||||
|
||||
U16 RandU16()
|
||||
{//Random U16.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res.u16[0];
|
||||
}
|
||||
|
||||
I32 RandI32()
|
||||
{//Random I32.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res.i32[0];
|
||||
}
|
||||
|
||||
U32 RandU32()
|
||||
{//Random U32.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res.u32[0];
|
||||
}
|
||||
|
||||
I64 RandI64()
|
||||
{//Random I64.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res;
|
||||
}
|
||||
|
||||
U64 RandU64()
|
||||
{//Random U64.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return res;
|
||||
}
|
||||
|
||||
F64 Rand()
|
||||
{//Random F64.
|
||||
I64 res=Fs->rand_seed;
|
||||
res=LIN_CONGRUE_A*res^(res&0xFFFFFFFF0000)>>16+LIN_CONGRUE_C;
|
||||
if (!Bt(&Fs->task_flags,TASKf_NONTIMER_RAND))
|
||||
res^=GetTSC;
|
||||
Fs->rand_seed=res;
|
||||
return (res&0x3FFFFFFFFFFFFFFF)/ToF64(0x4000000000000000);
|
||||
}
|
||||
|
||||
I64 Seed(I64 seed=0,CTask *task=NULL)
|
||||
{//Set $LK,"Rand",A="MN:Rand"$() seed. Zero for timer-based.
|
||||
if (!task) task=Fs;
|
||||
if (seed) {
|
||||
LBts(&task->task_flags,TASKf_NONTIMER_RAND);
|
||||
return task->rand_seed=seed;
|
||||
} else {
|
||||
LBtr(&task->task_flags,TASKf_NONTIMER_RAND);
|
||||
return task->rand_seed^=GetTSC;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
U0 PortNop()
|
||||
{//Innoculous (reads IRQ Mask) which should take fixed time
|
||||
//because it's an ISA-bus standard. It takes 1.0uS-2.0uS.
|
||||
InU8(0x21);
|
||||
}
|
||||
|
||||
U16 EndianU16(U16 d)
|
||||
{//Swap big<-->little endian.
|
||||
I64 res=0;
|
||||
res.u8[1]=d.u8[0];
|
||||
res.u8[0]=d.u8[1];
|
||||
return res;
|
||||
}
|
||||
|
||||
U32 EndianU32(U32 d)
|
||||
{//Swap big<-->little endian.
|
||||
I64 res=0;
|
||||
res.u8[3]=d.u8[0];
|
||||
res.u8[2]=d.u8[1];
|
||||
res.u8[1]=d.u8[2];
|
||||
res.u8[0]=d.u8[3];
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 EndianI64(I64 d)
|
||||
{//Swap big<-->little endian.
|
||||
U64 res;
|
||||
res.u8[7]=d.u8[0];
|
||||
res.u8[6]=d.u8[1];
|
||||
res.u8[5]=d.u8[2];
|
||||
res.u8[4]=d.u8[3];
|
||||
res.u8[3]=d.u8[4];
|
||||
res.u8[2]=d.u8[5];
|
||||
res.u8[1]=d.u8[6];
|
||||
res.u8[0]=d.u8[7];
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 BCnt(I64 d)
|
||||
{//Count set bits in I64.
|
||||
I64 res=0,i;
|
||||
for (i=0;i<8;i++)
|
||||
res+=set_bits_table[d.u8[i]];
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 IntCore0TimerHndlr(CTask *)
|
||||
{//Called from $LK,"IntCore0TimerHndlr",A="FF:::/Kernel/KInts.HC,IntCore0TimerHndlr"$
|
||||
I64 i;
|
||||
if (mp_cnt>1)
|
||||
while (LBts(&sys_semas[SEMA_SYS_TIMER],0))
|
||||
PAUSE
|
||||
lock cnts.jiffies++;
|
||||
cnts.timer+=SYS_TIMER0_PERIOD+1;
|
||||
LBtr(&sys_semas[SEMA_SYS_TIMER],0);
|
||||
for (i=1;i<mp_cnt;i++)
|
||||
MPInt(I_TIMER,i);
|
||||
OutU8(0x20,0x20); //Acknowledge PIC Interrupt
|
||||
}
|
||||
|
||||
I64 SysTimerRead()
|
||||
{//System timer count with overflow already handled.
|
||||
I64 i,res;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (mp_cnt>1)
|
||||
while (LBts(&sys_semas[SEMA_SYS_TIMER],0))
|
||||
PAUSE
|
||||
OutU8(0x43,0); //Latch Timer0
|
||||
if ((i=InU8(0x40)+InU8(0x40)<<8)==SYS_TIMER0_PERIOD) {
|
||||
if (InU8(0x20) & 1)
|
||||
i=-1;
|
||||
}
|
||||
res=cnts.timer+SYS_TIMER0_PERIOD-i;
|
||||
LBtr(&sys_semas[SEMA_SYS_TIMER],0);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 HPET()
|
||||
{ //Get high precision event timer.
|
||||
return *(dev.uncached_alias+HPET_MAIN_CNT)(I64 *);
|
||||
}
|
||||
|
||||
I64 TimeStampFreqCal()
|
||||
{
|
||||
static I64 time_stamp_start=0,timer_start=0,HPET_start=0;
|
||||
I64 i;
|
||||
if (time_stamp_start) {
|
||||
PUSHFD
|
||||
CLI
|
||||
if (HPET_start) {
|
||||
cnts.time_stamp_freq=cnts.HPET_freq*(GetTSC-time_stamp_start);
|
||||
i=HPET-HPET_start;
|
||||
} else {
|
||||
cnts.time_stamp_freq=SYS_TIMER_FREQ*(GetTSC-time_stamp_start);
|
||||
i=SysTimerRead-timer_start;
|
||||
}
|
||||
if (!i)
|
||||
AdamErr("Timer Cal Error");
|
||||
else {
|
||||
cnts.time_stamp_freq/=i;
|
||||
cnts.time_stamp_kHz_freq=cnts.time_stamp_freq/1000;
|
||||
cnts.time_stamp_calibrated=TRUE;
|
||||
}
|
||||
POPFD
|
||||
}
|
||||
PUSHFD
|
||||
CLI
|
||||
if (cnts.HPET_freq) {
|
||||
timer_start=0;
|
||||
HPET_start=HPET;
|
||||
} else {
|
||||
timer_start=SysTimerRead;
|
||||
HPET_start=0;
|
||||
}
|
||||
time_stamp_start=GetTSC;
|
||||
POPFD
|
||||
return cnts.time_stamp_freq;
|
||||
}
|
||||
|
||||
F64 tS()
|
||||
{//Time since boot in seconds as a float.
|
||||
if (cnts.HPET_freq)
|
||||
return ToF64(HPET-cnts.HPET_initial)/cnts.HPET_freq;
|
||||
else
|
||||
return SysTimerRead/ToF64(SYS_TIMER_FREQ);
|
||||
}
|
||||
|
||||
Bool Blink(F64 Hz=2.5)
|
||||
{//Return TRUE, then FALSE, then TRUE at given frequency.
|
||||
if (!Hz) return 0;
|
||||
return ToI64(cnts.jiffies*2*Hz/JIFFY_FREQ)&1;
|
||||
}
|
||||
|
||||
U0 Busy(I64 æS)
|
||||
{//Loosely timed.
|
||||
I64 i;
|
||||
if (cnts.HPET_freq) {
|
||||
i=HPET+cnts.HPET_freq*æS/1000000;
|
||||
while (HPET<i);
|
||||
} else
|
||||
for (i=0;i<æS;i++)
|
||||
PortNop;
|
||||
}
|
||||
|
||||
U0 SleepUntil(I64 wake_jiffy)
|
||||
{//Not for power-saving. It is to make a program pause without hogging the CPU.
|
||||
Bool old_idle=LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
Fs->wake_jiffy=wake_jiffy;
|
||||
Yield;
|
||||
LBEqu(&Fs->task_flags,TASKf_IDLE,old_idle);
|
||||
}
|
||||
|
||||
U0 Sleep(I64 mS)
|
||||
{//Not for power-saving. It is to make a program pause without hogging the CPU.
|
||||
if (!mS)
|
||||
Yield;
|
||||
else
|
||||
SleepUntil(cnts.jiffies+mS*JIFFY_FREQ/1000);
|
||||
}
|
||||
|
||||
F64 Ona2Freq(I8 ona)
|
||||
{//Ona to freq. Ona=60 is 440.0Hz.
|
||||
if (ona==ONA_REST)
|
||||
return 0;
|
||||
else
|
||||
return 440.0/32*2.0`(ona/12.0);
|
||||
}
|
||||
|
||||
I8 Freq2Ona(F64 freq)
|
||||
{//Freq to Ona. 440.0Hz is Ona=60.
|
||||
if (freq>0)
|
||||
return ClampI64(12*Log2(32.0/440.0*freq),ONA_REST+1,I8_MAX);
|
||||
else
|
||||
return ONA_REST;
|
||||
}
|
||||
|
||||
U0 Snd(I8 ona=ONA_REST)
|
||||
{//Play freq. Zero means off.
|
||||
I64 period;
|
||||
CSndData *d;
|
||||
if (!Bt(&sys_semas[SEMA_MUTE],0) &&
|
||||
!LBts(&sys_semas[SEMA_SND],0)) { //Mutex. Just throw-out if in use
|
||||
if (ona<=ONA_REST) {
|
||||
snd.ona=ona;
|
||||
OutU8(0x61,InU8(0x61)&~3);
|
||||
} else if (ona!=snd.ona) {
|
||||
snd.ona=ona;
|
||||
period=ClampI64(SYS_TIMER_FREQ/Ona2Freq(ona),1,U16_MAX);
|
||||
OutU8(0x43,0xB6);
|
||||
OutU8(0x42,period);
|
||||
OutU8(0x42,period.u8[1]);
|
||||
OutU8(0x61,3|InU8(0x61));
|
||||
}
|
||||
if (!IsDbgMode && snd.record) {
|
||||
d=ACAlloc(sizeof(CSndData));
|
||||
d->ona=ona;
|
||||
d->time=tS;
|
||||
QueIns(d,snd.record_head.last);
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_SND],0);
|
||||
}
|
||||
}
|
||||
|
||||
U0 SndRst()
|
||||
{//Fix stuck sound.
|
||||
if (Bt(&sys_semas[SEMA_SND],0)) {
|
||||
Sleep(1);
|
||||
if (Bt(&sys_semas[SEMA_SND],0)) {
|
||||
Sleep(1);
|
||||
LBtr(&sys_semas[SEMA_SND],0);
|
||||
}
|
||||
}
|
||||
Snd;
|
||||
}
|
||||
|
||||
U0 Beep(I8 ona=62,Bool busy=FALSE)
|
||||
{//Make beep at given ona freq.
|
||||
Snd(ona);
|
||||
if (busy)
|
||||
Busy(500000);
|
||||
else
|
||||
Sleep(500);
|
||||
Snd;
|
||||
if (busy)
|
||||
Busy(200000);
|
||||
else
|
||||
Sleep(200);
|
||||
}
|
||||
|
||||
Bool Mute(Bool val)
|
||||
{//Turn-off sound.
|
||||
Bool res;
|
||||
if (val) {
|
||||
PUSHFD
|
||||
CLI
|
||||
Snd;
|
||||
res=LBts(&sys_semas[SEMA_MUTE],0);
|
||||
POPFD
|
||||
} else
|
||||
res=LBtr(&sys_semas[SEMA_MUTE],0);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool IsMute()
|
||||
{//Return is-mute flag.
|
||||
return Bt(&sys_semas[SEMA_MUTE],0);
|
||||
}
|
||||
|
||||
Bool Silent(Bool val=ON)
|
||||
{//Turn-off StdOut console text. (Not sound.)
|
||||
return LBEqu(&Fs->display_flags,DISPLAYf_SILENT,val);
|
||||
}
|
||||
|
||||
Bool IsSilent()
|
||||
{//Return StdOut turned-off?
|
||||
return Bt(&Fs->display_flags,DISPLAYf_SILENT);
|
||||
}
|
||||
|
||||
Bool SysDbg(Bool val)
|
||||
{//Set SysDbg bit you can use while debugging.
|
||||
return LBEqu(&sys_semas[SEMA_DEBUG],0,val);
|
||||
}
|
||||
|
||||
Bool IsSysDbg()
|
||||
{//Return SysDbg bit.
|
||||
return Bt(&sys_semas[SEMA_DEBUG],0);
|
||||
}
|
||||
|
||||
Bool Raw(Bool val)
|
||||
{//Set to direct scrn, BLACK & WHITE, non-windowed output mode.
|
||||
if (!val)
|
||||
VGAFlush;
|
||||
return !LBEqu(&Fs->display_flags,DISPLAYf_NOT_RAW,!val);
|
||||
}
|
||||
|
||||
Bool IsRaw()
|
||||
{//Are we in BLACK & WHITE raw scrn mode?
|
||||
return !Bt(&Fs->display_flags,DISPLAYf_NOT_RAW);
|
||||
}
|
||||
|
||||
Bool SingleUser(Bool val)
|
||||
{//Set single-user mode.
|
||||
return LBEqu(&sys_semas[SEMA_SINGLE_USER],0,val);
|
||||
}
|
||||
|
||||
Bool IsSingleUser()
|
||||
{//Return single-user mode.
|
||||
return Bt(&sys_semas[SEMA_SINGLE_USER],0);
|
||||
}
|
||||
|
||||
Bool DbgMode(Bool val)
|
||||
{//Set dbg-mode.
|
||||
return LBEqu(&sys_semas[SEMA_DBG_MODE],0,val);
|
||||
}
|
||||
|
||||
Bool IsDbgMode()
|
||||
{//Return dbg-mode.
|
||||
return Bt(&sys_semas[SEMA_DBG_MODE],0);
|
||||
}
|
||||
|
||||
U0 ProgressBarsRst(U8 *path=NULL)
|
||||
{//Reset all progress bars to zero.
|
||||
CallExtStr("ProgressBarsRegTf",path);
|
||||
MemSet(sys_progresses,0,sizeof(sys_progresses));
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
asm {/* See $LK,"::/Doc/Boot.DD"$.
|
||||
TempleOS starts in real, calls some BIOS
|
||||
routines, switches to 32 bit, and 64 bit mode
|
||||
and continues in $LK,"HolyC",A="FI:::/Doc/HolyC.DD"$ at $LK,"KMain",A="MN:KMain"$().
|
||||
|
||||
The boot loader jumps here in real-mode (16-bit).
|
||||
It actually jumps to the $LK,"CBinFile",A="MN:CBinFile"$ header which is
|
||||
placed just before this by $LK,"the compiler",A="FF:::/Compiler/CMain.HC,16 ALIGN"$.
|
||||
The header begins with a short jmp to
|
||||
the start of this file's code which begins
|
||||
with the following small jump past some data.
|
||||
|
||||
This file is first in the Kernel image
|
||||
because it is #included first. $LK,"Kernel.PRJ",A="FF:::/Kernel/Kernel.PRJ,KStart16:1"$
|
||||
*/
|
||||
USE16
|
||||
SYS_KERNEL:: //This must match $LK,"CKernel",A="MN:CKernel"$.
|
||||
JMP I16 CORE0_16BIT_INIT
|
||||
|
||||
//************************************
|
||||
// ASM Global vars required for 16-bit start-up
|
||||
ALIGN 4,OC_NOP
|
||||
SYS_BOOT_SRC:: DU32 BOOT_SRC_NULL;
|
||||
SYS_BOOT_BLK:: DU32 0;
|
||||
SYS_BOOT_PATCH_TABLE_BASE:: DU32 0;
|
||||
SYS_RUN_LEVEL:: DU32 0;
|
||||
#exe {StreamPrint("SYS_COMPILE_TIME:: DU64 0x%X;",Now);} //See $LK,"BootDVDProbe",A="MN:BootDVDProbe"$
|
||||
#assert SYS_COMPILE_TIME+sizeof(CDate)+sizeof(CBinFile)<DVD_BLK_SIZE
|
||||
|
||||
MEM_BOOT_BASE:: DU32 0; //Offset from start used by reboot
|
||||
MEM_E801:: DU16 0,0;
|
||||
MEM_E820:: DU8 MEM_E820_ENTRIES_NUM*sizeof(CMemE820) DUP (0);
|
||||
MEM_PHYSICAL_SPACE:: DU64 0;
|
||||
SYS_GDT_PTR:: DU16 sizeof(CGDT)-1;
|
||||
DU64 0;
|
||||
SYS_PCI_BUSES:: DU16 0;
|
||||
|
||||
ALIGN 16,OC_NOP
|
||||
SYS_GDT:: //See $LK,"CGDT",A="MN:CGDT"$
|
||||
GDT_NULL: DU64 0,0;
|
||||
GDT_BOOT_DS: DU64 0x00CF92000000FFFF,0; //Gets patched.
|
||||
GDT_BOOT_CS: DU64 0x00CF9A000000FFFF,0; //Gets patched.
|
||||
GDT_CS32: DU64 0x00CF9A000000FFFF,0;
|
||||
GDT_CS64: DU64 0x00209A0000000000,0; //The $LK,"Charter",A="FI:::/Doc/Charter.DD"$ says just ring0.
|
||||
GDT_CS64_RING3: DU64 0x0020FA0000000000,0; //$LK,"Ring3",A="FI:::/Demo/Lectures/Ring3.HC"$, so you can play with.
|
||||
GDT_DS: DU64 0x00CF92000000FFFF,0;
|
||||
GDT_DS_RING3: DU64 0x00CFF2000000FFFF,0;
|
||||
GDT_TR: DU8 MP_PROCESSORS_NUM*16 DUP(0);
|
||||
GDT_TR_RING3: DU8 MP_PROCESSORS_NUM*16 DUP(0);
|
||||
#assert $$-SYS_GDT==sizeof(CGDT)
|
||||
|
||||
#assert $$-SYS_KERNEL==sizeof(CKernel)-sizeof(CBinFile)
|
||||
|
||||
//************************************
|
||||
CORE0_16BIT_INIT::
|
||||
//EAX is $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.HC,[SYS_BOOT_SRC]"$. (Val passed from boot blk, $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.)
|
||||
MOV ECX,EAX
|
||||
MOV AX,(BOOT_RAM_LIMIT-BOOT_STK_SIZE)/16
|
||||
MOV SS,AX
|
||||
MOV SP,BOOT_STK_SIZE
|
||||
PUSH ECX //Will be $LK,"SYS_BOOT_SRC",A="FF:::/Kernel/KStart16.HC,[SYS_BOOT_SRC]"$. See $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$ & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.
|
||||
PUSH EBX
|
||||
|
||||
CALL U16 GET_RIP
|
||||
GET_RIP: POP BX
|
||||
SUB BX,GET_RIP
|
||||
SHR BX,4
|
||||
MOV AX,CS
|
||||
ADD AX,BX
|
||||
PUSH AX
|
||||
PUSH U16 @@05
|
||||
RETF
|
||||
|
||||
@@05: STI
|
||||
MOV AX,CS
|
||||
MOV DS,AX
|
||||
|
||||
MOV U32 [SYS_RUN_LEVEL],RLF_16BIT
|
||||
|
||||
MOV AX,0x4F02
|
||||
MOV BX,0x12 //640x480 16 color
|
||||
#exe {
|
||||
if (!kernel_cfg->opts[CFG_TEXT_MODE])
|
||||
StreamPrint("INT 0x10"); //Enable VGA
|
||||
};
|
||||
CMP AX,0x004F
|
||||
JNE @@10 //Jmp if fail
|
||||
BTS U32 [SYS_RUN_LEVEL],RLf_VGA
|
||||
@@10:
|
||||
|
||||
//Get mem maps.
|
||||
MOV AX,0xE801
|
||||
INT 0x15
|
||||
MOV U16 [MEM_E801],CX
|
||||
MOV U16 [MEM_E801+2],DX
|
||||
|
||||
MOV CX,MEM_E820_ENTRIES_NUM-1 //Leave one to terminate
|
||||
XOR EBX,EBX
|
||||
MOV AX,DS
|
||||
MOV ES,AX
|
||||
MOV DI,MEM_E820
|
||||
@@15: PUSH CX
|
||||
MOV EAX,0xE820
|
||||
MOV ECX,sizeof(CMemE820)
|
||||
MOV EDX,'PAMS'
|
||||
INT 0x15
|
||||
JC @@20
|
||||
CMP EAX,'PAMS'
|
||||
JNE @@20
|
||||
TEST EBX,EBX
|
||||
JZ @@20
|
||||
ADD DI,sizeof(CMemE820)
|
||||
POP CX
|
||||
LOOP @@15
|
||||
SUB SP,2
|
||||
@@20: ADD SP,2
|
||||
|
||||
//Find how much space to map, start with E801 limit.
|
||||
XOR EAX,EAX
|
||||
MOV AX,[MEM_E801+2]
|
||||
SHL EAX,16
|
||||
ADD EAX,SYS_16MEG_AREA_LIMIT
|
||||
XOR EDX,EDX
|
||||
|
||||
//Find max of E820 to set mapped space.
|
||||
MOV SI,MEM_E820
|
||||
@@25: MOV CL,CMemE820.type[SI]
|
||||
TEST CL,CL
|
||||
JZ @@35
|
||||
MOV EBX,CMemE820.base[SI]
|
||||
MOV ECX,CMemE820.base+4[SI]
|
||||
ADD EBX,CMemE820.len[SI]
|
||||
ADC ECX,CMemE820.len+4[SI]
|
||||
SUB EBX,EAX
|
||||
SBB ECX,EDX
|
||||
JC @@30
|
||||
MOV EAX,CMemE820.base[SI]
|
||||
MOV EDX,CMemE820.base+4[SI]
|
||||
ADD EAX,CMemE820.len[SI]
|
||||
ADC EDX,CMemE820.len+4[SI]
|
||||
@@30: ADD SI,sizeof(CMemE820)
|
||||
JMP @@25
|
||||
|
||||
@@35: MOV [MEM_PHYSICAL_SPACE],EAX
|
||||
MOV [MEM_PHYSICAL_SPACE+4],EDX
|
||||
|
||||
//Get PCI Bus Info
|
||||
MOV U16 [SYS_PCI_BUSES],256
|
||||
XOR DX,DX
|
||||
MOV AX,0xB101
|
||||
INT 0x1A
|
||||
CMP DX,'PC'
|
||||
JNE @@40
|
||||
MOV CH,0
|
||||
INC CX
|
||||
MOV U16 [SYS_PCI_BUSES],CX
|
||||
@@40:
|
||||
CLI
|
||||
//Enable A20
|
||||
IN AL,0x92
|
||||
OR AL,2
|
||||
OUT 0x92,AL
|
||||
|
||||
POP U32 [SYS_BOOT_BLK]
|
||||
POP U32 [SYS_BOOT_SRC] //See $LK,"BootHD",A="FF:::/Adam/Opt/Boot/BootHD.HC,BOOT_SRC_HARDDRV"$, $LK,"BootDVD",A="FF:::/Adam/Opt/Boot/BootDVD.HC,BOOT_SRC_DVD"$, & $LK,"BootRAM",A="FF:::/Adam/Opt/Boot/BootRAM.HC,BOOT_SRC_RAM"$.
|
||||
|
||||
CLD
|
||||
XOR EAX,EAX
|
||||
MOV AX,CS
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
SHL EAX,4
|
||||
|
||||
MOV U32 [MEM_BOOT_BASE],EAX
|
||||
|
||||
MOV DX,CS
|
||||
SUB DX,sizeof(CBinFile)/16
|
||||
#assert !(sizeof(CBinFile)&15)
|
||||
MOV GS,DX
|
||||
|
||||
MOV EDX,EAX
|
||||
ADD EDX,U32 GS:[CBinFile.patch_table_offset]
|
||||
SUB EDX,sizeof(CBinFile)
|
||||
MOV U32 [SYS_BOOT_PATCH_TABLE_BASE],EDX
|
||||
|
||||
ADD U32 [GDT_BOOT_DS+2],EAX
|
||||
ADD U32 [GDT_BOOT_CS+2],EAX
|
||||
ADD EAX,I32 SYS_GDT
|
||||
MOV U32 [SYS_GDT_PTR+CSysLimitBase.base],EAX
|
||||
LGDT U32 [SYS_GDT_PTR]
|
||||
|
||||
MOV EAX,SYS_START_CR0
|
||||
MOV_CR0_EAX
|
||||
|
||||
/* The assembler doesn't support far jumps so
|
||||
we hand code it. 16-bit code is not important
|
||||
enough to fully implement in the assembler.
|
||||
|
||||
To complete the switch to 32-bit mode, we have to load
|
||||
the code segment with a far jump.
|
||||
*/
|
||||
DU8 0x66,0xEA; //JMP CGDT.boot_cs:CORE0_32BIT_INIT
|
||||
DU32 CORE0_32BIT_INIT;
|
||||
DU16 CGDT.boot_cs;
|
||||
#assert $$+16<=0xFFFF
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
asm {
|
||||
USE32
|
||||
//************************************
|
||||
// ASM Global vars not required for 16-bit start-up
|
||||
ALIGN 8,OC_NOP
|
||||
MEM_HEAP_BASE:: DU64 0;
|
||||
MEM_HEAP_LIMIT:: DU64 0;
|
||||
MEM_PAGE_SIZE:: DU64 0;
|
||||
MEM_MAPPED_SPACE:: DU64 0;
|
||||
MEM_2MEG_NUM:: DU64 0;
|
||||
MEM_1GIG_NUM:: DU64 0;
|
||||
MEM_512GIG_NUM:: DU64 0;
|
||||
MEM_PML2:: DU64 0;
|
||||
MEM_PML3:: DU64 0;
|
||||
MEM_PML4:: DU64 0;
|
||||
|
||||
#exe {
|
||||
StreamPrint(
|
||||
"SYS_MEM_INIT_FLAG:: DU8 %d;"
|
||||
"SYS_MEM_INIT_VAL:: DU8 %d;"
|
||||
"SYS_HEAP_INIT_FLAG:: DU8 %d;"
|
||||
"SYS_HEAP_INIT_VAL:: DU8 %d;"
|
||||
"SYS_VAR_INIT_FLAG:: DU8 %d;"
|
||||
"SYS_VAR_INIT_VAL:: DU8 %d;"
|
||||
"SYS_STAFF_MODE_FLAG:: DU8 %d;",
|
||||
kernel_cfg->opts[CFG_MEM_INIT], kernel_cfg->mem_init_val,
|
||||
kernel_cfg->opts[CFG_HEAP_INIT],kernel_cfg->heap_init_val,
|
||||
kernel_cfg->opts[CFG_VAR_INIT], kernel_cfg->var_init_val,
|
||||
kernel_cfg->opts[CFG_STAFF_MODE]);
|
||||
};
|
||||
SYS_HEAP_DBG_FLAG:: DU8 _CFG_HEAP_DBG;
|
||||
|
||||
ALIGN 8,0
|
||||
SYS_CTRL_ALT_FLAGS:: DU64 0;
|
||||
SYS_EXTERN_TABLE:: DU64 0;
|
||||
|
||||
SYS_CODE_BP:: DU64 0;
|
||||
SYS_DATA_BP:: DU64 0;
|
||||
|
||||
SYS_PROGRESSES::
|
||||
SYS_PROGRESS1:: DU64 0;
|
||||
SYS_PROGRESS1_MAX:: DU64 0;
|
||||
SYS_PROGRESS1_T0:: DU64 0;
|
||||
SYS_PROGRESS1_TF:: DU64 0;
|
||||
SYS_PROGRESS1_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
|
||||
SYS_PROGRESS2:: DU64 0;
|
||||
SYS_PROGRESS2_MAX:: DU64 0;
|
||||
SYS_PROGRESS2_T0:: DU64 0;
|
||||
SYS_PROGRESS2_TF:: DU64 0;
|
||||
SYS_PROGRESS2_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
|
||||
SYS_PROGRESS3:: DU64 0;
|
||||
SYS_PROGRESS3_MAX:: DU64 0;
|
||||
SYS_PROGRESS3_T0:: DU64 0;
|
||||
SYS_PROGRESS3_TF:: DU64 0;
|
||||
SYS_PROGRESS3_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
|
||||
SYS_PROGRESS4:: DU64 0;
|
||||
SYS_PROGRESS4_MAX:: DU64 0;
|
||||
SYS_PROGRESS4_T0:: DU64 0;
|
||||
SYS_PROGRESS4_TF:: DU64 0;
|
||||
SYS_PROGRESS4_DESC:: DU8 PROGRESS_DESC_LEN DUP(0);
|
||||
#assert $$-SYS_PROGRESSES==sizeof(CProgress)*4
|
||||
|
||||
SYS_FOCUS_TASK:: DU64 0;
|
||||
SYS_CPU_STRUCTS:: DU64 0;
|
||||
SYS_MP_CNT:: DU64 1;
|
||||
SYS_MP_CNT_INITIAL:: DU64 1;
|
||||
SYS_MP_CNT_LOCK:: DU64 1;
|
||||
|
||||
ALIGN DFT_CACHE_LINE_WIDTH,OC_NOP
|
||||
SYS_CACHE_LINE_WIDTH:: DU64 DFT_CACHE_LINE_WIDTH;
|
||||
DU8 DFT_CACHE_LINE_WIDTH-sizeof(CBinFile)-8 DUP(0);
|
||||
SYS_SEMAS:: DU8 SEMA_SEMAS_NUM*DFT_CACHE_LINE_WIDTH DUP(0);
|
||||
//************************************
|
||||
ALIGN 16,OC_NOP
|
||||
CORE0_32BIT_INIT:: //Entry point for $LK,"BootRAM",A="MN:BootRAM"$.
|
||||
PUSH U32 RFLAGG_START
|
||||
POPFD
|
||||
MOV EAX,SYS_START_CR0
|
||||
MOV_CR0_EAX
|
||||
|
||||
MOV AX,CGDT.boot_ds //LOAD DS SELECTOR
|
||||
MOV DS,AX
|
||||
BTS U32 [SYS_RUN_LEVEL],RLf_32BIT
|
||||
MOV ESI,U32 [SYS_BOOT_PATCH_TABLE_BASE]
|
||||
MOV EDI,U32 [MEM_BOOT_BASE]
|
||||
|
||||
MOV AX,CGDT.ds
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
MOV FS,AX
|
||||
MOV GS,AX
|
||||
MOV SS,AX
|
||||
MOV ESP,BOOT_RAM_LIMIT //Tmp Stk
|
||||
|
||||
//Patch abs addresses
|
||||
MOV ECX,U32 CPatchTableAbsAddr.abs_addres_cnt[ESI]
|
||||
LEA ESI,U32 CPatchTableAbsAddr.abs_addres[ESI]
|
||||
@@05: LODSD
|
||||
ADD EAX,EDI
|
||||
ADD U32 [EAX],EDI
|
||||
LOOP @@05
|
||||
|
||||
DU8 0xEA; //JMP CGDT.cs32:@@10
|
||||
DU32 @@10;
|
||||
DU16 CGDT.cs32;
|
||||
|
||||
@@10: BTS U32 [SYS_RUN_LEVEL],RLf_PATCHED
|
||||
|
||||
CALL SYS_FIND_PCIBIOS_SERVICE_DIR
|
||||
CALL SYS_FIND_PCI_SERVICES
|
||||
CALL SYS_INIT_PAGE_TABLES
|
||||
CALL SYS_INIT_16MEG_SYS_CODE_BP
|
||||
PUSH U32 0 //Return from next call will be 64-bit
|
||||
CALL SYS_ENTER_LONG_MODE
|
||||
|
||||
//We fall-thou to $LK,"KStart64",A="FL:::/Kernel/KStart64.HC,1"$, next.
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
asm {
|
||||
USE64
|
||||
BTS U32 [SYS_RUN_LEVEL],RLf_64BIT
|
||||
|
||||
FNINIT
|
||||
MOV RAX,SYS_FIXED_AREA+CSysFixedArea.init_fpu_mmx
|
||||
FXSAVE U64 [RAX]
|
||||
|
||||
//Init CPU0 Struct
|
||||
PUSH SYS_FIXED_AREA+CSysFixedArea.adam
|
||||
PUSH SYS_FIXED_AREA+CSysFixedArea.boot_cpu
|
||||
PUSH 0
|
||||
CALL &CPUStructInit
|
||||
CALL SET_GS_BASE
|
||||
|
||||
//Init Adam HeapCtrl
|
||||
MOV EDI,U32 SYS_FIXED_AREA+CSysFixedArea.adam_hc
|
||||
MOV EAX,U32 SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
|
||||
MOV U64 CHeapCtrl.bp[RDI],RAX
|
||||
MOV U32 CHeapCtrl.hc_signature[RDI],HEAP_CTRL_SIGNATURE_VAL
|
||||
|
||||
LEA RAX,U64 CHeapCtrl.next_um-CMemUsed.next[RDI]
|
||||
MOV U64 CHeapCtrl.next_um[RDI],RAX
|
||||
MOV U64 CHeapCtrl.last_um[RDI],RAX
|
||||
|
||||
MOV EAX,U32 SYS_FIXED_AREA+CSysFixedArea.adam
|
||||
MOV U64 CHeapCtrl.mem_task[RDI],RAX
|
||||
MOV U64 CTask.code_heap[RAX],RDI
|
||||
MOV U64 CTask.data_heap[RAX],RDI
|
||||
MOV U32 CTask.task_signature[RAX],TASK_SIGNATURE_VAL
|
||||
|
||||
BTS U32 [SYS_RUN_LEVEL],RLf_16MEG_ADAM_HEAP_CTRL
|
||||
|
||||
PUSH MEM_ADAM_STK
|
||||
PUSH U32 SYS_FIXED_AREA+CSysFixedArea.adam
|
||||
CALL &TaskInit
|
||||
CALL SET_FS_BASE
|
||||
MOV RSP,U64 CTask.rsp[RAX]
|
||||
|
||||
JMP I32 &KMain
|
||||
|
||||
//************************************
|
||||
USE32
|
||||
SYS_ENTER_LONG_MODE:: //Switch to long 64-bit mode
|
||||
MOV_EAX_CR4
|
||||
OR EAX,0xB0
|
||||
MOV_CR4_EAX
|
||||
|
||||
MOV EAX,[MEM_PML4]
|
||||
MOV_CR3_EAX
|
||||
|
||||
MOV ECX,IA32_EFER
|
||||
XOR EDX,EDX
|
||||
MOV EAX,IA32F_LME
|
||||
WRMSR
|
||||
|
||||
MOV_EAX_CR0
|
||||
BTS EAX,31 //Enable paging (required for 64-bit mode)
|
||||
MOV_CR0_EAX
|
||||
|
||||
DU8 0xEA; //JMP CGDT.cs64:@@05
|
||||
DU32 @@05;
|
||||
DU16 CGDT.cs64;
|
||||
USE64
|
||||
@@05: MOV AX,CGDT.ds
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
MOV SS,AX
|
||||
MOV FS,AX
|
||||
MOV GS,AX
|
||||
RET
|
||||
|
||||
//************************************
|
||||
SYS_RAM_REBOOT:: //This gets copied high. $LK,"SYS_RAM_REBOOT",A="FF:::/Adam/Opt/Boot/BootRAM.HC,SYS_RAM_REBOOT:2"$
|
||||
PUSH U32 CGDT.ds //stk seg
|
||||
PUSH U32 BOOT_RAM_LIMIT //stk
|
||||
PUSH U32 0 //flags
|
||||
PUSH U32 CGDT.cs32
|
||||
LEA RAX,[@@10]
|
||||
PUSH RAX
|
||||
IRET
|
||||
USE32
|
||||
@@10: WBINVD
|
||||
|
||||
//Disable paging
|
||||
MOV_EAX_CR0
|
||||
BTR EAX,31
|
||||
MOV_CR0_EAX
|
||||
|
||||
MOV ECX,IA32_EFER
|
||||
XOR EDX,EDX
|
||||
XOR EAX,EAX
|
||||
WRMSR
|
||||
|
||||
MOV EBX,BOOT_SRC_RAM
|
||||
MOV EAX,I32 CORE0_32BIT_INIT
|
||||
JMP EAX
|
||||
SYS_RAM_REBOOT_END::
|
||||
USE64
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
U0 Exit()
|
||||
{//Terminate own task.
|
||||
if (Fs==sys_focus_task && IsDbgMode) {
|
||||
LBts(&Fs->task_flags,TASKf_KILL_AFTER_DBG);
|
||||
G;
|
||||
} else {
|
||||
if (sys_staff_mode_flag)
|
||||
AdamLog("%p:%p:%p:%p:%p:%p\n",Caller(0),Caller(1),Caller(2),Caller(3),
|
||||
Caller(4),Caller(5),Caller(6),Caller(7));
|
||||
if (!Gs->num && !IsDbgMode)
|
||||
SingleUser(OFF);
|
||||
Fs->rflags=GetRFlags;
|
||||
Fs->rsp=GetRSP;
|
||||
Fs->rbp=GetRBP;
|
||||
Fs->rip=$$;
|
||||
CLI
|
||||
LBts(&Fs->task_flags,TASKf_KILL_TASK);
|
||||
TaskEndNow;
|
||||
}
|
||||
}
|
||||
|
||||
Bool TaskValidate(CTask *task)
|
||||
{//return TRUE if task looks valid.
|
||||
if (!(0<task<=I32_MAX) || task->addr!=task ||
|
||||
task->task_signature!=TASK_SIGNATURE_VAL)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
I64 BirthWait(CTask **_task,I64 task_num=-1)
|
||||
{//Wait for task valid and not task_num.
|
||||
while (!TaskValidate(*_task)||(*_task)->task_num==task_num)
|
||||
Yield;
|
||||
return (*_task)->task_num;
|
||||
}
|
||||
|
||||
U0 DeathWait(CTask **_task,Bool send_exit=FALSE)
|
||||
{//Wait for task death.
|
||||
if (send_exit && TaskValidate(*_task)) {
|
||||
TaskWait(*_task,TRUE);
|
||||
XTalk(*_task,"Exit;\n");
|
||||
}
|
||||
while (TaskValidate(*_task))
|
||||
Yield;
|
||||
}
|
||||
|
||||
Bool Kill(CTask *task,Bool wait=TRUE,Bool just_break=FALSE)
|
||||
{//Terminate other task.
|
||||
I64 i;
|
||||
if (TaskValidate(task)) {
|
||||
if (just_break) {
|
||||
if (task!=Fs)
|
||||
Break;
|
||||
else {//TODO wait
|
||||
sys_focus_task=task;
|
||||
LBts(sys_ctrl_alt_flags,CTRL_ALT_C);
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
if (task!=sys_winmgr_task) {
|
||||
for (i=0;i<mp_cnt;i++)
|
||||
if (task==cpu_structs[i].seth_task)
|
||||
return FALSE;
|
||||
LBts(&task->task_flags,TASKf_KILL_TASK);
|
||||
if (wait) {
|
||||
do Yield;
|
||||
while (TaskValidate(task) && Bt(&task->task_flags,TASKf_KILL_TASK));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool Suspend(CTask *task=NULL,Bool state=TRUE)
|
||||
{//Tell scheduler to skip task.
|
||||
Bool res;
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (TaskValidate(task))
|
||||
res=LBEqu(&task->task_flags,TASKf_SUSPENDED,state);
|
||||
else
|
||||
res=FALSE;
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool IsSuspended(CTask *task=NULL)
|
||||
{//You might use this in a DrawIt() or Animatetask().
|
||||
if (!task) task=Fs;
|
||||
if (TaskValidate(task))
|
||||
return Bt(&task->task_flags,TASKf_SUSPENDED);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CTaskStk *TaskStkNew(I64 stk_size,CTask *task)
|
||||
{
|
||||
CTaskStk *tmps=MAlloc(stk_size+offset(CTaskStk.stk_base),task);
|
||||
tmps->next_stk=NULL;
|
||||
tmps->stk_ptr=NULL;
|
||||
tmps->stk_size=MSize(tmps)-offset(CTaskStk.stk_base);
|
||||
return tmps;
|
||||
}
|
||||
|
||||
#exe {Option(OPTf_NO_REG_VAR,ON);};
|
||||
argpop I64 CallStkGrow(I64 stk_size_threshold,I64 stk_size,
|
||||
/*argpop*/I64 (*fp_addr)(...),...)
|
||||
{//Grow stk in call with any fixed num of args.
|
||||
//See $LK,"::/Demo/StkGrow.HC"$.
|
||||
CTaskStk *tmps,*tmps2,**_stk;
|
||||
I64 res,*rsp,*rsp2,*old_stk;
|
||||
|
||||
if (UnusedStk>=stk_size_threshold) {
|
||||
|
||||
asm {
|
||||
LEAVE
|
||||
POP RAX //return addr
|
||||
ADD RSP,16 //pop threshold,stk_size
|
||||
POP RBX // *f
|
||||
ADD RSP,8 //pop ARGC
|
||||
PUSH RAX
|
||||
JMP RBX //CALL fp_addr()
|
||||
};
|
||||
|
||||
} else {
|
||||
|
||||
tmps2=TaskStkNew(stk_size,Fs);
|
||||
tmps2->next_stk=tmps=Fs->stk;
|
||||
rsp2=(&tmps2->stk_base)(U8 *)+tmps2->stk_size;
|
||||
old_stk=rsp=&argv[argc];
|
||||
while (argc-->0)
|
||||
*--rsp2=*--rsp;
|
||||
_stk=&Fs->stk;
|
||||
tmps->stk_ptr=rsp=GetRSP;
|
||||
asm {
|
||||
IMPORT _FREE; //We are in a function, not at glbl scope.
|
||||
//The compiler treats these in isolation.
|
||||
|
||||
PUSHFD
|
||||
POP RDX //flags
|
||||
CLI
|
||||
MOV RBX,U64 &tmps2[RBP]
|
||||
MOV RAX,&_stk[RBP]
|
||||
MOV U64 [RAX],RBX //Fs->stk=tmps2
|
||||
MOV RSP,U64 &rsp2[RBP]
|
||||
PUSH RDX
|
||||
POPFD
|
||||
|
||||
CALL U64 &fp_addr[RBP]
|
||||
MOV U64 &res[RBP],RAX
|
||||
|
||||
PUSHFD
|
||||
POP RDX //flags
|
||||
CLI
|
||||
MOV RBX,U64 &tmps[RBP]
|
||||
MOV RAX,&_stk[RBP]
|
||||
MOV U64 [RAX],RBX //Fs->stk=tmps
|
||||
MOV RSP,U64 &rsp[RBP]
|
||||
PUSH RDX
|
||||
POPFD
|
||||
|
||||
PUSH U64 &tmps2[RBP]
|
||||
CALL _FREE
|
||||
|
||||
MOV RDX,U64 &old_stk[RBP]
|
||||
MOV RBX,U64 8[RBP]
|
||||
MOV RAX,U64 &res[RBP]
|
||||
MOV RBP,U64 [RBP]
|
||||
MOV RSP,RDX
|
||||
JMP RBX //return
|
||||
};
|
||||
}
|
||||
return 0; //dummy to get rid of warning
|
||||
}
|
||||
;
|
||||
#exe {Option(OPTf_NO_REG_VAR,OFF);};
|
||||
|
||||
I64 TaskInit(CTask *task,I64 stk_size)
|
||||
{//Returns Fs of task
|
||||
CTaskStk *tmps;
|
||||
|
||||
QueInit(&task->code_heap->next_mem_blk);
|
||||
task->code_heap->last_mergable=NULL;
|
||||
if (task->code_heap!=task->data_heap) {
|
||||
QueInit(&task->data_heap->next_mem_blk);
|
||||
task->data_heap->last_mergable=NULL;
|
||||
}
|
||||
|
||||
task->addr=task->next_task=task->last_task=
|
||||
task->next_input_filter_task=task->last_input_filter_task=
|
||||
task;
|
||||
|
||||
task->task_num=sys_num_spawned_tasks++;
|
||||
|
||||
task->rflags=RFLAGG_NORMAL;
|
||||
task->win_inhibit=WIG_TASK_DFT;
|
||||
|
||||
task->next_child_task=task->last_child_task=
|
||||
(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
|
||||
|
||||
JobCtrlInit(&task->srv_ctrl);
|
||||
QueInit(&task->next_cc);
|
||||
QueInit(&task->next_except);
|
||||
QueInit(&task->next_ctrl);
|
||||
QueInit(&task->next_ode);
|
||||
|
||||
task->fpu_mmx=MAllocAligned(sizeof(CFPU),0x10,task);
|
||||
MemCpy(task->fpu_mmx,
|
||||
SYS_FIXED_AREA+offset(CSysFixedArea.init_fpu_mmx),sizeof(CFPU));
|
||||
|
||||
task->hash_table=HashTableNew(TASK_HASH_TABLE_SIZE,task);
|
||||
|
||||
if (!stk_size)
|
||||
stk_size=MEM_DFT_STK;
|
||||
task->stk=tmps=TaskStkNew(stk_size,task);
|
||||
task->rsp=(&tmps->stk_base)(U8 *)+tmps->stk_size;
|
||||
|
||||
task->text_attr =WHITE<<4+BLUE;
|
||||
task->border_src =BDS_CONST;
|
||||
task->border_attr =DrvTextAttrGet(':');
|
||||
task->title_src =TTS_CONST;
|
||||
task->win_left =1;
|
||||
task->win_right =text.cols-2;
|
||||
task->win_top =13;
|
||||
task->win_bottom =text.rows-2;
|
||||
|
||||
if (blkdev.home_dir) {//Beware Adam $LK,"TaskInit",A="FF:::/Kernel/KStart64.HC,TaskInit"$. I guess ok until $LK,"ChgDsk",A="FF:::/Kernel/KEnd.HC,ChgDsk"$().
|
||||
task->cur_dv=blkdev.let_to_drv[*blkdev.home_dir-'A'];
|
||||
task->cur_dir=StrNew(blkdev.home_dir+2,task);
|
||||
} else
|
||||
task->cur_dir=StrNew("/Home",task);
|
||||
|
||||
Seed(,task);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
CTask *Spawn(U0 (*fp_start_addr)(U8 *data),U8 *data=NULL,U8 *task_name=NULL,
|
||||
I64 target_cpu=-1, //-1 for current CPU. See $LK,"multi-core",A="FI:::/Demo/MultiCore/LoadTest.HC"$.
|
||||
CTask *parent=NULL, //NULL means adam
|
||||
I64 stk_size=0, //0=default
|
||||
I64 flags=1<<JOBf_ADD_TO_QUE)
|
||||
{//Create task on core running at address.
|
||||
//Alloc $LK,"CTask",A="MN:CTask"$ structure from code heap so addr will be short.
|
||||
//Could be alloced off of data heap.
|
||||
CTask *task;
|
||||
if (target_cpu>=0)
|
||||
return SpawnQue(fp_start_addr,data,task_name,target_cpu,
|
||||
parent,stk_size,flags);
|
||||
task=CAlloc(sizeof(CTask),adam_task->code_heap);
|
||||
task->task_signature=TASK_SIGNATURE_VAL;
|
||||
if (!task_name) task_name="Unnamed Task";
|
||||
if (!parent) parent=Gs->seth_task;
|
||||
task->parent_task=parent;
|
||||
task->gs=parent->gs;
|
||||
if (sys_code_bp)
|
||||
task->code_heap=HeapCtrlInit(,task,sys_code_bp);
|
||||
if (sys_data_bp)
|
||||
task->data_heap=HeapCtrlInit(,task,sys_data_bp);
|
||||
else
|
||||
task->data_heap=task->code_heap;
|
||||
TaskInit(task,stk_size);
|
||||
task->rip=fp_start_addr;
|
||||
task->rsp(U8 *)-=8;
|
||||
*task->rsp=data;
|
||||
task->rsp(U8 *)-=8;
|
||||
*task->rsp=&Exit;
|
||||
task->hash_table->next=parent->hash_table;
|
||||
MemCpy(task->task_name,task_name,TASK_NAME_LEN);
|
||||
StrCpy(task->task_title,task->task_name);
|
||||
task->title_src=TTS_TASK_NAME;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (Bt(&flags,JOBf_ADD_TO_QUE)) {
|
||||
TaskQueInsChild(task);
|
||||
TaskQueIns(task);
|
||||
}
|
||||
POPFD
|
||||
return task;
|
||||
}
|
||||
|
||||
U0 TaskDerivedValsUpdate(CTask *task=NULL,Bool update_z_buf=TRUE)
|
||||
{//Those things calculated from other variables.
|
||||
if (!task) task=Fs;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
|
||||
PAUSE
|
||||
WinDerivedValsUpdate(task);
|
||||
if (fp_update_ctrls)
|
||||
(*fp_update_ctrls)(task);
|
||||
if (update_z_buf && Bt(&task->display_flags,DISPLAYf_SHOW))
|
||||
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
|
||||
LBtr(&task->task_flags,TASKf_TASK_LOCK);
|
||||
POPFD
|
||||
}
|
||||
|
||||
I64 ExeCmdLine(CCmpCtrl *cc)
|
||||
{//Terminal JIT-compile-and-execute loop for CCmpCtrl.
|
||||
I64 res=0,type,old_title_src=Fs->title_src;
|
||||
U8 *ptr,*ptr2,*ptr3,*machine_code,*old_task_title=StrNew(Fs->task_title);
|
||||
F64 t0;
|
||||
CDocEntry *doc_e;
|
||||
CDoc *doc;
|
||||
if (Fs->title_src!=TTS_LOCKED_CONST)
|
||||
Fs->title_src=TTS_CUR_LEX;
|
||||
while (cc->token &&
|
||||
(cc->token!='}' || !(cc->flags & CCF_EXE_BLK)) ) {
|
||||
if (Fs->title_src==TTS_CUR_LEX) {
|
||||
ptr2=&Fs->task_title;
|
||||
ptr3=ptr2+STR_LEN-1;
|
||||
if (cc->lex_include_stk->flags & LFSF_DOC) {
|
||||
doc_e=cc->lex_include_stk->cur_entry;
|
||||
doc=cc->lex_include_stk->doc;
|
||||
while (doc_e!=doc && ptr2<ptr3) {
|
||||
switch (doc_e->type_u8) {
|
||||
case DOCT_TEXT:
|
||||
ptr=doc_e->tag;
|
||||
while (*ptr && ptr2<ptr3)
|
||||
*ptr2++=*ptr++;
|
||||
break;
|
||||
case DOCT_TAB:
|
||||
case DOCT_NEW_LINE:
|
||||
*ptr2++='.';
|
||||
break;
|
||||
}
|
||||
doc_e=doc_e->next;
|
||||
}
|
||||
if (ptr2<ptr3) *ptr2=0;
|
||||
} else
|
||||
if ((ptr=cc->lex_include_stk->line_start) && *ptr)
|
||||
MemCpy(ptr2,ptr,STR_LEN-1);
|
||||
}
|
||||
cc->flags&=~CCF_HAS_MISC_DATA;
|
||||
machine_code=LexStmt2Bin(cc,&type);
|
||||
if (machine_code!=INVALID_PTR) {
|
||||
if (!(cc->flags&CCF_JUST_LOAD)) {
|
||||
t0=tS;
|
||||
res=Call(machine_code);
|
||||
Fs->answer=res;
|
||||
Fs->answer_type=type;
|
||||
Fs->answer_time=tS-t0;
|
||||
Fs->new_answer=TRUE;
|
||||
cc->pmt_line=0;
|
||||
}
|
||||
if (!(cc->flags&CCF_HAS_MISC_DATA))
|
||||
Free(machine_code);
|
||||
}
|
||||
}
|
||||
if (Fs->title_src!=TTS_LOCKED_CONST) {
|
||||
Fs->title_src=old_title_src;
|
||||
StrCpy(Fs->task_title,old_task_title);
|
||||
}
|
||||
Free(old_task_title);
|
||||
if (cc->flags&CCF_JUST_LOAD) {
|
||||
if (cc->error_cnt)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 SrvTaskCont()
|
||||
{//Act as server task in a loop handling commands.
|
||||
I64 old_flags=GetRFlags;
|
||||
FlushMsgs;
|
||||
while (TRUE) {
|
||||
CLI
|
||||
if (JobsHndlr(old_flags) && Fs->title_src==TTS_TASK_NAME)
|
||||
MemCpy(Fs->task_title,Fs->task_name,TASK_NAME_LEN);
|
||||
FlushMsgs;
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
|
||||
Yield;
|
||||
SetRFlags(old_flags);
|
||||
}
|
||||
}
|
||||
|
||||
U0 UserTaskCont()
|
||||
{//Terminal key-input-execute loop.
|
||||
CCmpCtrl *cc;
|
||||
CDoc *doc;
|
||||
Bool cont=TRUE;
|
||||
do {
|
||||
cc=CmpCtrlNew(,CCF_CMD_LINE|CCF_PMT|CCF_QUESTION_HELP);
|
||||
QueIns(cc,Fs->last_cc);
|
||||
try {
|
||||
Lex(cc);
|
||||
ExeCmdLine(cc);
|
||||
cont=Bt(&cc->flags,CCf_PMT);
|
||||
QueRem(cc);
|
||||
CmpCtrlDel(cc);
|
||||
} catch {
|
||||
if ((doc=Fs->put_doc) && doc->doc_signature==DOC_SIGNATURE_VAL)
|
||||
DocUnlock(doc);
|
||||
PutExcept;
|
||||
}
|
||||
} while (cont);
|
||||
}
|
||||
|
||||
U0 SrvCmdLine(I64 dummy=0)
|
||||
{
|
||||
no_warn dummy;
|
||||
Fs->win_inhibit=WIG_USER_TASK_DFT;
|
||||
CallExtStr("SrvStartUp");
|
||||
SrvTaskCont;
|
||||
}
|
||||
|
||||
U0 UserCmdLine(I64 dummy=0)
|
||||
{//A user task ends-up calling this.
|
||||
no_warn dummy;
|
||||
Fs->win_inhibit=WIG_USER_TASK_DFT;
|
||||
CallExtStr("UserStartUp");
|
||||
if (!LBts(&Fs->display_flags,DISPLAYf_SHOW))
|
||||
Dbg;
|
||||
UserTaskCont;
|
||||
}
|
||||
|
||||
CTask *User(U8 *fmt=NULL,...)
|
||||
{//Create user term task.
|
||||
U8 *st;
|
||||
CTask *task=Spawn(&UserCmdLine);
|
||||
TaskWait(task);
|
||||
if (fmt) {
|
||||
st=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
XTalk(task,st);
|
||||
Free(st);
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
U0 TaskDel(CTask *task)
|
||||
{//We delay freeing in case lingering ptr to reincarnated.
|
||||
HeapCtrlDel(task->code_heap);
|
||||
if (task->data_heap!=task->code_heap)
|
||||
HeapCtrlDel(task->data_heap);
|
||||
Free(task);
|
||||
}
|
||||
|
||||
I64 TaskEnd()
|
||||
{//Called with irq's off.
|
||||
CTask *task=Fs,*tmpt,*tmpt1;
|
||||
if (task==sys_task_being_scrn_updated) {
|
||||
LBts(&task->task_flags,TASKf_KILL_TASK);
|
||||
return task->next_task;
|
||||
}
|
||||
if (task->task_end_cb) {
|
||||
task->wake_jiffy=0;
|
||||
LBtr(&task->task_flags,TASKf_KILL_TASK);
|
||||
TaskRstAwaitingMsg(task);
|
||||
Suspend(task,FALSE);
|
||||
task->rip=task->task_end_cb;
|
||||
task->task_end_cb=NULL;
|
||||
return task;
|
||||
}
|
||||
if (task->parent_task && task->parent_task->popup_task==task) {
|
||||
task->parent_task->popup_task=NULL;
|
||||
Kill(task->parent_task,FALSE);
|
||||
return task->parent_task;
|
||||
}
|
||||
|
||||
DrvsRelease;
|
||||
BlkDevsRelease;
|
||||
tmpt1=(&task->next_child_task)(U8 *)-offset(CTask.next_sibling_task);
|
||||
tmpt=tmpt1->next_sibling_task;
|
||||
if (tmpt!=tmpt1) {
|
||||
do {
|
||||
LBts(&tmpt->task_flags,TASKf_KILL_TASK);
|
||||
tmpt=tmpt->next_sibling_task;
|
||||
} while (tmpt!=tmpt1);
|
||||
return task->next_task;
|
||||
}
|
||||
if (LBtr(&task->display_flags,DISPLAYf_SHOW))
|
||||
LBts(&sys_semas[SEMA_UPDATE_WIN_Z_BUF],0);
|
||||
|
||||
while (LBts(&task->task_flags,TASKf_TASK_LOCK))
|
||||
PAUSE
|
||||
while (LBts(&task->srv_ctrl.flags,JOBCf_LOCKED))
|
||||
PAUSE
|
||||
|
||||
JobQueDel(&task->srv_ctrl.next_waiting);
|
||||
JobQueDel(&task->srv_ctrl.next_done);
|
||||
|
||||
if (IsRaw)
|
||||
VGAFlush;
|
||||
|
||||
if (sys_focus_task==task) {
|
||||
if (!Gs->num)
|
||||
SingleUser(OFF);
|
||||
sys_focus_task=NULL;
|
||||
if (fp_set_std_palette)
|
||||
(*fp_set_std_palette)();
|
||||
}
|
||||
|
||||
//QueRem
|
||||
task->task_signature(I64)=0;
|
||||
|
||||
tmpt =task->next_input_filter_task;
|
||||
tmpt1=task->last_input_filter_task;
|
||||
tmpt1->next_input_filter_task=tmpt;
|
||||
tmpt ->last_input_filter_task=tmpt1;
|
||||
|
||||
tmpt =task->next_sibling_task;
|
||||
tmpt1=task->last_sibling_task;
|
||||
tmpt1->next_sibling_task=tmpt;
|
||||
tmpt ->last_sibling_task=tmpt1;
|
||||
|
||||
tmpt =task->next_task; //save to return
|
||||
TaskQueRem(task);
|
||||
|
||||
LBtr(&task->srv_ctrl.flags,JOBCf_LOCKED);
|
||||
LBtr(&task->task_flags,TASKf_TASK_LOCK);
|
||||
|
||||
task->wake_jiffy=cnts.jiffies+DYING_JIFFIES;
|
||||
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
|
||||
PAUSE
|
||||
QueIns(task,Gs->last_dying);
|
||||
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
|
||||
|
||||
return tmpt;
|
||||
}
|
||||
|
||||
U0 TaskKillDying()
|
||||
{//Delay freeing to prevent asking for trouble with quick reincarnations.
|
||||
//What if the user is doing this: $LK,"DoTreeCheckers",A="FF:::/Misc/OSTestSuite.HC,DoTreeCheckers"$.
|
||||
CTaskDying *task,*task1;
|
||||
if (Gs->kill_jiffy<cnts.jiffies) {//Avoid doing as many lock operations.
|
||||
while (LBts(&Gs->cpu_flags,CPUf_DYING_TASK_QUE))
|
||||
PAUSE
|
||||
task=Gs->next_dying;
|
||||
while (task!=&Gs->next_dying && task->wake_jiffy<cnts.jiffies) {
|
||||
task1=task->next;
|
||||
QueRem(task);
|
||||
TaskDel(task);
|
||||
task=task1;
|
||||
}
|
||||
LBtr(&Gs->cpu_flags,CPUf_DYING_TASK_QUE);
|
||||
Gs->kill_jiffy=cnts.jiffies+DYING_JIFFIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
asm {
|
||||
_MEMSET::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
REP_STOSB
|
||||
MOV RAX,RDI
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_MEMSET_U16::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
REP_STOSW
|
||||
MOV RAX,RDI
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_MEMSET_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
REP_STOSD
|
||||
MOV RAX,RDI
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_MEMSET_I64::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
REP_STOSQ
|
||||
MOV RAX,RDI
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_MEMCPY::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
REP_MOVSB
|
||||
MOV RAX,RDI
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_MEMCMP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
CLD
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDI,U64 SF_ARG2[RBP]
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
XOR RAX,RAX
|
||||
REPE_CMPSB
|
||||
JZ @@05
|
||||
MOV AL,1
|
||||
JA @@05
|
||||
MOV RAX,-1
|
||||
@@05: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_BEQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
XOR RAX,RAX
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
TEST RDX,RDX
|
||||
JZ @@5
|
||||
BTS U64 [RBX],RCX
|
||||
JMP @@10
|
||||
@@5: BTR U64 [RBX],RCX
|
||||
@@10: ADC AL,0
|
||||
POP RBP
|
||||
RET1 24
|
||||
_LBEQU::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
XOR RAX,RAX
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
TEST RDX,RDX
|
||||
JZ @@5
|
||||
LOCK
|
||||
BTS U64 [RBX],RCX
|
||||
JMP @@10
|
||||
@@5: LOCK
|
||||
BTR U64 [RBX],RCX
|
||||
@@10: ADC AL,0
|
||||
POP RBP
|
||||
RET1 24
|
||||
_CLAMP_I64::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
CMP RAX,RCX
|
||||
CMOVL RAX,RCX
|
||||
CMP RAX,RDX
|
||||
CMOVG RAX,RDX
|
||||
POP RBP
|
||||
RET1 24
|
||||
_CLAMP_U64::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
CMP RAX,RCX
|
||||
CMOVB RAX,RCX
|
||||
CMP RAX,RDX
|
||||
CMOVA RAX,RDX
|
||||
POP RBP
|
||||
RET1 24
|
||||
_CALL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
TEST RAX,RAX
|
||||
JZ @@05
|
||||
CALL RAX
|
||||
@@05: POP RBP
|
||||
RET1 8
|
||||
_BIT_FIELD_OR_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
SHR RBX,3
|
||||
ADD RBX,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
AND CL,7
|
||||
SHL RAX,CL
|
||||
OR U64 [RBX],RAX
|
||||
POP RBP
|
||||
RET1 24
|
||||
_BIT_FIELD_EXT_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RBX,U64 SF_ARG2[RBP]
|
||||
MOV RCX,RBX
|
||||
SHR RBX,3
|
||||
ADD RBX,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 [RBX]
|
||||
AND CL,7
|
||||
SHR RDX,CL
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
MOV RAX,1
|
||||
SHL RAX,CL
|
||||
DEC RAX
|
||||
AND RAX,RDX
|
||||
POP RBP
|
||||
RET1 24
|
||||
_XCHG_I64::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
XCHG U64 [RDX],RAX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_XCHG_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV EAX,U32 SF_ARG2[RBP]
|
||||
XCHG U32 [RDX],EAX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_XCHG_U16::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOVZX RAX,U16 SF_ARG2[RBP]
|
||||
XCHG U16 [RDX],AX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_XCHG_U8::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOVZX RAX,U8 SF_ARG2[RBP]
|
||||
XCHG U8 [RDX],AL
|
||||
POP RBP
|
||||
RET1 16
|
||||
|
||||
_LXCHG_I64::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RAX,U64 SF_ARG2[RBP]
|
||||
LOCK
|
||||
XCHG U64 [RDX],RAX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_LXCHG_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV EAX,U32 SF_ARG2[RBP]
|
||||
LOCK
|
||||
XCHG U32 [RDX],EAX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_LXCHG_U16::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOVZX RAX,U16 SF_ARG2[RBP]
|
||||
LOCK
|
||||
XCHG U16 [RDX],AX
|
||||
POP RBP
|
||||
RET1 16
|
||||
_LXCHG_U8::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOVZX RAX,U8 SF_ARG2[RBP]
|
||||
LOCK
|
||||
XCHG U8 [RDX],AL
|
||||
POP RBP
|
||||
RET1 16
|
||||
_REP_IN_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_INSD
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_REP_IN_U16::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_INSW
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_REP_IN_U8::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RDI
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_INSB
|
||||
POP RDI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_REP_OUT_U32::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_OUTSD
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_REP_OUT_U16::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_OUTSW
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_REP_OUT_U8::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
MOV RDX,U64 SF_ARG3[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP]
|
||||
REP_OUTSB
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_CPUID::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
CPUID
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV U64 [RSI],RAX
|
||||
MOV U64 8[RSI],RBX
|
||||
MOV U64 16[RSI],RCX
|
||||
MOV U64 24[RSI],RDX
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_CALL_IND:: //See $LK,"_LAST_FUN",A="MN:_LAST_FUN"$
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
LEA RSI,U64 SF_ARG3[RBP] //argv
|
||||
SHL RCX,3
|
||||
SUB RSP,RCX
|
||||
MOV RDI,RSP
|
||||
REP_MOVSB
|
||||
TEST RDX,RDX
|
||||
JZ @@05
|
||||
|
||||
CALL RDX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
|
||||
@@05: MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
SHL RCX,3
|
||||
ADD RSP,RCX
|
||||
XOR RAX,RAX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
_CALLEXTNUM::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RDX,U64 SF_ARG1[RBP]
|
||||
MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
LEA RSI,U64 SF_ARG3[RBP] //argv
|
||||
SHL RCX,3
|
||||
SUB RSP,RCX
|
||||
MOV RDI,RSP
|
||||
REP_MOVSB
|
||||
MOV RAX,U64 [SYS_EXTERN_TABLE]
|
||||
MOV RAX,U64 [RAX+RDX*8]
|
||||
TEST RAX,RAX
|
||||
JZ @@05
|
||||
|
||||
CALL RAX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
|
||||
@@05: MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
SHL RCX,3
|
||||
ADD RSP,RCX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
_CALLEXTSTR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
LEA RSI,U64 SF_ARG3[RBP] //argv
|
||||
SHL RCX,3
|
||||
SUB RSP,RCX
|
||||
MOV RDI,RSP
|
||||
REP_MOVSB
|
||||
MOV RSI,U64 SF_ARG1[RBP]
|
||||
|
||||
MOV RCX,1
|
||||
XOR RAX,RAX
|
||||
MOV RDI,U64 FS:CTask.hash_table[RAX]
|
||||
MOV RBX,HTT_FUN|HTT_EXPORT_SYS_SYM
|
||||
CALL SYS_HASH_FIND
|
||||
JZ @@15
|
||||
|
||||
TEST U32 CHash.type[RAX],HTT_FUN
|
||||
JZ @@05
|
||||
MOV RAX,U64 CHashFun.exe_addr[RAX]
|
||||
JMP @@10
|
||||
@@05: MOV RAX,U64 CHashExport.val[RAX]
|
||||
@@10: TEST RAX,RAX
|
||||
JZ @@15
|
||||
|
||||
CALL RAX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
|
||||
@@15: MOV RCX,U64 SF_ARG2[RBP] //argc
|
||||
SHL RCX,3
|
||||
ADD RSP,RCX
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET
|
||||
SET_GS_BASE::
|
||||
PUSH RAX
|
||||
PUSH RCX
|
||||
PUSH RDX
|
||||
MOV RDX,RAX
|
||||
SHR RDX,32
|
||||
MOV ECX,IA32_GS_BASE
|
||||
WRMSR
|
||||
POP RDX
|
||||
POP RCX
|
||||
POP RAX
|
||||
RET
|
||||
SET_FS_BASE::
|
||||
PUSH RAX
|
||||
PUSH RCX
|
||||
PUSH RDX
|
||||
MOV RDX,RAX
|
||||
SHR RDX,32
|
||||
MOV ECX,IA32_FS_BASE
|
||||
WRMSR
|
||||
POP RDX
|
||||
POP RCX
|
||||
POP RAX
|
||||
_RET::
|
||||
RET
|
||||
_SET_MSR::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,SF_ARG2[RBP]
|
||||
MOV RDX,RAX
|
||||
SHR RDX,32
|
||||
MOV RCX,SF_ARG1[RBP]
|
||||
WRMSR
|
||||
POP RBP
|
||||
RET1 16
|
||||
_SYS_HLT::
|
||||
CLI
|
||||
@@05: HLT
|
||||
JMP @@05
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,61 @@
|
||||
//Compile this by calling $LK,"BootHDIns",A="MN:BootHDIns"$().
|
||||
//Don't do it directly. See $LK,"Cmp(\"/Kernel/Kernel\")",A="FF:::/Adam/Opt/Boot/BootHDIns.HC,Cmp(\"/Kernel/Kernel\""$.
|
||||
|
||||
#exe {
|
||||
Cd(__DIR__);;
|
||||
Option(OPTf_WARN_PAREN,ON);
|
||||
Option(OPTf_WARN_DUP_TYPES,ON);
|
||||
#include "KCfg"
|
||||
CKCfg *kernel_cfg;
|
||||
kernel_cfg=KCfgNew;
|
||||
};
|
||||
|
||||
#include "KernelA.HH"
|
||||
#include "KStart16"
|
||||
#include "KStart32"
|
||||
#include "KStart64"
|
||||
#include "KMathA"
|
||||
#include "KUtils"
|
||||
#exe {Option(OPTf_KEEP_PRIVATE,ON);};
|
||||
#include "/Compiler/CompilerA.HH"
|
||||
#exe {Option(OPTf_EXTERNS_TO_IMPORTS,ON);};
|
||||
#include "/Compiler/CompilerB.HH"
|
||||
#exe {Option(OPTf_EXTERNS_TO_IMPORTS,OFF);};
|
||||
#exe {Option(OPTf_KEEP_PRIVATE,OFF);};
|
||||
#include "KernelB.HH"
|
||||
#include "KExts"
|
||||
#include "StrA"
|
||||
#include "KGlbls"
|
||||
#include "KMathB"
|
||||
#include "Sched"
|
||||
#include "Mem/MakeMem"
|
||||
#include "FontStd"
|
||||
#include "FontCyrillic"
|
||||
#include "StrB"
|
||||
#include "KHashA"
|
||||
#include "KInts"
|
||||
#include "KDataTypes"
|
||||
#include "Compress"
|
||||
#include "KHashB"
|
||||
#include "KLoad"
|
||||
#include "KDate"
|
||||
#include "StrPrint"
|
||||
#include "StrScan"
|
||||
#include "KDefine"
|
||||
#include "Display"
|
||||
#include "KMisc"
|
||||
#include "KDbg"
|
||||
#include "KeyDev"
|
||||
#include "KExcept"
|
||||
#include "SerialDev/MakeSerialDev"
|
||||
#include "QSort"
|
||||
#include "KTask"
|
||||
#include "Job"
|
||||
#include "PCIBIOS"
|
||||
#include "MultiProc"
|
||||
#include "EdLite"
|
||||
#include "BlkDev/MakeBlkDev"
|
||||
#include "FunSeg"
|
||||
#include "KEnd"
|
||||
|
||||
#exe {KCfgDel(kernel_cfg);};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,293 @@
|
||||
/* Kernel ASM symbols.
|
||||
$LK,"KernelB",A="FF:::/Kernel/Kernel.PRJ,KernelB"$ Kernel.PRJ
|
||||
$LK,"KernelB",A="FF:::/Compiler/Compiler.PRJ,KernelB"$ Compiler.PRJ
|
||||
$LK,"KernelB",A="FF:::/StartOS.HC,KernelB"$ StartOS.HC
|
||||
*/
|
||||
|
||||
#help_index "Bit"
|
||||
#help_file "::/Doc/Bit"
|
||||
public _intern IC_BSF I64 Bsf(
|
||||
I64 bit_field_val);//Scan fwd from lowest for 1st set. -1 if not found.
|
||||
public _intern IC_BSR I64 Bsr(
|
||||
I64 bit_field_val);//Scan rev from highest for 1st set. -1 if not found.
|
||||
public _intern IC_BT Bool Bt(
|
||||
U8 *bit_field,I64 bit); //Bit test.
|
||||
public _intern IC_BTC Bool Btc(
|
||||
U8 *bit_field,I64 bit); //Bit test and complement (same as xor with 1).
|
||||
public _intern IC_BTR Bool Btr(
|
||||
U8 *bit_field,I64 bit); //Bit test and reset to zero.
|
||||
public _intern IC_BTS Bool Bts(
|
||||
U8 *bit_field,I64 bit); //Bit test and set to one.
|
||||
public _intern IC_LBTC Bool LBtc(
|
||||
U8 *bit_field,I64 bit); //Locked bit test and complement (xor with 1).
|
||||
public _intern IC_LBTR Bool LBtr(
|
||||
U8 *bit_field,I64 bit); //Locked bit test and reset to zero.
|
||||
public _intern IC_LBTS Bool LBts(
|
||||
U8 *bit_field,I64 bit); //Locked bit test and set to one.
|
||||
public _extern _BEQU Bool BEqu(
|
||||
U8 *bit_field,I64 bit,Bool val);//Set bit equ to val.
|
||||
public _extern _BIT_FIELD_EXT_U32 U32 BFieldExtU32(
|
||||
U8 *bit_field,I64 bit,I64 size); //Extract U32 from bit field.
|
||||
public _extern _BIT_FIELD_OR_U32 U0 BFieldOrU32(
|
||||
U8 *bit_field,I64 bit,U32 pattern); //Or U32 into bit field.
|
||||
public _extern _LBEQU Bool LBEqu(
|
||||
U8 *bit_field,I64 bit,Bool val); //Locked Set bit equ to val.
|
||||
|
||||
#help_index "Boot"
|
||||
_extern MEM_BOOT_BASE U32 mem_boot_base;
|
||||
_extern SYS_BOOT_BLK U32 sys_boot_blk;
|
||||
_extern SYS_BOOT_PATCH_TABLE_BASE U32 sys_boot_patch_table_base;
|
||||
_extern SYS_BOOT_SRC U32 sys_boot_src;
|
||||
_extern SYS_RUN_LEVEL U32 sys_run_level;
|
||||
|
||||
#help_index "Call"
|
||||
public _extern _CALL I64 Call(U8 *machine_code); //Call addr with no args.
|
||||
public _extern _CALLEXTSTR I64 CallExtStr(
|
||||
/*argpop*/ U8 *name,...); //Search sym table for fun and pass it args.
|
||||
//Can have any fixed number of arguments.
|
||||
public _extern _CALL_IND I64 CallInd(
|
||||
/*argpop*/I64 (*fp_addr)(...),...); //Call with fixed number of args.
|
||||
|
||||
#help_index "Call/System Extern Num"
|
||||
public _extern SYS_EXTERN_TABLE /*argpop*/
|
||||
I64 (**ext)(...); //Array of fun ptrs. See $LK,"Extern Num Definitions",A="MN:EXT_EXTS_NUM"$
|
||||
public _extern _CALLEXTNUM
|
||||
I64 CallExtNum(I64 num,...); //Call ext num with fixed number of args.
|
||||
|
||||
#help_index "Char/Conversion"
|
||||
public _intern IC_TOUPPER I64 ToUpper(U8 ch); //Cvt char to upper case.
|
||||
|
||||
#help_index "Char/Operations"
|
||||
public _intern IC_STRLEN I64 StrLen(U8 *st); //String length.
|
||||
|
||||
#help_index "Data Types/Circular Queue"
|
||||
#help_file "::/Doc/Que"
|
||||
public _intern IC_QUE_INIT U0 QueInit(
|
||||
CQue *head); //Init queue head links.
|
||||
public _intern IC_QUE_INS U0 QueIns(
|
||||
CQue *entry,CQue *pred);//Insert item into que after predecessor.
|
||||
public _intern IC_QUE_INS_REV U0 QueInsRev(
|
||||
CQue *entry,CQue *succ);//Revd insert into que.
|
||||
//Ins item into que before successor.
|
||||
public _intern IC_QUE_REM U0 QueRem(CQue *entry); //Remove item from queue.
|
||||
|
||||
#help_index "I/O;Processor/IO Port"
|
||||
public _intern IC_IN_U16 U16 InU16(I64 port); //Read U16 from I/O port.
|
||||
public _intern IC_IN_U32 U32 InU32(I64 port); //Read U32 from I/O port.
|
||||
public _intern IC_IN_U8 U8 InU8(I64 port); //Read U8 from I/O port.
|
||||
public _intern IC_OUT_U16 U0 OutU16(I64 port, I64 val); //Write U16 to I/O port.
|
||||
public _intern IC_OUT_U32 U0 OutU32(I64 port, I64 val); //Write U32 to I/O port.
|
||||
public _intern IC_OUT_U8 U0 OutU8(I64 port, I64 val); //Write U8 to I/O port.
|
||||
public _extern _REP_IN_U16 U0 RepInU16(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated read U16 from I/O port.
|
||||
public _extern _REP_IN_U32 U0 RepInU32(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated read U32 from I/O port.
|
||||
public _extern _REP_IN_U8 U0 RepInU8(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated read U8 from I/O port.
|
||||
public _extern _REP_OUT_U16 U0 RepOutU16(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated write U16 to I/O port.
|
||||
public _extern _REP_OUT_U32 U0 RepOutU32(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated write U32 to I/O port.
|
||||
public _extern _REP_OUT_U8 U0 RepOutU8(
|
||||
U8 *buf,I64 cnt,I64 port); //Repeated write U8 to I/O port.
|
||||
|
||||
#help_index "Math"
|
||||
public _intern IC_ATAN F64 ATan(F64 d); //Arc Tan (Inverse Tan).
|
||||
public _intern IC_ABS F64 Abs(F64 d); //Absolute F64.
|
||||
public _intern IC_ABS_I64 I64 AbsI64(I64 i); //Absolute I64.
|
||||
public _intern IC_COS F64 Cos(F64 d); //Cosine.
|
||||
public _intern IC_MAX_I64 I64 MaxI64(I64 n1,I64 n2); //Max of two I64s.
|
||||
public _intern IC_MAX_U64 U64 MaxU64(U64 n1,U64 n2); //Max of two U64s.
|
||||
public _intern IC_MIN_I64 I64 MinI64(I64 n1,I64 n2); //Min of two I64s.
|
||||
public _intern IC_MIN_U64 U64 MinU64(U64 n1,U64 n2); //Min of two U64s.
|
||||
public _intern IC_MOD_U64 U64 ModU64(U64 *q,U64 d); //Div and return U64 Modulo.
|
||||
public _intern IC_SIGN_I64 I64 SignI64(I64 i); //Sign of I64: -1,0,1.
|
||||
public _intern IC_SIN F64 Sin(F64 d); //Sine.
|
||||
public _intern IC_SQR F64 Sqr(F64 d); //Square of F64.
|
||||
public _intern IC_SQR_I64 I64 SqrI64(I64 i); //Square of I64.
|
||||
public _intern IC_SQR_U64 U64 SqrU64(U64 i); //Square of U64.
|
||||
public _intern IC_SQRT F64 Sqrt(F64 d); //Square head of F64.
|
||||
public _intern IC_SWAP_I64 U0 SwapI64(
|
||||
I64 *n1,I64 *n2); //Swap two I64s. Not atomic.
|
||||
public _intern IC_SWAP_U16 U0 SwapU16(
|
||||
U16 *n1,U16 *n2); //Swap two U16s. Not atomic.
|
||||
public _intern IC_SWAP_U32 U0 SwapU32(
|
||||
U32 *n1,U32 *n2); //Swap two U32s. Not atomic.
|
||||
public _intern IC_SWAP_U8 U0 SwapU8(
|
||||
U8 *n1,U8 *n2); //Swap two U8s. Not atomic.
|
||||
public _intern IC_TAN F64 Tan(F64 d); //Tangent.
|
||||
public _intern IC_TO_BOOL Bool ToBool(I64 i); //Convert to Boolean.
|
||||
public _intern IC_TO_F64 F64 ToF64(I64 i); //Convert to F64.
|
||||
public _intern IC_TO_I64 I64 ToI64(F64 d); //Convert to I64. Truncates.
|
||||
public _extern _ARG F64 Arg(F64 x,F64 y); //Polar coordinate angle.
|
||||
public _extern _CEIL F64 Ceil(F64 d); //Ceiling of F64.
|
||||
public _extern _CLAMP_I64 I64 ClampI64(
|
||||
I64 num,I64 lo,I64 hi); //Clamp to I64 [] range.
|
||||
public _extern _CLAMP_U64 U64 ClampU64(
|
||||
U64 num,U64 lo,U64 hi); //Clamp to U64 [] range.
|
||||
public _extern _EXP F64 Exp(F64 d); //Exponential function.
|
||||
_extern _FCLEX U0 Fclex();
|
||||
_extern _FLDCW U0 Fldcw(U16 w);
|
||||
public _extern _FLOOR F64 Floor(F64 d); //Floor of F64.
|
||||
_extern _FSTCW U16 Fstcw();
|
||||
_extern _FSTSW U16 Fstsw();
|
||||
public _extern _LN F64 Ln(F64 d); //Logarithm.
|
||||
public _extern _LOG10 F64 Log10(F64 d); //Log base 10.
|
||||
public _extern _LOG2 F64 Log2(F64 d); //Log base 2.
|
||||
public _extern _POW F64 Pow(F64 base,F64 power); //F64 base to a power.
|
||||
public _extern _POW10 F64 Pow10(F64 d); //Ten to the dth power.
|
||||
public _extern _ROUND F64 Round(F64 d); //Round F64 to whole number.
|
||||
public _extern _SIGN F64 Sign(F64 d); //Sign of F64: -1,0,1
|
||||
public _extern _TRUNC F64 Trunc(F64 d); //Truncate F64.
|
||||
|
||||
#help_index "Math/CD3;Data Types/CD3"
|
||||
#help_file "::/Doc/D3"
|
||||
public _extern _D3_ADD CD3 *D3Add(CD3 *sum,CD3 *d1,CD3 *d2); //sum=d1+d2
|
||||
public _extern _D3_ADD_EQU CD3 *D3AddEqu(CD3 *sum,CD3 *d); //sum+=d
|
||||
public _extern _D3_COPY CD3 *D3Copy(CD3 *dst,CD3 *src); //dst=src
|
||||
public _extern _D3_CROSS CD3 *D3Cross(CD3 *prod,CD3 *d1,CD3 *d2); //prod=d1xd2
|
||||
public _extern _D3_DIST F64 D3Dist(CD3 *d1,CD3 *d2); //Distance
|
||||
public _extern _D3_DIST_SQR F64 D3DistSqr(CD3 *d1,CD3 *d2); //Distance Squared
|
||||
public _extern _D3_DIV CD3 *D3Div(CD3 *quot,CD3 *d,F64 s); //quot=d/s
|
||||
public _extern _D3_DIV_EQU CD3 *D3DivEqu(CD3 *quot,F64 s); //quot/=s
|
||||
public _extern _D3_DOT F64 D3Dot(CD3 *d1,CD3 *d2); //d1 dot d2
|
||||
public _extern _D3_EQU CD3 *D3Equ(CD3 *dst,F64 x,F64 y,F64 z); //dst=(x,y,z)
|
||||
public _extern _D3_MUL CD3 *D3Mul(CD3 *prod,F64 s,CD3 *d); //prod=s*d
|
||||
public _extern _D3_MUL_EQU CD3 *D3MulEqu(CD3 *prod,F64 s); //prod*=s
|
||||
public _extern _D3_NORM F64 D3Norm(CD3 *d); //Norm
|
||||
public _extern _D3_NORM_SQR F64 D3NormSqr(CD3 *d); //Norm Squared
|
||||
public _extern _D3_SUB CD3 *D3Sub(CD3 *diff,CD3 *d1,CD3 *d2); //diff=d1-d2
|
||||
public _extern _D3_SUB_EQU CD3 *D3SubEqu(CD3 *diff,CD3 *d); //diff-=d
|
||||
public _extern _D3_UNIT CD3 *D3Unit(CD3 *d); //To unit vect
|
||||
public _extern _D3_ZERO CD3 *D3Zero(CD3 *dst); //To zero
|
||||
|
||||
#help_index "Memory"
|
||||
public _extern _MEMCMP I64 MemCmp(
|
||||
U8 *ptr1,U8 *ptr2,I64 cnt); //Compare chunk of memory.
|
||||
public _extern _MEMCPY U8 *MemCpy(
|
||||
U8 *dst,U8 *src,I64 cnt); //Copy chunk of memory. Only goes fwd.
|
||||
public _extern _MEMSET U8 *MemSet(
|
||||
U8 *dst,I64 val,I64 cnt); //Set chunk of U8s to value.
|
||||
public _extern _MEMSET_I64 I64 *MemSetI64(
|
||||
I64 *dst,I64 val,I64 I64cnt); //Set chunk of I64s to value.
|
||||
public _extern _MEMSET_U16 U16 *MemSetU16(
|
||||
U16 *dst,I64 val,I64 U16cnt); //Set chunk of U16s to value.
|
||||
public _extern _MEMSET_U32 U32 *MemSetU32(
|
||||
U32 *dst,I64 val,I64 U32cnt); //Set chunk of U32s to value.
|
||||
public _extern _MEMSET U8 *MemSetU8(
|
||||
U8 *dst,I64 val,I64 U8cnt); //Set chunk of U8s to value.
|
||||
_extern SYS_HEAP_DBG_FLAG U8 sys_heap_dbg;
|
||||
_extern SYS_HEAP_INIT_FLAG U8 sys_heap_init_flag;
|
||||
_extern SYS_HEAP_INIT_VAL U8 sys_heap_init_val;
|
||||
_extern SYS_MEM_INIT_FLAG U8 sys_mem_init_flag;
|
||||
_extern SYS_MEM_INIT_VAL U8 sys_mem_init_val;
|
||||
_extern SYS_STAFF_MODE_FLAG U8 sys_staff_mode_flag;
|
||||
_extern SYS_VAR_INIT_FLAG U8 sys_var_init_flag;
|
||||
_extern SYS_VAR_INIT_VAL U8 sys_var_init_val;
|
||||
|
||||
#help_index "Memory/BlkPool"
|
||||
public _extern SYS_CODE_BP CBlkPool *sys_code_bp; //System's BlkPool for code.
|
||||
public _extern SYS_DATA_BP CBlkPool *sys_data_bp; //System's BlkPool for data.
|
||||
|
||||
#help_index "Memory/Info"
|
||||
_extern MEM_HEAP_BASE U8 *mem_heap_base;
|
||||
_extern MEM_HEAP_LIMIT U8 *mem_heap_limit;
|
||||
_extern MEM_MAPPED_SPACE U8 *mem_mapped_space;
|
||||
_extern MEM_PHYSICAL_SPACE U8 *mem_physical_space;
|
||||
|
||||
#help_index "Messages;Windows"
|
||||
public _extern SYS_FOCUS_TASK CTask *sys_focus_task; //Current focus task.
|
||||
|
||||
#help_index "Misc"
|
||||
public _extern SYS_COMPILE_TIME
|
||||
CDate sys_compile_time; //Date and time kernel was compiled.
|
||||
_extern SYS_CTRL_ALT_FLAGS
|
||||
I64 sys_ctrl_alt_flags[1]; //Should be semiphores?
|
||||
|
||||
#help_index "Misc/Progress Bars"
|
||||
public _extern SYS_PROGRESS1 I64 progress1; //Current progress 1.
|
||||
public _extern SYS_PROGRESS1_DESC
|
||||
U8 progress1_desc[PROGRESS_DESC_LEN]; //Progress 1 desc.
|
||||
public _extern SYS_PROGRESS1_MAX I64 progress1_max; //Progress 1 max.
|
||||
public _extern SYS_PROGRESS1_T0 F64 progress1_t0; //Progress 1 start time.
|
||||
public _extern SYS_PROGRESS1_TF F64 progress1_tf; //Progress 1 end time.
|
||||
public _extern SYS_PROGRESS2 I64 progress2; //Current progress 2.
|
||||
public _extern SYS_PROGRESS2_DESC
|
||||
U8 progress2_desc[PROGRESS_DESC_LEN]; //Progress 2 desc.
|
||||
public _extern SYS_PROGRESS2_MAX I64 progress2_max; //Progress 2 max.
|
||||
public _extern SYS_PROGRESS2_T0 F64 progress2_t0; //Progress 2 start time.
|
||||
public _extern SYS_PROGRESS2_TF F64 progress2_tf; //Progress 2 end time.
|
||||
public _extern SYS_PROGRESS3 I64 progress3; //Current progress 3.
|
||||
public _extern SYS_PROGRESS3_DESC
|
||||
U8 progress3_desc[PROGRESS_DESC_LEN]; //Progress 3 desc.
|
||||
public _extern SYS_PROGRESS3_MAX I64 progress3_max; //Progress 3 max.
|
||||
public _extern SYS_PROGRESS3_T0 F64 progress3_t0; //Progress 3 start time.
|
||||
public _extern SYS_PROGRESS3_TF F64 progress3_tf; //Progress 3 end time.
|
||||
public _extern SYS_PROGRESS4 I64 progress4; //Current progress 4.
|
||||
public _extern SYS_PROGRESS4_DESC
|
||||
U8 progress4_desc[PROGRESS_DESC_LEN]; //Progress 4 desc.
|
||||
public _extern SYS_PROGRESS4_MAX I64 progress4_max; //Progress 4 max.
|
||||
public _extern SYS_PROGRESS4_T0 F64 progress4_t0; //Progress 4 start time.
|
||||
public _extern SYS_PROGRESS4_TF F64 progress4_tf; //Progress 4 end time.
|
||||
public _extern SYS_PROGRESSES
|
||||
CProgress sys_progresses[PROGRESS_BARS_NUM]; //All progress bars.
|
||||
|
||||
#help_index "MultiCore"
|
||||
#help_file "::/Doc/MultiCore"
|
||||
public _extern SYS_CPU_STRUCTS CCPU *cpu_structs; //$LK,"Gs",A="MN:Gs"$ points to cur $LK,"CCPU",A="MN:CCPU"$.
|
||||
public _extern SYS_MP_CNT I64 mp_cnt; //Count of cores
|
||||
_extern SYS_MP_CNT_INITIAL I64 mp_cnt_initial; //only used during $LK,"Core0StartMP",A="MN:Core0StartMP"$
|
||||
_extern SYS_MP_CNT_LOCK I64 mp_cnt_lock;
|
||||
_extern SYS_SEMAS CSema sys_semas[SEMA_SEMAS_NUM];
|
||||
|
||||
#help_index "MultiCore;Processor"
|
||||
public _intern IC_GS CCPU *Gs(); //GS points to current $LK,"CCPU",A="MN:CCPU"$.
|
||||
|
||||
#help_index "PCI"
|
||||
public _extern SYS_PCI_BUSES U16 sys_pci_busses; //Number of PCI buses.
|
||||
|
||||
#help_index "Processor"
|
||||
public _intern IC_CARRY I64 Carry(); //See $LK,"::/Demo/Carry.HC"$
|
||||
public _intern IC_GET_RAX I64 GetRAX(); //Get RAX register value.
|
||||
public _intern IC_GET_RBP U8 *GetRBP(); //Get RBP register value.
|
||||
public _intern IC_GET_RFLAGS I64 GetRFlags(); //Get RFlags register value.
|
||||
public _intern IC_GET_RSP U8 *GetRSP(); //Get RSP register value.
|
||||
public _intern IC_POP I64 Pop(); //Pop value from stk.
|
||||
public _intern IC_PUSH U0 Push(I64 d); //Push value on stk.
|
||||
public _intern IC_SET_RAX U0 SetRAX(I64 d); //Set RAX register value.
|
||||
public _intern IC_SET_RBP U0 SetRBP(U8 *d); //Set RBP register value.
|
||||
public _intern IC_SET_RFLAGS U0 SetRFlags(I64 d); //Set RFlags register value.
|
||||
public _intern IC_SET_RSP U0 SetRSP(U8 *d); //Set RSP register value.
|
||||
public _extern _CPUID U0 CPUId(
|
||||
U32 rax,CRAXRBCRCXRDX *res); //Do CPUID inst.
|
||||
public _extern _LXCHG_I64 I64 LXchgI64(I64 *dst,I64 d); //Locked eXchange I64s.
|
||||
public _extern _LXCHG_U16 U16 LXchgU16(U16 *dst,U16 d); //Locked eXchange U16s.
|
||||
public _extern _LXCHG_U32 U32 LXchgU32(U32 *dst,U32 d); //Locked eXchange U32s.
|
||||
public _extern _LXCHG_U8 U8 LXchgU8(U8 *dst,U8 d); //Locked eXchange U8s.
|
||||
public _extern _SET_MSR U0 SetMSR(
|
||||
I64 model_specific_reg,I64 val); //Model Specific Reg See $LK,"MSRs",A="MN:IA32_EFER"$.
|
||||
public _extern _SYS_HLT U0 SysHlt(); //Loops doing HLT inst.
|
||||
public _extern _XCHG_I64 I64 XchgI64(I64 *dst,I64 d); //eXchange I64s.
|
||||
public _extern _XCHG_U16 U16 XchgU16(U16 *dst,U16 d); //eXchange U16s.
|
||||
public _extern _XCHG_U32 U32 XchgU32(U32 *dst,U32 d); //eXchange U32s.
|
||||
public _extern _XCHG_U8 U8 XchgU8(U8 *dst,U8 d); //eXchange U8s.
|
||||
_extern SYS_GDT CGDT sys_gdt;
|
||||
|
||||
#help_index "Processor/Cache;Memory/Cache"
|
||||
public _intern IC_CLFLUSH U0 CLFlush(U8 *a); //Flush cache line inst.
|
||||
public _extern SYS_CACHE_LINE_WIDTH
|
||||
I64 sys_cache_line_width; //CPU's Cache line width.
|
||||
|
||||
#help_index "Processor/Page Tables;Memory/Page Tables"
|
||||
public _intern IC_INVLPG
|
||||
U0 InvlPg(U8 *a); //Invalidate page at addr inst.
|
||||
public _extern MEM_PAGE_SIZE U64 mem_page_size;
|
||||
|
||||
#help_index "Task;Processor"
|
||||
public _intern IC_FS CTask *Fs(); //FS seg reg points to the current $LK,"CTask",A="MN:CTask"$.
|
||||
|
||||
#help_index "Time/CPU Cycles"
|
||||
#help_file "::/Doc/TimeCycles"
|
||||
public _intern IC_RDTSC I64 GetTSC(); //Get time stamp counter.
|
||||
|
||||
#help_index ""
|
||||
@@ -0,0 +1,764 @@
|
||||
#help_index "AutoComplete"
|
||||
#help_file "::/Doc/AutoComplete"
|
||||
public extern CAutoCompleteGlbls ac;
|
||||
|
||||
#help_index "AutoComplete/Dictionary"
|
||||
public extern CAutoCompleteDictGlbls acd;
|
||||
|
||||
#help_index "Bit"
|
||||
public extern I64 BCnt(I64 d);
|
||||
public extern U8 *rev_bits_table,*set_bits_table;
|
||||
|
||||
#help_index "Boot"
|
||||
#help_file "::/Doc/Boot"
|
||||
public extern U0 Reboot();
|
||||
|
||||
#help_index "Call"
|
||||
public argpop extern I64 CallStkGrow(I64 stk_size_threshold,I64 stk_size,
|
||||
/*argpop*/I64 (*fp_addr)(...),...);
|
||||
//fp_addr can have any fixed number of arguments.
|
||||
|
||||
#help_index "Call/FarCall32"
|
||||
public _extern _FAR_CALL32 Bool FarCall32(U0 (*fp_addr)());//Not reentrant
|
||||
public _extern C32_EAX U32 c32_eax;
|
||||
public _extern C32_EBX U32 c32_ebx;
|
||||
public _extern C32_ECX U32 c32_ecx;
|
||||
public _extern C32_EDI U32 c32_edi;
|
||||
public _extern C32_EDX U32 c32_edx;
|
||||
public _extern C32_EFLAGS U32 c32_eflags;
|
||||
public _extern C32_ESI U32 c32_esi;
|
||||
|
||||
#help_index "Char/BitMaps"
|
||||
public extern U32 char_bmp_alpha[16],char_bmp_alpha_numeric[16],
|
||||
char_bmp_alpha_numeric_no_at[16], char_bmp_word[16],
|
||||
char_bmp_dec_numeric[16], char_bmp_hex_numeric[16],
|
||||
char_bmp_white_space[16], char_bmp_non_eol_white_space[16],
|
||||
char_bmp_zero_cr_nl_cursor[16], char_bmp_zero_tab_cr_nl_cursor[16],
|
||||
char_bmp_zero_tab_cr_nl_cursor_dollar[16],
|
||||
char_bmp_macro[16], char_bmp_printable[16],
|
||||
char_bmp_displayable[16], char_bmp_safe_dollar[16],
|
||||
char_bmp_filename[16], char_bmp_non_eol[16];
|
||||
|
||||
#help_index "Char/Conversion"
|
||||
public extern U8 *Char2KeyName(I64 ch,Bool include_ctrl=TRUE);
|
||||
public extern I64 Char2ScanCode(I64 ch,I64 sc_flags=0);
|
||||
public extern U8 ScanCode2Char(I64 sc);
|
||||
public extern U8 *ScanCode2KeyName(I64 sc);
|
||||
public extern F64 Str2F64(U8 *src,U8 **_end_ptr=NULL);
|
||||
public extern I64 Str2I64(U8 *st,I64 radix=10,U8 **_end_ptr=NULL);
|
||||
public extern U8 *StrScan(U8 *src,U8 *fmt,...);
|
||||
|
||||
#help_index "Char/Conversion;Time/Date/CDate;Date/CDate"
|
||||
public extern CDate Str2Date(U8 *src);
|
||||
|
||||
#help_index "Char/Flags"
|
||||
public extern U0 ScanFlags(U8 *_dst_flags,U8 *lst,U8 *src);
|
||||
public extern U8 *StrPrintFlags(U8 *dst,U8 *lst,I64 flags);
|
||||
|
||||
#help_index "Char/Lists"
|
||||
public extern I64 LstMatch(U8 *needle, U8 *haystack_lst,I64 flags=0);
|
||||
public extern U8 *LstSub(I64 sub, U8 *lst);
|
||||
|
||||
#help_index "Char/Operations"
|
||||
public extern U8 *MStrPrint(U8 *fmt,...);
|
||||
public extern U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0);
|
||||
public extern U8 *ScaleIndent(U8 *src,F64 indent_scale_factor);
|
||||
public extern I64 Spaces2Tabs(U8 *dst,U8 *src);
|
||||
public _extern _STRCMP I64 StrCmp(U8 *st1,U8 *st2);
|
||||
public _extern _STRCPY U0 StrCpy(U8 *dst,U8 *src);
|
||||
public extern U8 *StrFind(U8 *needle,U8 *haystack_str,I64 flags=0);
|
||||
public extern U8 *StrFirstOcc(U8 *src,U8 *marker);
|
||||
public extern U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL);
|
||||
public _extern _STRICMP I64 StrICmp(U8 *st1,U8 *st2);
|
||||
public _extern _STRIMATCH U8 *StrIMatch(U8 *needle,U8 *haystack_str);
|
||||
public extern U8 *StrLastOcc(U8 *src,U8 *marker);
|
||||
public extern U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL);
|
||||
public _extern _STRMATCH U8 *StrMatch(U8 *needle,U8 *haystack_str);
|
||||
public _extern _STRNCMP I64 StrNCmp(U8 *st1,U8 *st2,I64 n);
|
||||
public _extern _STRNICMP I64 StrNICmp(U8 *st1,U8 *st2,I64 n);
|
||||
public extern I64 StrOcc(U8 *src, U8 ch);
|
||||
public extern U8 *StrPrint(U8 *dst,U8 *fmt,...);
|
||||
public extern U8 *StrPrintJoin(U8 *dst,U8 *fmt,I64 argc,I64 *argv);
|
||||
public extern U8 *StrUtil(U8 *_src,I64 flags);
|
||||
public extern U8 *Tabs2Spaces(U8 *src);
|
||||
public extern Bool WildMatch(U8 *test_str,U8 *wild_str);
|
||||
|
||||
#help_index "Char/Operations;Memory"
|
||||
public extern U8 *CatPrint(U8 *dst,U8 *fmt,...);
|
||||
|
||||
#help_index "Char/Operations;Memory/Adam Heap"
|
||||
public extern U8 *AStrNew(U8 *buf);
|
||||
|
||||
#help_index "Char/Operations;Memory/Heap"
|
||||
public extern U8 *StrNew(U8 *buf,CTask *mem_task=NULL);
|
||||
|
||||
#help_index "Char/Output;StdOut"
|
||||
public extern U0 GetOutOfDollar();
|
||||
public extern Bool IsSilent();
|
||||
public extern U0 Print(U8 *fmt,...);
|
||||
public extern U0 PrintErr(U8 *fmt,...);
|
||||
public extern U0 PrintWarn(U8 *fmt,...);
|
||||
public extern U0 PutChars(U64 ch);
|
||||
extern U0 PutHex(I64 num,I64 width);
|
||||
public extern U0 PutKey(I64 ch=0,I64 sc=0);
|
||||
extern U0 PutS(U8 *st); //Use $LK,"Print",A="MN:Print"$()
|
||||
public extern Bool Silent(Bool val=ON);
|
||||
extern U8 *StrPrintHex(U8 *dst,I64 num;I64 width);
|
||||
|
||||
#help_index "Char;Debugging/Raw Output;TextBase Layer/Char"
|
||||
public extern CTextGlbls text;
|
||||
|
||||
#help_index "Compiler/Lex"
|
||||
public extern U0 HashSrcFileSet(CCmpCtrl *cc,
|
||||
CHashSrcSym *h,I64 line_num_offset=0);
|
||||
|
||||
#help_index "Compiler;Cmd Line (Typically)"
|
||||
extern U8 *Load(U8 *filename,I64 ld_flags=0,
|
||||
CBinFile *bfh_addr=INVALID_PTR); //INVALID_PTR=don't care what load addr
|
||||
|
||||
#help_index "Compression"
|
||||
public extern CArcCompress *CompressBuf(U8 *src,I64 size,CTask *mem_task=NULL);
|
||||
public extern U8 *ExpandBuf(CArcCompress *arc,CTask *mem_task=NULL);
|
||||
|
||||
#help_index "Compression/Piece by Piece"
|
||||
public extern U0 ArcCompressBuf(CArcCtrl *c);
|
||||
public extern U0 ArcCtrlDel(CArcCtrl *c);
|
||||
public extern CArcCtrl *ArcCtrlNew(Bool expand,I64 compression_type=CT_8_BIT);
|
||||
public extern U0 ArcExpandBuf(CArcCtrl *c);
|
||||
public extern Bool ArcFinishCompression(CArcCtrl *c);
|
||||
|
||||
#help_index "Data Types/Circular Queue"
|
||||
public extern I64 QueCnt(CQue *head);
|
||||
public extern CQue *QueCopy(CQue *head,CTask *mem_task=NULL);
|
||||
public extern U0 QueDel(CQue *head,Bool querem=FALSE);
|
||||
public extern I64 QueSize(CQue *head);
|
||||
|
||||
#help_index "Data Types/Fifo"
|
||||
public extern I64 FifoI64Cnt(CFifoI64 *f);
|
||||
public extern U0 FifoI64Del(CFifoI64 *f);
|
||||
public extern U0 FifoI64Flush(CFifoI64 *f);
|
||||
public extern Bool FifoI64Ins(CFifoI64 *f,I64 q);
|
||||
public extern CFifoI64 *FifoI64New(I64 size,CTask *mem_task=NULL);
|
||||
public extern Bool FifoI64Peek(CFifoI64 *f,I64 *_q);
|
||||
public extern Bool FifoI64Rem(CFifoI64 *f,I64 *_q);
|
||||
public extern I64 FifoU8Cnt(CFifoU8 *f);
|
||||
public extern U0 FifoU8Del(CFifoU8 *f);
|
||||
public extern U0 FifoU8Flush(CFifoU8 *f);
|
||||
public extern Bool FifoU8Ins(CFifoU8 *f,U8 b);
|
||||
public extern CFifoU8 *FifoU8New(I64 size,CTask *mem_task=NULL);
|
||||
public extern Bool FifoU8Peek(CFifoU8 *f,U8 *_b);
|
||||
public extern Bool FifoU8Rem(CFifoU8 *f,U8 *_b);
|
||||
|
||||
#help_index "Data Types/Linked List"
|
||||
public extern I64 LinkedLstCnt(U8 **_lst);
|
||||
public extern U8 *LinkedLstCopy(U8 **_lst,CTask *mem_task=NULL);
|
||||
public extern U0 LinkedLstDel(U8 **_lst);
|
||||
public extern I64 LinkedLstSize(U8 **_lst);
|
||||
|
||||
#help_index "Data Types/Queue Vector"
|
||||
public extern U0 QueVectU8Del(CQueVectU8 *v);
|
||||
public extern I64 QueVectU8Get(CQueVectU8 *v,I64 idx);
|
||||
public extern CQueVectU8 *QueVectU8New(I64 min_idx=0);
|
||||
public extern U0 QueVectU8Put(CQueVectU8 *v,I64 idx,U8 ch);
|
||||
|
||||
#help_index "Debugging"
|
||||
public extern U8 *Caller(I64 num=1);
|
||||
public extern Bool ChkCodePtr(U8 *ptr);
|
||||
public extern Bool ChkOnStk(U8 *ptr,CTask *task=NULL);
|
||||
public extern Bool ChkPtr(U8 *ptr);
|
||||
public extern Bool IsSingleUser();
|
||||
public extern Bool IsSysDbg();
|
||||
public extern Bool SingleUser(Bool val);
|
||||
public extern Bool SysDbg(Bool val);
|
||||
public extern U8 *TaskCaller(CTask *task=NULL,
|
||||
I64 num=0,Bool saved_context=FALSE);
|
||||
public extern I64 UnusedStk(CTask *task=NULL);
|
||||
public extern CDbgGlbls dbg;
|
||||
|
||||
#help_index "Debugging/Debugger"
|
||||
public extern Bool B(U8 *addr,CTask *task=NULL,Bool live=TRUE) //Toggle bpt.
|
||||
public extern I64 B2(CTask *task=NULL,Bool live=TRUE);
|
||||
extern CBpt *BptFind(U8 *needle_addr,CTask *haystack_task=NULL,Bool rem=FALSE);
|
||||
public extern Bool BptR(U8 *addr,CTask *task=NULL,Bool live=TRUE,Bool rem=TRUE);
|
||||
public extern Bool BptS(U8 *addr,CTask *task=NULL,Bool live=TRUE);
|
||||
public extern Bool DbgMode(Bool val);
|
||||
public extern Bool E(U8 *addr,I64 cnt=512,I64 edf_dof_flags=0);
|
||||
public extern Bool EdLite(U8 *filename,I64 num=1,I64 edf_dof_flags=0);
|
||||
extern Bool EdLiteFileLine(U8 *fl_file_line,I64 edf_dof_flags=0);
|
||||
public extern Bool Fix(I64 edf_dof_flags=0);
|
||||
public extern U0 FixSet(U8 *filename,I64 line);
|
||||
public extern U0 G(U8 *ms=INVALID_PTR,CTask *task=NULL);
|
||||
public extern U0 G2(U8 *ms=INVALID_PTR,CTask *task=NULL);
|
||||
public extern Bool IsDbgMode();
|
||||
public extern U0 S(U8 *ms=INVALID_PTR,CTask *task=NULL);
|
||||
|
||||
#help_index "Debugging/Debugger;DolDoc/Cmd Line (Typically);"\
|
||||
"Cmd Line (Typically);Help System"
|
||||
public extern Bool Man(U8 *st,I64 edf_dof_flags=0);
|
||||
|
||||
#help_index "Debugging/Dump"
|
||||
public extern U0 CallerRep(U8 **rbp=NULL,CTask *task=NULL);
|
||||
public extern U0 D(U8 *addr,I64 cnt=0x80,Bool show_offset=TRUE);
|
||||
public extern U0 Da(U8 **addr,I64 cnt=0x10);
|
||||
public extern U0 Dm(U8 *addr,I64 cnt=0x80);
|
||||
public extern U0 Dr(CTask *task=NULL);
|
||||
public extern U0 StkRep(CTask *task=NULL);
|
||||
extern I64 *TaskRegAddr(CTask *task,I64 reg_num);
|
||||
|
||||
#help_index "Debugging/FunSeg"
|
||||
#help_file "::/Doc/DbgFunSeg"
|
||||
public extern Bool PutSrcLink(U8 *addr,I64 cnt=1,U8 *buf=NULL);
|
||||
public extern U8 *SrcEdLink(U8 *addr,I64 cnt=1,CTask *mem_task=NULL);
|
||||
public extern U8 *SrcFileName(U8 *addr,I64 cnt=1,CTask *mem_task=NULL);
|
||||
public extern I64 SrcLineNum(U8 *addr,I64 cnt=1);
|
||||
|
||||
#help_index "Debugging/FunSeg;Hash/System"
|
||||
public extern CHash *FunSegFind(U8 *addr,I64 *_offset);
|
||||
|
||||
#help_index "Debugging/Raw Output"
|
||||
public extern Bool IsRaw();
|
||||
public extern Bool Raw(Bool val);
|
||||
public extern U0 RawD(I64 mS=100,U8 *addr,I64 cnt=0x80);
|
||||
public extern U0 RawDm(I64 mS=100,U8 *addr,I64 cnt=0x80);
|
||||
extern U0 RawDr(CTask *task=NULL);
|
||||
public extern U0 RawPrint(I64 mS=100,U8 *fmt,...);
|
||||
public extern U0 RawPutChar(I64 ch);
|
||||
public extern U0 VGAFlush();
|
||||
|
||||
#help_index "Debugging;Debugging/Debugger"
|
||||
public extern U0 Dbg(U8 *msg=NULL,I64 msg_num=0);
|
||||
public extern U0 Panic(U8 *msg=NULL,I64 msg_num=0,Bool panic=TRUE);
|
||||
|
||||
#help_index "Define;Char/Define"
|
||||
#help_file "::/Doc/Define"
|
||||
public extern U8 *Define(U8 *dname);
|
||||
public extern CHashDefineStr *DefineLoad(U8 *dname,U8 *st);
|
||||
public extern U0 DefinePrint(U8 *dname,U8 *src,...);
|
||||
|
||||
#help_index "Define;Char/Define;Char/Lists"
|
||||
public extern I64 DefineCnt(U8 *dname);
|
||||
public extern CHashDefineStr *DefineLstLoad(U8 *dname,U8 *lst);
|
||||
public extern I64 DefineMatch(U8 *needle,U8 *haystack_lst_dname,I64 flags=0);
|
||||
public extern U8 *DefineSub(I64 sub,U8 *dname);
|
||||
|
||||
#help_index "Devices;Memory/Page Tables"
|
||||
public extern U8 *Mem32DevAlloc(I64 size,I64 alignment);
|
||||
public extern U0 Mem32DevFree(U8 *base);
|
||||
public extern U8 *Mem64DevAlloc(I64 *_pages1Gig);
|
||||
public extern U0 Mem64DevFree(U8 *base,I64 pages1Gig);
|
||||
public extern CDevGlbls dev;
|
||||
|
||||
#help_index "DolDoc/Clipboard"
|
||||
public extern CDoc *sys_clipboard_doc;
|
||||
|
||||
#help_index "DolDoc/Task;StdOut/Task"
|
||||
#help_file "::/Doc/StdOutTask"
|
||||
extern CDoc *(*fp_doc_put)(CTask *task=NULL);
|
||||
|
||||
#help_index "Exceptions"
|
||||
public extern U0 Break();
|
||||
public extern Bool BreakLock(CTask *task=NULL);
|
||||
public extern Bool BreakUnlock(CTask *task=NULL);
|
||||
public extern U0 PutExcept(Bool catch_it=TRUE);
|
||||
extern U0 SysTry(U8 *start_label,U8 *skip_label);
|
||||
extern U0 SysUntry();
|
||||
public extern U0 throw(I64 ch=0,Bool no_log=FALSE);
|
||||
|
||||
#help_index "File/CD DVD"
|
||||
public extern U0 DVDImageRead(U8 dvd_drv_let,U8 *out_name);
|
||||
public extern U0 DVDImageWrite(U8 dvd_drv_let,
|
||||
U8 *in_name=NULL,I64 media_type=MT_DVD);
|
||||
|
||||
#help_index "File/CFile"
|
||||
public extern U0 FClose(CFile *f);
|
||||
public extern CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0);
|
||||
public extern Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
|
||||
public extern I64 FSize(CFile *f);
|
||||
public extern Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1);
|
||||
|
||||
#help_index "File/Cmd Line (Typically);Cmd Line (Typically)"
|
||||
public extern Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE);
|
||||
public extern U0 ChgDsk(U8 drv_let=0);
|
||||
public extern I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
|
||||
Bool del_dir=FALSE,Bool print_msg=TRUE);
|
||||
public extern I64 Dir(U8 *files_find_mask="*",Bool full=FALSE);
|
||||
public extern Bool Drv(U8 drv_let);
|
||||
public extern U0 HomeSet(U8 *dirname);
|
||||
public extern Bool MkDir(U8 *filename,I64 entry_cnt=0);
|
||||
|
||||
#help_index "File/Cmd Line (Typically);Cmd Line (Typically);Install"
|
||||
public extern Bool DrvMap(U8 drv_let,CDrv *dv);
|
||||
|
||||
#help_index "File/FileNames"
|
||||
extern CDirEntry *Cd2DirEntry(CDirEntry *tmpde,U8 *abs_name);
|
||||
public extern U8 *ChgExt(U8 *filename,U8 *extension);
|
||||
public extern U8 *CurDir(CTask *task=NULL,CTask *mem_task=NULL);
|
||||
public extern U8 *DftExt(U8 *filename,U8 *extension);
|
||||
public extern U8 *DirFile(U8 *dirname,U8 *name=NULL,U8 *_extension=NULL);
|
||||
public extern U8 *DirNameAbs(U8 *dirname);
|
||||
public extern CBlkDev *DrvIsWritable(U8 drv_let=0,Bool except=FALSE);
|
||||
public extern U8 *FileExtDot(U8 *src);
|
||||
public extern U8 *FileExtRem(U8 *src,U8 *dst=NULL);
|
||||
public extern U8 *FileNameAbs(U8 *filename,I64 fuf_flags=0);
|
||||
public extern Bool FileNameChk(U8 *filename);
|
||||
public extern Bool FilesFindMatch(U8 *_test_name,
|
||||
U8 *files_find_mask,I64 fuf_flags=0);
|
||||
public extern Bool IsDir(U8 *dir_name);
|
||||
public extern Bool IsDotC(U8 *filename);
|
||||
public extern Bool IsDotZ(U8 *filename);
|
||||
public extern U0 PutDirLink(U8 *dirname,U8 *full_name=NULL);
|
||||
public extern U0 PutFileLink(U8 *filename,U8 *full_name=NULL,
|
||||
I64 line=0,Bool plain_text=FALSE);
|
||||
public extern U0 ToFileLine(U8 *_fl_file_line,U8 **_filename,I64 *_linenum);
|
||||
public extern U8 *ToggleZorNotZ(U8 *name);
|
||||
|
||||
#help_index "File/FileNames;Misc"
|
||||
public extern U8 *FileNameTmpTxt();
|
||||
|
||||
#help_index "File/Internal"
|
||||
public extern U0 DirContextDel(CDirContext *dirc,Bool restore=TRUE);
|
||||
public extern CDirContext *DirContextNew(U8 *mask,
|
||||
Bool make_mask=FALSE,Bool make_dirs=FALSE,Bool no_mask=FALSE);
|
||||
public extern Bool DirNew(CDrv *dv,U8 *cur_dir,
|
||||
CDirEntry *tmpde,Bool free_old_chain=TRUE);
|
||||
extern I64 FileAttr(U8 *name,I64 old_attr=0);
|
||||
|
||||
#help_index "File/Low Level"
|
||||
#help_file "::/Doc/FileLowLevel"
|
||||
public extern CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE);
|
||||
public extern U0 BlkDevDel(CBlkDev *bd);
|
||||
public extern Bool BlkDevLock(CBlkDev *bd);
|
||||
public extern CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type);
|
||||
public extern Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE);
|
||||
public extern U0 BlkDevsRelease();
|
||||
public extern I64 Cluster2Blk(CDrv *dv,I64 c);
|
||||
public extern I64 ClusterNumNext(CDrv *dv,I64 c,I64 cnt=1);
|
||||
public extern I64 ClustersAlloc(CDrv *dv,I64 c=0,
|
||||
I64 cnt=1,Bool contiguous=FALSE);
|
||||
extern Bool CopySingle(U8 *f1,U8 *f2); //Just one file
|
||||
public extern U8 Drv2Let(CDrv *dv=NULL);
|
||||
public extern CDrv *DrvChk(CDrv *dv,Bool except=TRUE);
|
||||
public extern U0 DrvDel(CDrv *dv);
|
||||
public extern Bool DrvLock(CDrv *dv);
|
||||
public extern CDrv *DrvMakeFreeSlot(U8 drv_let);
|
||||
public extern U8 *DrvModelNum(U8 drv_let=0);
|
||||
public extern U8 DrvNextFreeLet(U8 first_drv_let='C');
|
||||
public extern U8 *DrvSerialNum(U8 drv_let=0);
|
||||
public extern U8 DrvTextAttrGet(U8 drv_let=0);
|
||||
public extern Bool DrvUnlock(CDrv *dv,Bool rst=FALSE);
|
||||
public extern U0 DrvsRelease();
|
||||
extern U0 FAT32FreeClusters(CDrv *dv,I64 c);
|
||||
public extern CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE);
|
||||
public extern I64 Let2BlkDevType(U8 drv_let);
|
||||
public extern CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE);
|
||||
public extern U8 Let2Let(U8 drv_let=0);
|
||||
extern I64 Name2DirCluster(CDrv *dv,U8 *dirname);
|
||||
extern I64 Name2ParentDirCluster(CDrv *dv,U8 *dirname);
|
||||
public extern Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
|
||||
public extern I64 RClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt);
|
||||
public extern I64 RClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks);
|
||||
extern U0 RedSeaFreeClusters(CDrv *dv,I64 c,I64 cnt);
|
||||
public extern Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt);
|
||||
public extern I64 WClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt);
|
||||
public extern I64 WClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks);
|
||||
public extern U0 WZeroBlks(CDrv *dv,I64 blk,I64 cnt);
|
||||
|
||||
#help_index "File/Program Routines"
|
||||
public extern U0 DirEntryDel(CDirEntry *tmpde);
|
||||
public extern U0 DirEntryDel2(CDirEntry *tmpde);
|
||||
public extern U0 DirTreeDel(CDirEntry *tmpde);
|
||||
public extern U0 DirTreeDel2(CDirEntry *tmpde);
|
||||
public extern Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0);
|
||||
public extern U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL);
|
||||
public extern I64 FileWrite(U8 *filename,
|
||||
U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0);
|
||||
|
||||
#help_index "File/Program Routines;File/FileNames"
|
||||
public extern CDirEntry *FilesFind(U8 *files_find_mask,I64 fuf_flags=0);
|
||||
|
||||
#help_index "File/System"
|
||||
public extern CATARep *ATAIDDrvs(CATARep *head,CATARep **_ata_drv,
|
||||
CATARep **_atapi_drv);
|
||||
extern CBlkDev *ATAMount(U8 first_drv_let,
|
||||
I64 type,I64 base0,I64 base1,I64 unit);
|
||||
extern Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start);
|
||||
extern I64 ATAProbe(I64 base0,I64 base1,I64 unit);
|
||||
extern U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt);
|
||||
extern U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt);
|
||||
public extern I64 AutoMountIDE();
|
||||
extern I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
|
||||
Bool whole_drv,Bool make_free);
|
||||
extern U0 DskCacheInit(I64 size_in_U8s);
|
||||
public extern U0 DskCacheInvalidate(CDrv *dv);
|
||||
public extern CBlkDevGlbls blkdev;
|
||||
|
||||
#help_index "Graphics/Color"
|
||||
extern U0 (*fp_set_std_palette)();
|
||||
public extern U8 *Color2Str(U8 *buf,CColorROPU32 c);
|
||||
public extern CColorROPU16 Str2ColorU16(U8 *st);
|
||||
public extern CColorROPU32 Str2ColorU32(U8 *st);
|
||||
|
||||
#help_index "Hash"
|
||||
#help_file "::/Doc/Hash"
|
||||
public _extern _HASH_ADD U0 HashAdd(CHash *tmph,CHashTable *table);
|
||||
public _extern _HASH_ADD_AFTER U0 HashAddAfter(CHash *tmph,
|
||||
CHash *pred,CHashTable *table); //Add hash entry after entry.
|
||||
public _extern _HASH_BUCKET_FIND CHash **HashBucketFind(
|
||||
U8 *needle_str,CHashTable *haystack_table);
|
||||
public _extern _HASH_FIND CHash *HashFind(U8 *needle_str,
|
||||
CHashTable *haystack_table,I64 mask,I64 instance=1);
|
||||
public _extern _HASH_SINGLE_TABLE_FIND CHash *HashSingleTableFind(
|
||||
U8 *needle_str,CHashTable *haystack_table,I64 mask,I64 instance=1);
|
||||
public _extern _HASH_STR I64 HashStr(U8 *st);
|
||||
public extern CHashTable *HashTableNew(I64 size,CTask *mem_task=NULL);
|
||||
|
||||
#help_index "Hash/Frame"
|
||||
#help_file "::/Doc/Frame"
|
||||
public extern I64 FramePtr(U8 *name,CTask *task=NULL);
|
||||
public extern CHashGeneric *FramePtrAdd(U8 *name,I64 val=0,CTask *task=NULL);
|
||||
public extern I64 FramePtrDel(U8 *name,CTask *task=NULL);
|
||||
public extern I64 FramePtrSet(U8 *name,I64 val,CTask *task=NULL);
|
||||
|
||||
#help_index "Hash/System"
|
||||
public extern U0 HashDel(CHashSrcSym *tmph);
|
||||
public extern CHashGeneric *HashGenericAdd(U8 *name,
|
||||
I64 type,I64 val=0,I64 u8=0,I64 u16=0,CTask *task=NULL);
|
||||
public extern CHashGeneric *HashPublic(U8 *st,I64 mask,Bool val=TRUE);
|
||||
public _extern _HASH_REM_DEL Bool HashRemDel(CHash *tmph,CHashTable *table,
|
||||
I64 instance=1);//instance must match tmph's
|
||||
public extern U0 HashTableDel(CHashTable *table);
|
||||
public extern I64 HashTablePurge(CHashTable *table);
|
||||
public extern I64 HashTypeNum(CHash *tmph);
|
||||
public extern I64 HashVal(CHash *tmph);
|
||||
extern U0 SysSymImportsResolve(U8 *sptr,I64 ld_flags=0);
|
||||
|
||||
#help_index "Hash/System;Char/Lists"
|
||||
public extern I64 HashLstAdd(U8 *lst,I64 type,CHashTable *table);
|
||||
|
||||
#help_index "Hash/System;Define;Char/Define;Char/Lists"
|
||||
public extern I64 HashDefineLstAdd(U8 *dname,I64 type,CHashTable *table);
|
||||
|
||||
#help_index "Help System;Debugging/Debugger"
|
||||
public extern U0 Help();
|
||||
|
||||
#help_index "Info;File/Cmd Line (Typically);Cmd Line (Typically);Install"
|
||||
public extern U0 DrvRep();
|
||||
|
||||
#help_index "Install"
|
||||
#help_file "::/Doc/Install"
|
||||
extern CATARep *ATARepFind(CATARep *haystack_head,I64 needle_num);
|
||||
public extern Bool DrvEnable(U8 drv_let,Bool val);
|
||||
|
||||
#help_index "Install;File/Cmd Line (Typically);Cmd Line (Typically);"
|
||||
public extern U0 Fmt(U8 drv_let,Bool quick=TRUE,
|
||||
Bool confirm=TRUE,I64 type=FSt_FAT32);
|
||||
|
||||
#help_index "Install;Memory/BlkPool"
|
||||
public extern I64 Scale2Mem(I64 min,I64 max,I64 limit=2*1024*1024*1024);
|
||||
|
||||
#help_index "Job/Exe;Task/Job/Exe"
|
||||
public extern U0 AdamErr(U8 *fmt,...);
|
||||
public extern U0 AdamLog(U8 *fmt,...);
|
||||
public extern I64 ExeCmdLine(CCmpCtrl *cc);
|
||||
public extern U0 JobDel(CJob *tmpc);
|
||||
public extern I64 JobsHndlr(I64 run_flags,CTask *task=NULL);
|
||||
extern U0 SrvCmdLine();
|
||||
public extern U0 SrvTaskCont();
|
||||
public extern CJob *TaskExe(CTask *srv,CTask *master,U8 *data,I64 flags);
|
||||
public extern U0 TaskRstAwaitingMsg(CTask *task=NULL);
|
||||
public extern U0 UserTaskCont();
|
||||
|
||||
#help_index "Job/Exe;Task/Job/Exe;Compiler"
|
||||
public extern I64 Adam(U8 *fmt,...);
|
||||
public extern I64 PopUp(U8 *buf,CTask *parent=NULL,CTask **_pu_task=NULL);
|
||||
public extern I64 PopUpPrint(U8 *fmt,...);
|
||||
|
||||
#help_index "Job/Exe;Task/Job/Exe;MultiCore"
|
||||
public extern I64 JobResGet(CJob *rqst=NULL);
|
||||
public extern Bool JobResScan(CJob *rqst=NULL,I64 *_res=NULL);
|
||||
|
||||
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs"
|
||||
public extern CJob *TaskText(CTask *srv,CTask *master,U8 *data,I64 flags);
|
||||
|
||||
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs;InFile;StdIn/InFile"
|
||||
public extern U0 In(U8 *fmt,...);
|
||||
public extern U0 InFile(U8 *filename);
|
||||
public extern U0 InStr(U8 *fmt,...);
|
||||
public extern U0 XTalk(CTask *task,U8 *fmt,...);
|
||||
public extern U0 XTalkStr(CTask *task,U8 *fmt,...);
|
||||
public extern U0 XTalkStrWait(CTask *task,U8 *fmt,...);
|
||||
public extern U0 XTalkWait(CTask *task,U8 *fmt,...);
|
||||
|
||||
#help_index "Job/Text & Msgs;Task/Job/Text & Msgs;Messages"
|
||||
public extern U0 Msg(I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
|
||||
public extern U0 PostMsg(CTask *task,
|
||||
I64 msg_code,I64 arg1,I64 arg2,I64 flags=0);
|
||||
public extern U0 PostMsgWait(CTask *task,I64 msg_code,
|
||||
I64 arg1,I64 arg2,I64 flags=0);
|
||||
public extern CJob *TaskMsg(CTask *srv,CTask *master,
|
||||
I64 msg_code,I64 arg1,I64 arg2,I64 flags);
|
||||
|
||||
#help_index "Job;Task/Job"
|
||||
#help_file "::/Doc/Job"
|
||||
|
||||
#help_index "Keyboard Devices/System;Char/System"
|
||||
#help_file "::/Doc/KeyDev"
|
||||
public extern U0 CtrlAltCBSet(U8 ch,U0 (*fp_hndlr)(I64 sc),
|
||||
U8 *no_shift_desc=NULL,U8 *shift_desc=NULL,Bool in_irq=FALSE);
|
||||
public extern U0 KeyDescSet(U8 *fmt,...);
|
||||
public extern CKeyDevEntry *KeyDevAdd(Bool (*fp_put_key)(I64 ch,I64 sc),
|
||||
Bool (*fp_puts)(U8 *st),I64 priority,Bool key_descs=FALSE);
|
||||
public extern U0 KeyDevRem(CKeyDevEntry *tmpk);
|
||||
extern CKeyDevGlbls keydev;
|
||||
extern CJob sys_macro_head;
|
||||
extern CTask *sys_macro_task;
|
||||
|
||||
#help_index "Keyboard Devices;Char/Input;StdIn"
|
||||
extern U8 *(*fp_getstr2)(I64 flags=0); //GetStr $LK,"Flags",A="MN:GSF_SHIFT_ESC_EXIT"$
|
||||
public extern Bool AreYouSure();
|
||||
public extern I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,
|
||||
Bool raw_cursor=FALSE);
|
||||
public extern I64 GetKey(I64 *_scan_code=NULL,Bool echo=FALSE,
|
||||
Bool raw_cursor=FALSE);
|
||||
public extern I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE);
|
||||
public extern U8 *GetStr(U8 *msg=NULL,U8 *dft=NULL,I64 flags=0);
|
||||
extern U0 KbdInit();
|
||||
public extern I64 KbdMsEvtTime();
|
||||
extern U0 KbdMsHndlr(Bool poll_kbd,Bool poll_ms);
|
||||
extern U0 KbdMsInit();
|
||||
extern I64 KbdMsgsQue();
|
||||
public extern U0 KbdTypeMatic(U8 delay);
|
||||
extern Bool MsHardDrvrInstall();
|
||||
public extern I64 PressAKey();
|
||||
public extern I64 ScanChar();
|
||||
public extern Bool ScanKey(I64 *_ch=NULL,I64 *_scan_code=NULL,Bool echo=FALSE);
|
||||
public extern Bool YorN();
|
||||
public extern CKbdStateGlbls kbd;
|
||||
|
||||
#help_index "Math"
|
||||
public extern I64 CeilI64(I64 num,I64 to);
|
||||
public extern U64 CeilU64(U64 num,U64 to);
|
||||
public extern F64 Clamp(F64 d,F64 lo,F64 hi);
|
||||
public extern I64 FloorI64(I64 num,I64 to);
|
||||
public extern U64 FloorU64(U64 num,U64 to);
|
||||
public extern F64 Max(F64 n1,F64 n2);
|
||||
public extern F64 Min(F64 n1,F64 n2);
|
||||
public extern F64 Pow10I64(I64 i);
|
||||
public extern F64 Rand(); //With timestamp
|
||||
public extern I16 RandI16();
|
||||
public extern I32 RandI32();
|
||||
public extern I64 RandI64();
|
||||
public extern U16 RandU16();
|
||||
public extern U32 RandU32();
|
||||
public extern U64 RandU64();
|
||||
public extern I64 RoundI64(I64 num,I64 to);
|
||||
public extern I64 Seed(I64 seed=0,CTask *task=NULL);
|
||||
|
||||
#help_index "Memory/Adam Heap"
|
||||
public extern U8 *ACAlloc(I64 size);
|
||||
public extern U8 *AMAlloc(I64 size);
|
||||
public extern U8 *AMAllocIdent(U8 *src);
|
||||
|
||||
#help_index "Memory/BlkPool"
|
||||
public extern U0 BlkPoolAdd(CBlkPool *bp,CMemBlk *m,I64 pags);
|
||||
public extern U0 BlkPoolInit(CBlkPool *bp,I64 pags);
|
||||
public extern U8 *MemPagAlloc(I64 pags,CBlkPool *bp=NULL);
|
||||
public extern U0 MemPagFree(CMemBlk *m,CBlkPool *bp=NULL);
|
||||
|
||||
#help_index "Memory/Heap"
|
||||
public extern U8 *CAlloc(I64 size,CTask *mem_task=NULL);
|
||||
public extern U8 *CAllocAligned(I64 size,I64 alignment,
|
||||
CTask *mem_task=NULL,I64 misalignment=0);
|
||||
public _extern _FREE U0 Free(U8 *addr);
|
||||
public _extern _MALLOC U8 *MAlloc(I64 size,CTask *mem_task=NULL);
|
||||
public extern U8 *MAllocAligned(I64 size,I64 alignment,
|
||||
CTask *mem_task=NULL,I64 misalignment=0);
|
||||
public extern U8 *MAllocIdent(U8 *src,CTask *mem_task=NULL);
|
||||
public _extern _MHEAP_CTRL CHeapCtrl *MHeapCtrl(U8 *src);
|
||||
public _extern _MSIZE I64 MSize(U8 *src); //size of heap object
|
||||
public _extern _MSIZE2 I64 MSize2(U8 *src); //Internal size
|
||||
|
||||
#help_index "Memory/HeapCtrl"
|
||||
public extern U0 HeapCtrlDel(CHeapCtrl *hc);
|
||||
public extern CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,
|
||||
CTask *task=NULL,CBlkPool *bp);
|
||||
|
||||
#help_index "Memory/Page Tables"
|
||||
public extern I64 *MemPageTable(U8 *a);
|
||||
|
||||
#help_index "Messages"
|
||||
#help_file "::/Doc/Msgs"
|
||||
public extern I64 FlushMsgs(CTask *task=NULL);
|
||||
public extern I64 GetMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,
|
||||
I64 mask=~1,CTask *task=NULL);
|
||||
extern U0 InputFilterTask();
|
||||
public extern I64 ScanMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,
|
||||
I64 mask=~1,CTask *task=NULL);
|
||||
|
||||
#help_index "Misc"
|
||||
public extern I64 EndianI64(I64 d);
|
||||
public extern U16 EndianU16(U16 d);
|
||||
public extern U32 EndianU32(U32 d);
|
||||
public extern U0 QSort(U8 *base,I64 num, I64 width,
|
||||
I64 (*fp_compare)(U8 *e1,U8 *e2));
|
||||
public extern U0 QSortI64(I64 *base,I64 num,
|
||||
I64 (*fp_compare)(I64 e1,I64 e2));
|
||||
public extern F64 sys_os_version;
|
||||
|
||||
#help_index "Misc/Progress Bars"
|
||||
public extern U0 ProgressBarsRst(U8 *path=NULL);
|
||||
|
||||
#help_index "Mouse"
|
||||
#help_file "::/Doc/Mouse"
|
||||
public extern U0 GridInit();
|
||||
public extern U0 MsSet(I64 x=I64_MAX,I64 y=I64_MAX,I64 z=I64_MAX,
|
||||
I64 l=I64_MAX,I64 r=I64_MAX);
|
||||
public extern CMsStateGlbls ms;
|
||||
public extern CGridGlbls ms_grid;
|
||||
public extern CMsHardStateGlbls ms_hard;
|
||||
extern CMsHardStateGlbls ms_hard_last;
|
||||
extern CMsStateGlbls ms_last;
|
||||
|
||||
#help_index "Mouse/Ptr"
|
||||
extern U0 MsInit();
|
||||
extern U0 MsUpdate(I64 x,I64 y,I64 z,Bool l,Bool r);
|
||||
|
||||
#help_index "MultiCore"
|
||||
extern U0 Core0StartMP();
|
||||
extern U0 CoreAPSethTask();
|
||||
public extern U0 MPInt(U8 num,I64 cpu_num=1);
|
||||
public extern U0 MPIntAll(U8 num);
|
||||
public extern U0 MPNMInt();
|
||||
extern CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
|
||||
U8 *task_name=NULL,I64 target_cpu,
|
||||
CTask *parent=NULL, //NULL means adam
|
||||
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
|
||||
|
||||
#help_index "MultiCore;Boot"
|
||||
public extern U0 MPHalt();
|
||||
|
||||
#help_index "MultiCore;Job/Exe;Task/Job/Exe"
|
||||
public extern CJob *JobQue(I64 (*fp_addr)(U8 *data),U8 *data=NULL,
|
||||
I64 target_cpu=1,I64 flags=1<<JOBf_FREE_ON_COMPLETE,
|
||||
I64 job_code=JOBT_CALL,U8 *aux_str=NULL,I64 aux1=0,I64 aux2=0);
|
||||
|
||||
#help_index "PCI"
|
||||
public extern I64 PCIClassFind(I64 class_code,I64 n);
|
||||
public extern U16 PCIReadU16(I64 bus,I64 dev,I64 fun,I64 rg);
|
||||
public extern U32 PCIReadU32(I64 bus,I64 dev,I64 fun,I64 rg);
|
||||
public extern U8 PCIReadU8(I64 bus,I64 dev,I64 fun,I64 rg);
|
||||
public extern U0 PCIWriteU16(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
|
||||
public extern U0 PCIWriteU32(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
|
||||
public extern U0 PCIWriteU8(I64 bus,I64 dev,I64 fun,I64 rg,I64 val);
|
||||
public _extern SYS_PCIBIOS_SERVICE_DIR
|
||||
U32 sys_PCIBIOS_service_dir;//Far call routine in the BIOS
|
||||
public _extern SYS_PCI_SERVICES
|
||||
U32 sys_pci_services;//Far call routine in the BIOS
|
||||
|
||||
#help_index "PCI;Info;File/System;Devices"
|
||||
public extern I64 ATARep(Bool pmt=TRUE,
|
||||
Bool just_ide=FALSE,CATARep **_head=NULL);
|
||||
|
||||
#help_index "Processor"
|
||||
public extern U8 *IntEntryGet(I64 irq);
|
||||
public extern U8 *IntEntrySet(I64 irq,
|
||||
U0 (*fp_new_hndlr)(),I64 type=IDTET_IRQ,I64 dpl=0);
|
||||
|
||||
#help_index "Snd"
|
||||
#help_file "::/Doc/Snd"
|
||||
public extern U0 Beep(I8 ona=62,Bool busy=FALSE);
|
||||
public extern I8 Freq2Ona(F64 freq);
|
||||
public extern Bool IsMute();
|
||||
public extern Bool Mute(Bool val);
|
||||
public extern F64 Ona2Freq(I64 ona);
|
||||
public extern U0 Snd(I8 ona=ONA_REST);
|
||||
public extern U0 SndRst();
|
||||
public extern CSndGlbls snd;
|
||||
|
||||
#help_index "StdIn"
|
||||
#help_file "::/Doc/Streams"
|
||||
|
||||
#help_index "StdOut"
|
||||
#help_file "::/Doc/Streams"
|
||||
|
||||
#help_index "Task"
|
||||
public extern I64 BirthWait(CTask **_task,I64 task_num=-1);
|
||||
public extern U0 DeathWait(CTask **_task,Bool send_exit=FALSE);
|
||||
public extern U0 Exit();
|
||||
public extern Bool IsSuspended(CTask *task=NULL);
|
||||
public extern Bool Kill(CTask *task,Bool wait=TRUE,Bool just_break=FALSE);
|
||||
public extern Bool Suspend(CTask *task=NULL,Bool state=TRUE);
|
||||
_extern _TASK_CONTEXT_RESTORE U0 TaskContextRestore();
|
||||
_extern _TASK_END_NOW U0 TaskEndNow();
|
||||
extern U0 TaskKillDying();
|
||||
public extern U0 TaskQueIns(CTask *task,CTask *pred=NULL);
|
||||
public extern U0 TaskQueRem(CTask *task);
|
||||
public extern Bool TaskValidate(CTask *task);
|
||||
public extern U0 TaskWait(CTask *task=NULL,Bool cmd_line_pmt=FALSE);
|
||||
public extern CTask *User(U8 *fmt=NULL,...);
|
||||
public extern U0 UserCmdLine();
|
||||
public _extern _YIELD U0 Yield();
|
||||
public extern CTask *adam_task;
|
||||
public extern I64 sys_num_spawned_tasks;
|
||||
extern CTask *sys_winmgr_task,*sys_task_being_scrn_updated;
|
||||
|
||||
#help_index "Task/Delay;Time/CPU Cycles"
|
||||
public extern U0 Busy(I64 æS); //Loosely timed
|
||||
public extern U0 PortNop(); //On the order of 1uS
|
||||
extern I64 TimeStampFreqCal();
|
||||
|
||||
#help_index "Task/Delay;Time/Jiffies"
|
||||
public extern U0 Sleep(I64 mS);
|
||||
public extern U0 SleepUntil(I64 wake_jiffy);
|
||||
|
||||
#help_index "Task/Misc"
|
||||
extern U0 (*fp_update_ctrls)(CTask *task);
|
||||
public extern U0 TSSBusy(I64 tr,Bool val=OFF);
|
||||
public extern U0 TaskDerivedValsUpdate(CTask *task=NULL,Bool update_z_buf=TRUE);
|
||||
public extern U0 WinDerivedValsUpdate(CTask *task);
|
||||
|
||||
#help_index "Task;Job/Exe;Task/Job/Exe;MultiCore"
|
||||
public extern CTask *Spawn(U0 (*fp_addr)(U8 *data),U8 *data=NULL,
|
||||
U8 *task_name=NULL,I64 target_cpu=-1, //-1 means current CPU
|
||||
CTask *parent=NULL, //NULL means adam
|
||||
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE);
|
||||
|
||||
#help_index "Time/CPU Cycles;Time/HPET;Time/Jiffies"
|
||||
public extern CCntsGlbls cnts;
|
||||
|
||||
#help_index "Time/Date/CDate;Date/CDate"
|
||||
#help_file "::/Doc/TimeDate"
|
||||
extern U0 Date2ISO1(CISO1Date *dst,CDate cdt);
|
||||
public extern U0 Date2Struct(CDateStruct *_ds,CDate cdt);
|
||||
extern U8 *MPrintDate(CDate cdt);
|
||||
extern U8 *MPrintTime(CDate cdt);
|
||||
public extern CDate Now();
|
||||
public extern CDate Struct2Date(CDateStruct *_ds);
|
||||
public extern CDate local_time_offset;
|
||||
|
||||
#help_index "Time/Date;Date"
|
||||
#help_file "::/Doc/Date"
|
||||
public extern I64 DayOfWeek(I64 i);
|
||||
public extern I64 FirstDayOfMon(I64 i);
|
||||
public extern I64 FirstDayOfYear(I64 i);
|
||||
public extern I64 LastDayOfMon(I64 i);
|
||||
public extern I64 LastDayOfYear(I64 i);
|
||||
public extern I64 YearStartDate(I64 year);
|
||||
public extern U16 mon_start_days1[12];
|
||||
public extern U16 mon_start_days2[12];
|
||||
|
||||
#help_index "Time/HPET"
|
||||
#help_file "::/Doc/TimeHPET"
|
||||
public extern I64 HPET();
|
||||
|
||||
#help_index "Time/Jiffies"
|
||||
#help_file "::/Doc/TimeJiffy"
|
||||
public extern I64 SysTimerRead();//18.33333*65536Hz (SYS_TIMER_FREQ)
|
||||
|
||||
#help_index "Time/Seconds"
|
||||
public extern Bool Blink(F64 Hz=2.5);
|
||||
public extern F64 tS(); //From SysTimerFreq.
|
||||
|
||||
#help_index "Windows"
|
||||
public extern Bool WinInside(I64 x,I64 y,CTask *task=NULL,I64 border=0);
|
||||
#help_index ""
|
||||
@@ -0,0 +1,219 @@
|
||||
U0 PutKey(I64 ch=0,I64 sc=0)
|
||||
{//See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
|
||||
CKeyDevEntry *tmpk;
|
||||
if (ch||sc) {
|
||||
tmpk=keydev.put_key_head.next;
|
||||
if (!Bt(&Fs->display_flags,DISPLAYf_SILENT)) {
|
||||
if (kbd.scan_code & SCF_SCROLL && sys_focus_task==Fs)
|
||||
while (kbd.scan_code & SCF_SCROLL)
|
||||
Yield; //Wait on SCROLL LOCK Key
|
||||
while (tmpk!=&keydev.put_key_head) {
|
||||
if ((!(sc&SCF_KEY_DESC) || tmpk->flags & KDF_HAS_DESCS) &&
|
||||
(*tmpk->put_key)(ch,sc))
|
||||
break;
|
||||
tmpk=tmpk->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 PutChars(U64 ch)
|
||||
{//Output chars. Up to 8 chars in a single U64.
|
||||
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
|
||||
while (ch) {
|
||||
PutKey(ch&255,0);
|
||||
ch>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
U0 PutS(U8 *st)
|
||||
{//Use $LK,"Print",A="MN:Print"$(). See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
|
||||
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
|
||||
I64 ch;
|
||||
U8 *ptr;
|
||||
Bool cont=TRUE;
|
||||
if (!st) return;
|
||||
CKeyDevEntry *tmpk=keydev.put_key_head.next;
|
||||
if (!Bt(&Fs->display_flags,DISPLAYf_SILENT)) {
|
||||
if (kbd.scan_code & SCF_SCROLL && sys_focus_task==Fs)
|
||||
while (kbd.scan_code & SCF_SCROLL)
|
||||
Yield;
|
||||
while (cont && tmpk!=&keydev.put_key_head) {
|
||||
if (tmpk->put_s) {
|
||||
if ((*tmpk->put_s)(st))
|
||||
break;
|
||||
} else {
|
||||
ptr=st;
|
||||
while (ch=*ptr++)
|
||||
if ((*tmpk->put_key)(ch,0))
|
||||
cont=FALSE;
|
||||
}
|
||||
tmpk=tmpk->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 KeyDescSet(U8 *fmt,...)
|
||||
{//Call this from key hndlr to report desc in $LK,"KeyMap",A="MN:KeyMap"$().
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
StrCpy(keydev.desc,buf);
|
||||
keydev.hndlr=Caller;
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 KeyDevRem(CKeyDevEntry *tmpk)
|
||||
{//Remove StdOut hook and free.
|
||||
QueRem(tmpk);
|
||||
Free(tmpk);
|
||||
}
|
||||
|
||||
CKeyDevEntry *KeyDevAdd(Bool (*fp_put_key)(I64 ch,I64 sc),
|
||||
Bool (*fp_puts)(U8 *st),I64 priority,Bool key_descs=FALSE)
|
||||
{//Places hook in StdOut chain. See $LK,"Keyboard Devices",A="HI:Keyboard Devices/System"$.
|
||||
CKeyDevEntry *tmpk=keydev.put_key_head.last,
|
||||
*tmpk1=ACAlloc(sizeof(CKeyDevEntry));
|
||||
tmpk1->put_key=fp_put_key;
|
||||
tmpk1->put_s=fp_puts;
|
||||
tmpk1->priority=priority;
|
||||
if (key_descs)
|
||||
tmpk1->flags|=KDF_HAS_DESCS;
|
||||
while (tmpk->priority>priority)
|
||||
tmpk=tmpk->last;
|
||||
QueIns(tmpk1,tmpk);
|
||||
if (tmpk->priority==priority)
|
||||
KeyDevRem(tmpk);
|
||||
return tmpk1;
|
||||
}
|
||||
|
||||
Bool KDRawPutKey(I64 ch,I64)
|
||||
{
|
||||
if (IsRaw) {
|
||||
RawPutChar(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool KDRawPutS(U8 *st)
|
||||
{
|
||||
I64 ch;
|
||||
if (IsRaw) {
|
||||
while (ch=*st++)
|
||||
RawPutChar(ch);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool KDInputFilterPutKey(I64 ch,I64 scan_code)
|
||||
{
|
||||
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK)) {
|
||||
Msg(MSG_KEY_DOWN,ch,scan_code);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool KDInputFilterPutS(U8 *st)
|
||||
{
|
||||
I64 ch;
|
||||
if (Bt(&Fs->task_flags,TASKf_INPUT_FILTER_TASK)) {
|
||||
while (ch=*st++)
|
||||
Msg(MSG_KEY_DOWN,ch,0);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 CtrlAltDel(I64)
|
||||
{
|
||||
LBts(sys_ctrl_alt_flags,CTRL_ALT_DEL);
|
||||
}
|
||||
|
||||
U0 CtrlAltC(I64)
|
||||
{
|
||||
LBts(sys_ctrl_alt_flags,CTRL_ALT_C);
|
||||
}
|
||||
|
||||
U0 CtrlAltD(I64)
|
||||
{
|
||||
if (!IsDbgMode) {
|
||||
if (Fs==Gs->idle_task)
|
||||
BptS(sys_winmgr_task->rip,sys_winmgr_task);
|
||||
else
|
||||
BptS(*keydev.ctrl_alt_ret_addr);
|
||||
}
|
||||
}
|
||||
|
||||
U0 CtrlAltF(I64)
|
||||
{
|
||||
SwapI64(&text.font,&text.aux_font);
|
||||
}
|
||||
|
||||
U0 CtrlAltM(I64)
|
||||
{
|
||||
Mute(!IsMute);
|
||||
}
|
||||
|
||||
U0 CtrlAltN(I64)
|
||||
{
|
||||
LBts(sys_ctrl_alt_flags,CTRL_ALT_TAB);
|
||||
}
|
||||
|
||||
U0 CtrlAltT(I64)
|
||||
{
|
||||
User;
|
||||
}
|
||||
|
||||
U0 CtrlAltV(I64)
|
||||
{
|
||||
VGAFlush;
|
||||
}
|
||||
|
||||
U0 CtrlAltX(I64)
|
||||
{
|
||||
LBts(sys_ctrl_alt_flags,CTRL_ALT_X);
|
||||
}
|
||||
|
||||
U0 CtrlAltCBSet(U8 ch,U0 (*fp_hndlr)(I64 sc),
|
||||
U8 *no_shift_desc=NULL,U8 *shift_desc=NULL,Bool in_irq=FALSE)
|
||||
{//Set callback for <CTRL-ALT-letter>.
|
||||
ch=ToUpper(ch)-'A';
|
||||
if (ch<26) {
|
||||
keydev.fp_ctrl_alt_cbs[ch]=fp_hndlr;
|
||||
|
||||
Free(keydev.ctrl_alt_no_shift_descs[ch]);
|
||||
if (no_shift_desc)
|
||||
keydev.ctrl_alt_no_shift_descs[ch]=AStrNew(no_shift_desc);
|
||||
else
|
||||
keydev.ctrl_alt_no_shift_descs[ch]=NULL;
|
||||
|
||||
Free(keydev.ctrl_alt_shift_descs[ch]);
|
||||
if (shift_desc)
|
||||
keydev.ctrl_alt_shift_descs[ch]=AStrNew(shift_desc);
|
||||
else
|
||||
keydev.ctrl_alt_shift_descs[ch]=NULL;
|
||||
|
||||
BEqu(&keydev.ctrl_alt_in_irq_flags,ch,in_irq);
|
||||
}
|
||||
}
|
||||
|
||||
U0 KeyDevInit()
|
||||
{
|
||||
keydev.fp_ctrl_alt_cbs =CAlloc(26*sizeof(U8 *));
|
||||
keydev.ctrl_alt_no_shift_descs=CAlloc(26*sizeof(U8 *));
|
||||
keydev.ctrl_alt_shift_descs =CAlloc(26*sizeof(U8 *));
|
||||
keydev.ctrl_alt_in_irq_flags =0;
|
||||
MemSet(&keydev.put_key_head,0,sizeof(CKeyDevEntry));
|
||||
QueInit(&keydev.put_key_head);
|
||||
KeyDevAdd(&KDInputFilterPutKey,&KDInputFilterPutS,0x40000000,FALSE);
|
||||
KeyDevAdd(&KDRawPutKey,&KDRawPutS,0x60000000,FALSE);
|
||||
CtrlAltCBSet('C',&CtrlAltC,"Cmd /Break Execution",,TRUE);
|
||||
CtrlAltCBSet('D',&CtrlAltD,"Cmd /Enter Debugger",,TRUE);
|
||||
CtrlAltCBSet('F',&CtrlAltF,"Cmd /Toggle Aux Font");
|
||||
CtrlAltCBSet('M',&CtrlAltM,"Cmd /Toggle Mute");
|
||||
CtrlAltCBSet('N',&CtrlAltN,"Cmd /Next Focus Task",,TRUE);
|
||||
CtrlAltCBSet('T',&CtrlAltT,"Cmd /Terminal Window");
|
||||
CtrlAltCBSet('V',&CtrlAltV,"Cmd /VGA Flush",,TRUE);
|
||||
CtrlAltCBSet('X',&CtrlAltX,"Cmd /Kill Focused Task",,TRUE);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
U0 BlkPoolAdd(CBlkPool *bp,CMemBlk *m,I64 pags)
|
||||
{//Add mem to BlkPool.
|
||||
if (sys_mem_init_flag)
|
||||
MemSet(m,sys_mem_init_val,pags*MEM_PAG_SIZE);
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&bp->locked_flags,BPlf_LOCKED))
|
||||
PAUSE
|
||||
m->next=bp->mem_free_lst;
|
||||
m->pags=pags;
|
||||
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
|
||||
bp->alloced_u8s+=pags<<MEM_PAG_BITS;
|
||||
bp->mem_free_lst=m;
|
||||
LBtr(&bp->locked_flags,BPlf_LOCKED);
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 BlkPoolInit(CBlkPool *bp,I64 pags)
|
||||
{//Make mem chunk into a BlkPool.
|
||||
I64 num;
|
||||
CMemBlk *m;
|
||||
MemSet(bp,0,sizeof(CBlkPool));
|
||||
m=(bp(U8 *)+sizeof(CBlkPool)+MEM_PAG_SIZE-1)&~(MEM_PAG_SIZE-1);
|
||||
num=(bp(U8 *)+pags<<MEM_PAG_BITS-m(U8 *))>>MEM_PAG_BITS;
|
||||
bp->alloced_u8s=(pags-num)<<MEM_PAG_BITS; //Compensate before num added.
|
||||
BlkPoolAdd(bp,m,num);
|
||||
}
|
||||
|
||||
U0 BlkPoolsInit()
|
||||
{
|
||||
I64 i,total,lo,hi,code_heap_limit;
|
||||
CMemE820 *m20=MEM_E820;
|
||||
Bool first=TRUE;
|
||||
|
||||
total=BIOSTotalMem;
|
||||
|
||||
if (total<=0x80000000)
|
||||
code_heap_limit=total;
|
||||
else if (total<=0x100000000)
|
||||
code_heap_limit=total/4;
|
||||
else
|
||||
code_heap_limit=0x80000000;
|
||||
|
||||
i=code_heap_limit-SYS_16MEG_AREA_LIMIT; //See $LK,"RLf_16MEG_SYS_CODE_BP",A="FF:::/Kernel/Mem/PageTables.HC,RLf_16MEG_SYS_CODE_BP"$
|
||||
BlkPoolAdd(sys_code_bp,SYS_16MEG_AREA_LIMIT,i>>MEM_PAG_BITS);
|
||||
mem_heap_limit=i+SYS_16MEG_AREA_LIMIT-1;
|
||||
|
||||
if (code_heap_limit<total) {
|
||||
while (m20->type) {
|
||||
if (m20->type==1) {
|
||||
lo=m20->base;
|
||||
hi=m20->base+m20->len;
|
||||
if (lo<code_heap_limit) {
|
||||
if (hi>code_heap_limit)
|
||||
lo=code_heap_limit;
|
||||
else
|
||||
hi=lo; //cancel
|
||||
}
|
||||
if (code_heap_limit<=lo<hi) {
|
||||
if (first) {
|
||||
BlkPoolInit(lo,(hi-lo)>>MEM_PAG_BITS);
|
||||
sys_data_bp=lo;
|
||||
Fs->data_heap=HeapCtrlInit(,Fs,sys_data_bp);
|
||||
first=FALSE;
|
||||
} else
|
||||
BlkPoolAdd(sys_data_bp,lo,(hi-lo)>>MEM_PAG_BITS);
|
||||
}
|
||||
}
|
||||
m20++;
|
||||
}
|
||||
}
|
||||
LBts(&sys_run_level,RLf_FULL_HEAPS);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
CHeapCtrl *HeapCtrlInit(CHeapCtrl *hc=NULL,CTask *task=NULL,CBlkPool *bp)
|
||||
{//See $LK,"HeapLog",A="MN:HeapLog"$() for an example.
|
||||
//Duplicated for $LK,"Adam Task",A="FF:::/Kernel/KStart64.HC,CHeapCtrl.bp"$.
|
||||
if (!hc)
|
||||
hc=ACAlloc(sizeof(CHeapCtrl));
|
||||
hc->hc_signature=HEAP_CTRL_SIGNATURE_VAL;
|
||||
hc->mem_task=task;
|
||||
hc->bp=bp;
|
||||
QueInit(&hc->next_mem_blk);
|
||||
hc->last_mergable=NULL;
|
||||
hc->next_um=hc->last_um=(&hc->next_um)(U8 *)-offset(CMemUsed.next);
|
||||
return hc;
|
||||
}
|
||||
|
||||
U0 HeapCtrlDel(CHeapCtrl *hc)
|
||||
{//Free all blks alloced to a HeapCtrl.
|
||||
CMemBlk *m,*m1;
|
||||
if (hc) {
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&hc->locked_flags,HClf_LOCKED))
|
||||
PAUSE
|
||||
m=hc->next_mem_blk;
|
||||
while (m!=&hc->next_mem_blk) {
|
||||
m1=m->next;
|
||||
MemPagTaskFree(m,hc);
|
||||
m=m1;
|
||||
}
|
||||
LBtr(&hc->locked_flags,HClf_LOCKED);
|
||||
POPFD
|
||||
Free(hc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
asm {
|
||||
//************************************
|
||||
//See $LK,"::/Doc/Credits.DD"$.
|
||||
_MALLOC::
|
||||
// Throws 'OutMem'
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
|
||||
XOR RBX,RBX
|
||||
MOV RDX,U64 SF_ARG2[RBP]
|
||||
TEST RDX,RDX
|
||||
JNZ @@05
|
||||
MOV RDX,U64 FS:CTask.addr[RBX]
|
||||
@@05: CMP U32 CTask.task_signature[RDX],TASK_SIGNATURE_VAL
|
||||
|
||||
#assert CTask.task_signature==CHeapCtrl.hc_signature //location signature same
|
||||
|
||||
JNE @@10
|
||||
MOV RDX,U64 CTask.data_heap[RDX]
|
||||
@@10: CMP U32 CHeapCtrl.hc_signature[RDX],HEAP_CTRL_SIGNATURE_VAL
|
||||
JE @@15
|
||||
PUSH RDX
|
||||
CALL &SysBadMAlloc
|
||||
JMP I32 _SYS_HLT
|
||||
|
||||
@@15: MOV RAX,U64 SF_ARG1[RBP]
|
||||
PUSHFD
|
||||
ADD RAX,CMemUsed.start+7 //round-up to I64
|
||||
AND AL,0xF8
|
||||
#assert CMemUsed.start>=sizeof(CMemUnused)
|
||||
CMP RAX,CMemUsed.start
|
||||
JAE @@20
|
||||
MOV RAX,CMemUsed.start
|
||||
@@20:
|
||||
|
||||
CLI
|
||||
@@25: LOCK
|
||||
BTS U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
|
||||
PAUSE //don't know if this inst helps
|
||||
JC @@25
|
||||
|
||||
CMP RAX,MEM_HEAP_HASH_SIZE
|
||||
JAE @@30
|
||||
MOV RSI,U64 CHeapCtrl.heap_hash[RAX+RDX]
|
||||
TEST RSI,RSI
|
||||
JZ @@35
|
||||
MOV RCX,U64 CMemUnused.next[RSI]
|
||||
MOV U64 CHeapCtrl.heap_hash[RAX+RDX],RCX
|
||||
JMP I32 MALLOC_ALMOST_DONE
|
||||
|
||||
//Big allocation
|
||||
@@30: ADD RAX,sizeof(CMemBlk)+MEM_PAG_SIZE-1
|
||||
SHR RAX,MEM_PAG_BITS
|
||||
|
||||
PUSH RDX //preserve HeapCtrl
|
||||
PUSH RDX
|
||||
PUSH RAX
|
||||
CALL &MemPagTaskAlloc
|
||||
POP RDX
|
||||
TEST RAX,RAX
|
||||
JZ @@45 //Out of memory
|
||||
MOV RSI,RAX
|
||||
MOV EAX,U32 CMemBlk.pags[RSI]
|
||||
|
||||
SHL RAX,MEM_PAG_BITS
|
||||
SUB RAX,sizeof(CMemBlk)
|
||||
ADD RSI,sizeof(CMemBlk)
|
||||
JMP I32 MALLOC_ALMOST_DONE
|
||||
|
||||
//Little allocation, chunk-off piece from free lst chunks
|
||||
@@35: LEA RSI,U64 CHeapCtrl.malloc_free_lst-CMemUnused.next[RDX]
|
||||
|
||||
@@40: MOV RBX,RSI
|
||||
MOV RSI,U64 CMemUnused.next[RBX]
|
||||
TEST RSI,RSI
|
||||
JNZ I32 @@60
|
||||
PUSH RAX //-**** save byte size
|
||||
ADD RAX,16*MEM_PAG_SIZE-1
|
||||
SHR RAX,MEM_PAG_BITS
|
||||
|
||||
PUSH RDX //preserve HeapCtrl
|
||||
PUSH RDX
|
||||
PUSH RAX
|
||||
CALL &MemPagTaskAlloc
|
||||
POP RDX
|
||||
TEST RAX,RAX
|
||||
JNZ @@50
|
||||
|
||||
//Out of memory
|
||||
@@45: LOCK
|
||||
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
|
||||
POPFD
|
||||
PUSH TRUE
|
||||
MOV RAX,'OutMem'
|
||||
PUSH RAX
|
||||
CALL I32 &throw
|
||||
JMP I32 MALLOC_FINAL_EXIT //Never gets here, hopefully.
|
||||
|
||||
@@50: MOV RSI,RAX
|
||||
MOV EAX,U32 CMemBlk.pags[RSI]
|
||||
SHL RAX,MEM_PAG_BITS
|
||||
|
||||
//Can it be combined with last chunk? (Never Free these chunks.)
|
||||
MOV RDI,U64 CHeapCtrl.last_mergable[RDX]
|
||||
LEA RBX,U64 [RSI+RAX]
|
||||
CMP RDI,RBX
|
||||
JNE @@55
|
||||
|
||||
PUSH RAX
|
||||
MOV EAX,U32 CMemBlk.pags[RDI]
|
||||
ADD U32 CMemBlk.pags[RSI],EAX
|
||||
//QueRem
|
||||
MOV RAX,U64 CMemBlk.next[RDI]
|
||||
MOV RBX,U64 CMemBlk.last[RDI]
|
||||
MOV U64 CMemBlk.last[RAX],RBX
|
||||
MOV U64 CMemBlk.next[RBX],RAX
|
||||
POP RAX
|
||||
|
||||
@@55: MOV U64 CHeapCtrl.last_mergable[RDX],RSI
|
||||
LEA RSI,U64 sizeof(CMemBlk)[RSI]
|
||||
SUB RAX,sizeof(CMemBlk)
|
||||
LEA RBX,U64 CHeapCtrl.malloc_free_lst-CMemUnused.next[RDX]
|
||||
MOV RDI,U64 CMemUnused.next[RBX]
|
||||
MOV U64 CMemUnused.next[RSI],RDI
|
||||
MOV U64 CMemUnused.size[RSI],RAX
|
||||
MOV U64 CMemUnused.next[RBX],RSI
|
||||
POP RAX //+****
|
||||
JMP @@70
|
||||
@@60: CMP U64 CMemUnused.size[RSI],RAX
|
||||
JB I32 @@40
|
||||
JNE @@70
|
||||
|
||||
@@65: MOV RDI,U64 CMemUnused.next[RSI]
|
||||
MOV U64 CMemUnused.next[RBX],RDI
|
||||
JMP MALLOC_ALMOST_DONE
|
||||
|
||||
@@70: SUB U64 CMemUnused.size[RSI],RAX //UPDATE FREE ENTRY
|
||||
CMP U64 CMemUnused.size[RSI],sizeof(CMemUnused)
|
||||
JAE @@75 //take from top of block
|
||||
ADD U64 CMemUnused.size[RSI],RAX //doesn't fit, undo
|
||||
JMP I32 @@40
|
||||
|
||||
@@75: ADD RSI,U64 CMemUnused.size[RSI]
|
||||
|
||||
MALLOC_ALMOST_DONE:
|
||||
//RSI=res-CMemUsed.size
|
||||
//RAX=size+CMemUsed.size
|
||||
//RDX=HeapCtrl
|
||||
ADD U64 CHeapCtrl.used_u8s[RDX],RAX
|
||||
|
||||
#if _CFG_HEAP_DBG
|
||||
//QueIns
|
||||
MOV RDI,U64 CHeapCtrl.last_um[RDX]
|
||||
MOV U64 CMemUsed.next[RDI],RSI
|
||||
MOV U64 CHeapCtrl.last_um[RDX],RSI
|
||||
MOV U64 CMemUsed.last[RSI],RDI
|
||||
LEA RDI,U64 CHeapCtrl.next_um-CMemUsed.next[RDX]
|
||||
MOV U64 CMemUsed.next[RSI],RDI
|
||||
|
||||
//Caller1/Caller2
|
||||
PUSH RDX
|
||||
MOV RDX,U64 [MEM_HEAP_LIMIT]
|
||||
MOV RDI,U64 SF_RIP[RBP]
|
||||
CMP RDI,RDX
|
||||
JB @@80
|
||||
XOR RDI,RDI
|
||||
MOV U64 CMemUsed.caller1[RSI],RDI
|
||||
JMP @@90
|
||||
@@80: MOV U64 CMemUsed.caller1[RSI],RDI
|
||||
MOV RDI,U64 SF_RBP[RBP]
|
||||
CMP RDI,RDX
|
||||
JB @@85
|
||||
XOR RDI,RDI
|
||||
JMP @@90
|
||||
@@85: MOV RDI,U64 SF_RIP[RDI]
|
||||
CMP RDI,RDX
|
||||
JB @@90
|
||||
XOR RDI,RDI
|
||||
@@90: MOV U64 CMemUsed.caller2[RSI],RDI
|
||||
POP RDX
|
||||
|
||||
#endif
|
||||
LOCK
|
||||
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
|
||||
POPFD
|
||||
|
||||
MOV U64 CMemUsed.size[RSI],RAX
|
||||
MOV U64 CMemUsed.hc[RSI],RDX
|
||||
LEA RAX,U64 CMemUsed.start[RSI]
|
||||
|
||||
TEST U8 [SYS_SEMAS+SEMA_HEAPLOG_ACTIVE*DFT_CACHE_LINE_WIDTH],1
|
||||
JZ @@105
|
||||
PUSH RAX
|
||||
PUSH RAX
|
||||
MOV RAX,U64 [SYS_EXTERN_TABLE]
|
||||
MOV RAX,U64 EXT_HEAPLOG_MALLOC*8[RAX]
|
||||
TEST RAX,RAX
|
||||
JZ @@95
|
||||
CALL RAX
|
||||
JMP @@100
|
||||
@@95: ADD RSP,8
|
||||
@@100: POP RAX
|
||||
|
||||
@@105: TEST U8 [SYS_HEAP_INIT_FLAG],1
|
||||
JZ MALLOC_FINAL_EXIT
|
||||
|
||||
PUSH RAX
|
||||
MOV RCX,U64 CMemUsed.size-CMemUsed.start[RAX]
|
||||
SUB RCX,CMemUsed.start
|
||||
MOV RDI,RAX
|
||||
MOV AL,U8 [SYS_HEAP_INIT_VAL]
|
||||
REP_STOSB
|
||||
POP RAX
|
||||
|
||||
MALLOC_FINAL_EXIT:
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
//************************************
|
||||
_FREE::
|
||||
//Be aware of $LK,"heap_hash",A="FF:::/Kernel/Mem/MAllocFree.HC,heap_hash"$ in $LK,"MemPagTaskAlloc",A="MN:MemPagTaskAlloc"$().
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
|
||||
TEST U8 [SYS_SEMAS+SEMA_HEAPLOG_ACTIVE*DFT_CACHE_LINE_WIDTH],1
|
||||
JZ @@15
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
TEST RBX,RBX
|
||||
JZ @@05
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
TEST RAX,RAX
|
||||
JGE @@05 //Aligned alloced chunks have neg size
|
||||
ADD RBX,RAX
|
||||
@@05: PUSH RBX
|
||||
MOV RAX,U64 [SYS_EXTERN_TABLE]
|
||||
MOV RAX,U64 EXT_HEAPLOG_FREE*8[RAX]
|
||||
TEST RAX,RAX
|
||||
JZ @@10
|
||||
CALL RAX
|
||||
JMP @@15
|
||||
@@10: ADD RSP,8
|
||||
|
||||
@@15: MOV RSI,U64 SF_ARG1[RBP]
|
||||
TEST RSI,RSI
|
||||
|
||||
#if _CFG_HEAP_DBG
|
||||
JZ I32 FREE_DONE
|
||||
#else
|
||||
JZ FREE_DONE
|
||||
#endif
|
||||
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RSI]
|
||||
TEST RAX,RAX
|
||||
JGE @@20 //Aligned alloced chunks have neg size.
|
||||
//The neg size is offset to start of $LK,"CMemUsed",A="MN:CMemUsed"$ struct.
|
||||
ADD RSI,RAX
|
||||
|
||||
@@20: PUSHFD
|
||||
SUB RSI,CMemUsed.start
|
||||
MOV RDX,U64 CMemUsed.hc[RSI]
|
||||
CMP U32 CHeapCtrl.hc_signature[RDX],HEAP_CTRL_SIGNATURE_VAL
|
||||
JE @@25
|
||||
ADD RSI,CMemUsed.start
|
||||
PUSH RSI
|
||||
CALL &SysBadFree
|
||||
JMP I32 _SYS_HLT
|
||||
|
||||
@@25: MOV RAX,U64 CMemUsed.size[RSI]
|
||||
SUB U64 CHeapCtrl.used_u8s[RDX],RAX
|
||||
CLI
|
||||
@@30: LOCK
|
||||
BTS U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
|
||||
PAUSE
|
||||
JC @@30
|
||||
#if _CFG_HEAP_DBG
|
||||
//QueRem
|
||||
MOV RDX,U64 CMemUsed.next[RSI]
|
||||
MOV RDI,U64 CMemUsed.last[RSI]
|
||||
MOV U64 CMemUsed.last[RDX],RDI
|
||||
MOV U64 CMemUsed.next[RDI],RDX
|
||||
|
||||
//Caller1/Caller2
|
||||
MOV RDX,U64 [MEM_HEAP_LIMIT]
|
||||
MOV RDI,U64 SF_RIP[RBP]
|
||||
CMP RDI,RDX
|
||||
JB @@35
|
||||
XOR RDI,RDI
|
||||
MOV U64 CMemUnused.caller1[RSI],RDI
|
||||
JMP @@45
|
||||
@@35: MOV U64 CMemUnused.caller1[RSI],RDI
|
||||
MOV RDI,U64 SF_RBP[RBP]
|
||||
CMP RDI,RDX
|
||||
JB @@40
|
||||
XOR RDI,RDI
|
||||
JMP @@45
|
||||
@@40: MOV RDI,U64 SF_RIP[RDI]
|
||||
CMP RDI,RDX
|
||||
JB @@45
|
||||
XOR RDI,RDI
|
||||
@@45: MOV U64 CMemUnused.caller2[RSI],RDI
|
||||
|
||||
MOV RDX,U64 CMemUsed.hc[RSI]
|
||||
#endif
|
||||
CMP RAX,MEM_HEAP_HASH_SIZE
|
||||
JAE @@50
|
||||
|
||||
#assert CMemUnused.size==CMemUsed.size
|
||||
// MOV U64 CMemUnused.size[RSI],RAX
|
||||
|
||||
MOV RBX,U64 CHeapCtrl.heap_hash[RAX+RDX]
|
||||
MOV U64 CMemUnused.next[RSI],RBX
|
||||
MOV U64 CHeapCtrl.heap_hash[RAX+RDX],RSI
|
||||
JMP @@55
|
||||
|
||||
@@50: SUB RSI,sizeof(CMemBlk)
|
||||
PUSH RDX
|
||||
PUSH RDX
|
||||
PUSH RSI
|
||||
CALL &MemPagTaskFree
|
||||
POP RDX
|
||||
|
||||
@@55: LOCK
|
||||
BTR U32 CHeapCtrl.locked_flags[RDX],HClf_LOCKED
|
||||
POPFD
|
||||
FREE_DONE:
|
||||
POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_MSIZE::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
XOR RAX,RAX
|
||||
TEST RBX,RBX
|
||||
JZ @@10
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
TEST RAX,RAX
|
||||
JGE @@05 //Aligned alloced chunks have neg size
|
||||
ADD RBX,RAX
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
@@05: SUB RAX,CMemUsed.start
|
||||
@@10: POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_MSIZE2::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
XOR RAX,RAX
|
||||
TEST RBX,RBX
|
||||
JZ @@10
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
TEST RAX,RAX
|
||||
JGE @@05 //Aligned alloced chunks have neg size
|
||||
ADD RBX,RAX
|
||||
@@05: MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
@@10: POP RBP
|
||||
RET1 8
|
||||
//************************************
|
||||
_MHEAP_CTRL::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RBX,U64 SF_ARG1[RBP]
|
||||
XOR RAX,RAX
|
||||
TEST RBX,RBX
|
||||
JZ @@10
|
||||
MOV RAX,U64 CMemUsed.size-CMemUsed.start[RBX]
|
||||
TEST RAX,RAX
|
||||
JGE @@05 //Aligned alloced chunks have neg size
|
||||
ADD RBX,RAX
|
||||
@@05: MOV RAX,U64 CMemUsed.hc-CMemUsed.start[RBX]
|
||||
@@10: POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
_extern _FREE U0 Free(U8 *addr); //Free $LK,"MAlloc",A="MN:MAlloc"$()ed memory chunk.
|
||||
_extern _MSIZE I64 MSize(U8 *src); //Size of heap object.
|
||||
_extern _MSIZE2 I64 MSize2(U8 *src); //Internal size of heap object.
|
||||
_extern _MHEAP_CTRL CHeapCtrl *MHeapCtrl(U8 *src); //$LK,"CHeapCtrl",A="MN:CHeapCtrl"$ of object.
|
||||
_extern _MALLOC U8 *MAlloc(I64 size,CTask *mem_task=NULL); //Alloc memory chunk.
|
||||
//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
|
||||
|
||||
U8 *AMAlloc(I64 size)
|
||||
{//Alloc memory in Adam's heap.
|
||||
return MAlloc(size,adam_task);
|
||||
}
|
||||
|
||||
U8 *CAlloc(I64 size,CTask *mem_task=NULL)
|
||||
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
|
||||
U8 *res=MAlloc(size,mem_task);
|
||||
MemSet(res,0,size);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *ACAlloc(I64 size)
|
||||
{//Alloc and set to zero memory in Adam's heap.
|
||||
return CAlloc(size,adam_task);
|
||||
}
|
||||
|
||||
U8 *MAllocIdent(U8 *src,CTask *mem_task=NULL)
|
||||
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
|
||||
U8 *res;
|
||||
I64 size;
|
||||
if (!src) return NULL;
|
||||
size=MSize(src);
|
||||
res=MAlloc(size,mem_task);
|
||||
MemCpy(res,src,size);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *AMAllocIdent(U8 *src)
|
||||
{//Alloc in Adam's heap, ident copy of heap node.
|
||||
return MAllocIdent(src,adam_task);
|
||||
}
|
||||
|
||||
U8 *MAllocAligned(I64 size,I64 alignment,
|
||||
CTask *mem_task=NULL,I64 misalignment=0)
|
||||
{//Only powers of two alignment. This is awful.
|
||||
I64 mask=alignment-1;
|
||||
U8 *ptr=MAlloc(size+mask+sizeof(I64)+misalignment,mem_task),
|
||||
*res=(ptr+sizeof(I64)+mask)&~mask+misalignment;
|
||||
res(I64 *)[-1]=ptr-res;
|
||||
#assert offset(CMemUsed.size)==offset(CMemUsed.start)-sizeof(I64)
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *CAllocAligned(I64 size,I64 alignment,
|
||||
CTask *mem_task=NULL,I64 misalignment=0)
|
||||
{//Only powers of two alignment. This is awful.
|
||||
I64 mask=alignment-1;
|
||||
U8 *ptr=MAlloc(size+mask+sizeof(I64)+misalignment,mem_task),
|
||||
*res=(ptr+sizeof(I64)+mask)&~mask+misalignment;
|
||||
res(I64 *)[-1]=ptr-res;
|
||||
#assert offset(CMemUsed.size)==offset(CMemUsed.start)-sizeof(I64)
|
||||
MemSet(res,0,size);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *StrNew(U8 *buf,CTask *mem_task=NULL)
|
||||
{//Accepts a $LK,"CTask",A="MN:CTask"$ or $LK,"CHeapCtrl",A="MN:CHeapCtrl"$. NULL allocs off current task's heap.
|
||||
U8 *res;
|
||||
I64 size;
|
||||
if (buf) {
|
||||
size=StrLen(buf)+1;
|
||||
res=MAlloc(size,mem_task);
|
||||
MemCpy(res,buf,size);
|
||||
} else {
|
||||
res=MAlloc(1,mem_task);
|
||||
*res=0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *AStrNew(U8 *buf)
|
||||
{//Alloc copy of string in Adam's heap.
|
||||
return StrNew(buf,adam_task);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#exe {Cd(__DIR__);};
|
||||
#include "PageTables"
|
||||
#include "MemPag"
|
||||
#include "BlkPool"
|
||||
#include "MAllocFree"
|
||||
#include "HeapCtrl"
|
||||
#include "MemPhysical"
|
||||
#exe {Cd("..");};
|
||||
@@ -0,0 +1,167 @@
|
||||
U0 SysBadFree(I64 *ptr)
|
||||
{
|
||||
Panic("Bad Free:",ptr);
|
||||
}
|
||||
|
||||
U0 SysBadMAlloc(I64 *ptr)
|
||||
{
|
||||
Panic("Bad MAlloc:",ptr);
|
||||
}
|
||||
|
||||
U8 *MemPagAlloc(I64 pags,CBlkPool *bp=NULL)
|
||||
{/*Alloc pags from BlkPool. Don't link to task.
|
||||
(Linking to a task means they will be freed when the task dies.)
|
||||
It might give you more than you asked for.
|
||||
|
||||
Return: NULL if out of memory.
|
||||
*/
|
||||
CMemBlk *res=NULL,*m;
|
||||
I64 i;
|
||||
if (!bp) bp=sys_code_bp;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&bp->locked_flags,BPlf_LOCKED))
|
||||
PAUSE
|
||||
if (pags<MEM_FREE_PAG_HASH_SIZE) {
|
||||
if (res=bp->free_pag_hash[pags]) {
|
||||
bp->free_pag_hash[pags]=res->next;
|
||||
goto at_done;
|
||||
}
|
||||
i=Bsr(MEM_FREE_PAG_HASH_SIZE)+1;
|
||||
} else {
|
||||
//We'll now round-up to a power of two.
|
||||
//There is some overhead on allocations and
|
||||
//we wouldn't want to round to the next
|
||||
//power of two if a power of two was requested.
|
||||
//So we use a little more than a power of two.
|
||||
pags-=MEM_EXTRA_HASH2_PAGS;
|
||||
i=Bsr(pags)+1;
|
||||
pags=1<<i+MEM_EXTRA_HASH2_PAGS;
|
||||
if (res=bp->free_pag_hash2[i]) {
|
||||
bp->free_pag_hash2[i]=res->next;
|
||||
goto at_done;
|
||||
}
|
||||
}
|
||||
m=&bp->mem_free_lst;
|
||||
while (TRUE) {
|
||||
if (!(res=m->next)) {
|
||||
//We're probably out of luck, but lets search for a
|
||||
//freed larger size block... and, screw-it, return the whole thing.
|
||||
do {
|
||||
if (res=bp->free_pag_hash2[++i]) {
|
||||
pags=1<<i+MEM_EXTRA_HASH2_PAGS;
|
||||
bp->free_pag_hash2[i]=res->next;
|
||||
goto at_done;
|
||||
}
|
||||
} while (i<64-MEM_PAG_BITS-1);
|
||||
pags=0;
|
||||
res=NULL; //Out of memory
|
||||
goto at_done2;
|
||||
}
|
||||
if (res->pags<pags)
|
||||
m=res;
|
||||
else {
|
||||
if (res->pags==pags) {
|
||||
m->next=res->next;
|
||||
goto at_done;
|
||||
} else {
|
||||
res->pags-=pags;
|
||||
res(U8 *)+=res->pags<<MEM_PAG_BITS;
|
||||
res->pags=pags;
|
||||
goto at_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
at_done:
|
||||
bp->used_u8s+=res->pags<<MEM_PAG_BITS;
|
||||
at_done2:
|
||||
LBtr(&bp->locked_flags,BPlf_LOCKED);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 MemPagFree(CMemBlk *m,CBlkPool *bp=NULL)
|
||||
{//Return non-task pags to BlkPool.
|
||||
I64 i,pags;
|
||||
if (m) {
|
||||
if (!bp) bp=sys_code_bp;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&bp->locked_flags,BPlf_LOCKED))
|
||||
PAUSE
|
||||
pags=m->pags;
|
||||
m->mb_signature=MBS_UNUSED_SIGNATURE_VAL;
|
||||
bp->used_u8s-=pags<<MEM_PAG_BITS;
|
||||
if (pags<MEM_FREE_PAG_HASH_SIZE) {
|
||||
m->next=bp->free_pag_hash[pags];
|
||||
bp->free_pag_hash[pags]=m;
|
||||
} else {
|
||||
//We'll now round-up to a power of two.
|
||||
//There is some overhead on allocations and
|
||||
//we wouldn't want to round to the next
|
||||
//power of two if a power of two was requested.
|
||||
//So we use a little more than a power of two.
|
||||
pags-=MEM_EXTRA_HASH2_PAGS;
|
||||
i=Bsr(pags);
|
||||
m->next=bp->free_pag_hash2[i];
|
||||
bp->free_pag_hash2[i]=m;
|
||||
}
|
||||
LBtr(&bp->locked_flags,BPlf_LOCKED);
|
||||
POPFD
|
||||
}
|
||||
}
|
||||
|
||||
CMemBlk *MemPagTaskAlloc(I64 pags,CHeapCtrl *hc)
|
||||
{/*hc must be locked. Don't preempt this routine.
|
||||
Currently, this is only called from $LK,"MAlloc",A="MN:MAlloc"$().
|
||||
Return: NULL if out of memory.
|
||||
*/
|
||||
CMemBlk *res;
|
||||
I64 threshold,cnt,size;
|
||||
CMemUnused *uum,**_uum,**_ptr;
|
||||
if (res=MemPagAlloc(pags,hc->bp)) {
|
||||
QueIns(res,hc->last_mem_blk);
|
||||
res->mb_signature=MBS_USED_SIGNATURE_VAL;
|
||||
hc->alloced_u8s+=res->pags<<MEM_PAG_BITS;
|
||||
|
||||
//Tidy-up free lst (Move into heap hash)
|
||||
//because if free lst gets long, delay causes crash.
|
||||
threshold=MEM_HEAP_HASH_SIZE>>4;
|
||||
#assert MEM_HEAP_HASH_SIZE>>4>=sizeof(U8 *)
|
||||
do {
|
||||
cnt=0;
|
||||
_uum=&hc->malloc_free_lst;
|
||||
while (uum=*_uum) {
|
||||
#assert !offset(CMemUnused.next)
|
||||
size=uum->size;
|
||||
if (size<threshold) {
|
||||
*_uum=uum->next;
|
||||
_ptr=(&hc->heap_hash)(U8 *)+size;
|
||||
uum->next=*_ptr;
|
||||
*_ptr=uum;
|
||||
} else {
|
||||
cnt++;
|
||||
_uum=uum;
|
||||
}
|
||||
}
|
||||
threshold<<=1;
|
||||
} while (cnt>8 && threshold<=MEM_HEAP_HASH_SIZE);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 MemPagTaskFree(CMemBlk *m,CHeapCtrl *hc)
|
||||
{//hc must be locked
|
||||
if (m) {
|
||||
PUSHFD
|
||||
CLI
|
||||
if (m->mb_signature!=MBS_USED_SIGNATURE_VAL)
|
||||
SysBadFree(m);
|
||||
else {
|
||||
QueRem(m);
|
||||
hc->alloced_u8s-=m->pags<<MEM_PAG_BITS;
|
||||
MemPagFree(m,hc->bp);
|
||||
}
|
||||
POPFD
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
Bool Mem32DevIns(CMemRange *tmpmr)
|
||||
{
|
||||
CMemRange *tmpmr1=dev.mem32_head.next,*tmpmr2;
|
||||
while (tmpmr1!=&dev.mem32_head) {
|
||||
if (!tmpmr1->type && tmpmr->base>=tmpmr1->base &&
|
||||
tmpmr->base+tmpmr->size<=tmpmr1->base+tmpmr1->size) {
|
||||
if (tmpmr->base>tmpmr1->base) {
|
||||
tmpmr2=AMAlloc(sizeof(CMemRange));
|
||||
tmpmr2->type=MRT_UNUSED;
|
||||
tmpmr2->flags=0;
|
||||
tmpmr2->base=tmpmr1->base;
|
||||
tmpmr2->size=tmpmr->base-tmpmr1->base;
|
||||
QueInsRev(tmpmr2,tmpmr1);
|
||||
}
|
||||
QueInsRev(tmpmr,tmpmr1);
|
||||
tmpmr1->size=tmpmr1->base+tmpmr1->size-
|
||||
(tmpmr->base+tmpmr->size);
|
||||
tmpmr1->base=tmpmr->base+tmpmr->size;
|
||||
if (!tmpmr1->size) {
|
||||
QueRem(tmpmr1);
|
||||
Free(tmpmr1);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
tmpmr1=tmpmr1->next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 Mem32DevInit()
|
||||
{
|
||||
CMemRange *tmpmr;
|
||||
CMemE820 *m20=MEM_E820;
|
||||
|
||||
QueInit(&dev.mem32_head);
|
||||
tmpmr=AMAlloc(sizeof(CMemRange));
|
||||
tmpmr->type=MRT_UNUSED;
|
||||
tmpmr->flags=0;
|
||||
//Maybe !!! Change this to 0xF0000000 !!!
|
||||
tmpmr->base=0xE0000000;
|
||||
tmpmr->size=0x10000000;
|
||||
QueIns(tmpmr,dev.mem32_head.last);
|
||||
|
||||
if (m20->type) {
|
||||
while (m20->type) {
|
||||
tmpmr=AMAlloc(sizeof(CMemRange));
|
||||
tmpmr->type=m20->type;
|
||||
tmpmr->flags=0;
|
||||
tmpmr->base=m20->base;
|
||||
tmpmr->size=m20->len;
|
||||
if (!Mem32DevIns(tmpmr))
|
||||
Free(tmpmr);
|
||||
m20++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U8 *Mem32DevAlloc(I64 size,I64 alignment)
|
||||
{//Alloc 32-bit addr space for device. (Doesn't work.) Not used.
|
||||
//For this to work the BIOS E820 map must be searched for gaps in
|
||||
//the 32-bit range and the pool initialized to the gaps.
|
||||
U8 *base,*limit;
|
||||
CMemRange *tmpmr,*tmpmr1;
|
||||
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
|
||||
Yield;
|
||||
tmpmr1=dev.mem32_head.next;
|
||||
while (tmpmr1!=&dev.mem32_head) {
|
||||
base=(tmpmr1->base+alignment-1)&~(alignment-1);
|
||||
limit=base+size-1;
|
||||
if (!tmpmr1->type &&
|
||||
limit<tmpmr1->base+tmpmr1->size) {
|
||||
tmpmr=AMAlloc(sizeof(CMemRange));
|
||||
tmpmr->type=MRT_DEV;
|
||||
tmpmr->flags=0;
|
||||
tmpmr->base=base;
|
||||
tmpmr->size=size;
|
||||
if (!Mem32DevIns(tmpmr)) {
|
||||
Free(tmpmr);
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
return NULL;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
return tmpmr->base;
|
||||
}
|
||||
tmpmr1=tmpmr1->next;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 Mem32DevFree(U8 *base)
|
||||
{//Free 32-bit device address space.
|
||||
CMemRange *tmpmr;
|
||||
if (!base) return;
|
||||
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
|
||||
Yield;
|
||||
tmpmr=dev.mem32_head.next;
|
||||
while (tmpmr!=&dev.mem32_head) {
|
||||
if (tmpmr->base==base) {
|
||||
tmpmr->type=MRT_UNUSED;
|
||||
break;
|
||||
}
|
||||
tmpmr=tmpmr->next;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
}
|
||||
|
||||
U8 *Mem64DevAlloc(I64 *_pages1Gig)
|
||||
{//Alloc 64-bit addr space for device.
|
||||
U8 *a;
|
||||
I64 i=*_pages1Gig,*pte;
|
||||
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
|
||||
Yield;
|
||||
while (i--) {
|
||||
a=dev.mem64_ptr-=1<<30;
|
||||
do {
|
||||
pte=MemPageTable(a);
|
||||
*pte=*pte&~0x18 |0x11; //Uncached and present
|
||||
InvlPg(dev.mem64_ptr);
|
||||
a+=mem_page_size;
|
||||
} while (a-dev.mem64_ptr<1<<30);
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
return dev.mem64_ptr;
|
||||
}
|
||||
|
||||
U0 Mem64DevFree(U8 *base,I64 pages1Gig)
|
||||
{//Free 64-bit device address space.
|
||||
if (!base) return;
|
||||
while (LBts(&sys_semas[SEMA_DEV_MEM],0))
|
||||
Yield;
|
||||
if (base==dev.mem64_ptr)
|
||||
dev.mem64_ptr+=pages1Gig*1<<30;
|
||||
//else not freed
|
||||
LBtr(&sys_semas[SEMA_DEV_MEM],0);
|
||||
}
|
||||
|
||||
U0 UncachedAliasAlloc() //Make uncached alias for 4 lowest Gig.
|
||||
{
|
||||
I64 i=4,*pte;
|
||||
U8 *a;
|
||||
a=dev.uncached_alias=Mem64DevAlloc(&i);
|
||||
do {
|
||||
pte=MemPageTable(a);
|
||||
*pte=0x197+a-dev.uncached_alias;
|
||||
InvlPg(a);
|
||||
a+=mem_page_size;
|
||||
} while (a-dev.uncached_alias<1<<32);
|
||||
}
|
||||
|
||||
I64 BIOSTotalMem()
|
||||
{
|
||||
I64 r01,r20;
|
||||
U16 *m01=MEM_E801;
|
||||
CMemE820 *m20=MEM_E820;
|
||||
|
||||
r01=0x100000+m01[0]<<10+m01[1]<<16;
|
||||
r20=0;
|
||||
if (m20->type) {
|
||||
while (m20->type) {
|
||||
if (m20->type==1)
|
||||
r20+=m20->len;
|
||||
m20++;
|
||||
}
|
||||
}
|
||||
return MaxI64(r01,r20);
|
||||
}
|
||||
|
||||
I64 Scale2Mem(I64 min,I64 max,I64 limit=2*1024*1024*1024)
|
||||
{//Helps pick DiskCache and RAMDisk sizes.
|
||||
//Can be used in $LK,"BootHDIns",A="MN:BootHDIns"$() config scripts.
|
||||
I64 i;
|
||||
if (sys_data_bp)
|
||||
i=sys_data_bp->alloced_u8s;
|
||||
else
|
||||
i=sys_code_bp->alloced_u8s;
|
||||
if (i>=limit)
|
||||
return max;
|
||||
else
|
||||
return min+(max-min)*i/limit;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
asm {
|
||||
// $LK,"::/Doc/MemOverview.DD"$
|
||||
|
||||
USE32
|
||||
SYS_INIT_PAGE_TABLES::
|
||||
//Check 1Gig page capability and set page size.
|
||||
MOV EAX,0x80000001
|
||||
CPUID
|
||||
MOV EAX,1<<21
|
||||
BT EDX,26
|
||||
JNC @@05
|
||||
MOV EAX,1<<30
|
||||
@@05: MOV U32 [MEM_PAGE_SIZE],EAX
|
||||
|
||||
//Set mapped space limit
|
||||
MOV EAX,[MEM_PHYSICAL_SPACE]
|
||||
MOV EDX,[MEM_PHYSICAL_SPACE+4]
|
||||
BT U32 [MEM_PAGE_SIZE],30 //Round-up to 1Gig boundary?
|
||||
JNC @@10
|
||||
ADD EAX,0x3FFFFFFF
|
||||
ADC EDX,0
|
||||
AND EAX,~0x3FFFFFFF
|
||||
@@10: INC EDX //Need 4Gig extra for uncached alias up at top of space.
|
||||
MOV [MEM_MAPPED_SPACE],EAX
|
||||
MOV [MEM_MAPPED_SPACE+4],EDX
|
||||
|
||||
//How many 2Meg pages?
|
||||
MOV CL,21
|
||||
ADD EAX,0x1FFFFF
|
||||
ADC EDX,0
|
||||
SHRD EAX,EDX
|
||||
SHR EDX,CL
|
||||
MOV [MEM_2MEG_NUM],EAX
|
||||
MOV [MEM_2MEG_NUM+4],EDX
|
||||
|
||||
//How many 1Gig pages?
|
||||
MOV CL,9
|
||||
ADD EAX,0x1FF
|
||||
ADC EDX,0
|
||||
SHRD EAX,EDX
|
||||
SHR EDX,CL
|
||||
MOV [MEM_1GIG_NUM],EAX
|
||||
MOV [MEM_1GIG_NUM+4],EDX
|
||||
|
||||
//How many 512Gig pages?
|
||||
MOV CL,9
|
||||
ADD EAX,0x1FF
|
||||
ADC EDX,0
|
||||
SHRD EAX,EDX
|
||||
SHR EDX,CL
|
||||
MOV [MEM_512GIG_NUM],EAX
|
||||
MOV [MEM_512GIG_NUM+4],EDX
|
||||
|
||||
//Set $LK,"CSysFixedArea",A="MN:CSysFixedArea"$ to zero
|
||||
MOV EDI,SYS_FIXED_AREA
|
||||
XOR EAX,EAX
|
||||
MOV ECX,sizeof(CSysFixedArea)/4
|
||||
REP_STOSD
|
||||
|
||||
MOV U32 [MEM_PML2],EDI
|
||||
//Check for 1Gig page capability.
|
||||
BT U32 [MEM_PAGE_SIZE],30
|
||||
JC @@15
|
||||
//Find PML2 Size
|
||||
MOV EAX,U32 [MEM_2MEG_NUM]
|
||||
ADD EAX,0x1FF
|
||||
AND EAX,~0x1FF
|
||||
SHL EAX,3
|
||||
ADD EDI,EAX
|
||||
|
||||
//Find PML3 Size
|
||||
@@15: MOV U32 [MEM_PML3],EDI
|
||||
MOV EAX,U32 [MEM_1GIG_NUM]
|
||||
ADD EAX,0x1FF
|
||||
AND EAX,~0x1FF
|
||||
SHL EAX,3
|
||||
ADD EDI,EAX
|
||||
|
||||
//Find PML4 Size
|
||||
MOV U32 [MEM_PML4],EDI
|
||||
MOV EAX,U32 [MEM_512GIG_NUM]
|
||||
ADD EAX,0x1FF
|
||||
AND EAX,~0x1FF
|
||||
SHL EAX,3
|
||||
ADD EAX,EDI
|
||||
|
||||
MOV U32 [MEM_HEAP_BASE],EAX
|
||||
|
||||
//Set page tables to zero
|
||||
MOV EDI,U32 [MEM_PML2]
|
||||
SUB EAX,EDI
|
||||
MOV ECX,EAX
|
||||
SHR ECX,2
|
||||
XOR EAX,EAX
|
||||
REP_STOSD
|
||||
|
||||
//Check for 1Gig page capability.
|
||||
BT U32 [MEM_PAGE_SIZE],30
|
||||
JC @@30
|
||||
|
||||
//PML2: Use 2Meg Pages
|
||||
MOV EAX,0x87 //bit 7 is page size (2Meg)
|
||||
XOR EDX,EDX
|
||||
MOV EDI,[MEM_PML2]
|
||||
MOV ECX,[MEM_2MEG_NUM]
|
||||
@@20: MOV U32 [EDI],EAX
|
||||
ADD EDI,4
|
||||
MOV U32 [EDI],EDX
|
||||
ADD EDI,4
|
||||
ADD EAX,0x200000
|
||||
ADC EDX,0
|
||||
LOOP @@20
|
||||
//PML3: Use 2Meg Pages
|
||||
MOV EAX,[MEM_PML2]
|
||||
OR EAX,7
|
||||
XOR EDX,EDX
|
||||
MOV EDI,[MEM_PML3]
|
||||
MOV ECX,[MEM_1GIG_NUM]
|
||||
@@25: MOV U32 [EDI],EAX
|
||||
ADD EDI,4
|
||||
MOV U32 [EDI],EDX
|
||||
ADD EDI,4
|
||||
ADD EAX,0x1000
|
||||
ADC EDX,0
|
||||
LOOP @@25
|
||||
JMP @@40
|
||||
|
||||
//PML3: Use 1Gig Pages
|
||||
@@30: MOV EAX,0x87 //bit 7 is page size (1Gig)
|
||||
XOR EDX,EDX
|
||||
MOV EDI,[MEM_PML3]
|
||||
MOV ECX,[MEM_1GIG_NUM]
|
||||
@@35: MOV U32 [EDI],EAX
|
||||
ADD EDI,4
|
||||
MOV U32 [EDI],EDX
|
||||
ADD EDI,4
|
||||
ADD EAX,0x40000000
|
||||
ADC EDX,0
|
||||
LOOP @@35
|
||||
|
||||
//PML4
|
||||
@@40: MOV EAX,[MEM_PML3]
|
||||
OR EAX,7
|
||||
XOR EDX,EDX
|
||||
MOV EDI,[MEM_PML4]
|
||||
MOV ECX,[MEM_512GIG_NUM]
|
||||
@@45: MOV U32 [EDI],EAX
|
||||
ADD EDI,4
|
||||
MOV U32 [EDI],EDX
|
||||
ADD EDI,4
|
||||
ADD EAX,0x1000
|
||||
ADC EDX,0
|
||||
LOOP @@45
|
||||
RET
|
||||
|
||||
SYS_INIT_16MEG_SYS_CODE_BP::
|
||||
// Init sys_code_bp to BIOS E801 lowest 16Meg val.
|
||||
// $LK,"BlkPoolsInit",A="MN:BlkPoolsInit"$() adds the rest.
|
||||
MOV U32 [SYS_CODE_BP],SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
|
||||
MOV U32 [SYS_CODE_BP+4],0
|
||||
|
||||
MOV U32 [SYS_DATA_BP],0
|
||||
MOV U32 [SYS_DATA_BP+4],0
|
||||
|
||||
XOR EAX,EAX
|
||||
MOV AX,U16 [MEM_E801] //1 Kb blks between 1M and 16M
|
||||
SHL EAX,10
|
||||
ADD EAX,0x100000
|
||||
MOV EDI,U32 [MEM_HEAP_BASE]
|
||||
SUB EAX,EDI
|
||||
|
||||
//EDI=BASE EAX=SIZE
|
||||
TEST U8 [SYS_MEM_INIT_FLAG],1
|
||||
JZ @@05
|
||||
PUSH EAX
|
||||
PUSH EDI
|
||||
MOV ECX,EAX
|
||||
MOV AL,U8 [SYS_MEM_INIT_VAL]
|
||||
REP_STOSB
|
||||
POP EDI
|
||||
POP EAX
|
||||
|
||||
@@05: SHR EAX,MEM_PAG_BITS
|
||||
MOV ESI,SYS_FIXED_AREA+CSysFixedArea.sys_code_bp
|
||||
MOV EBX,U32 CBlkPool.mem_free_lst[ESI]
|
||||
MOV U32 CMemBlk.next[EDI],EBX
|
||||
MOV U32 CMemBlk.next+4[EDI],0
|
||||
MOV U32 CBlkPool.mem_free_lst[ESI],EDI
|
||||
MOV U32 CBlkPool.mem_free_lst+4[ESI],0
|
||||
MOV U32 CMemBlk.mb_signature[EDI],MBS_UNUSED_SIGNATURE_VAL
|
||||
MOV U32 CMemBlk.pags[EDI],EAX
|
||||
SHL EAX,MEM_PAG_BITS
|
||||
ADD U32 CBlkPool.alloced_u8s[ESI],EAX
|
||||
|
||||
BTS U32 [SYS_RUN_LEVEL],RLf_16MEG_SYS_CODE_BP
|
||||
RET
|
||||
}
|
||||
|
||||
I64 *MemPageTable(U8 *a)
|
||||
{//Point to page table entry for addr.
|
||||
if (Bt(&mem_page_size,30))
|
||||
return *MEM_PML3(U64 *)+a>>30*8;
|
||||
else
|
||||
return *MEM_PML2(U64 *)+a>>21*8;
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
asm {
|
||||
ALIGN 16,OC_NOP
|
||||
USE16
|
||||
//See $LK,"TempleOS MultiCore",A="FI:::/Doc/MultiCore.DD"$.
|
||||
|
||||
//This code gets copied to $LK,"MP_VECT_ADDR",A="MN:MP_VECT_ADDR"$.
|
||||
//See $LK,"MemCpy(MP_VECT_ADDR",A="FF:::/Kernel/MultiProc.HC,MemCpy(mp:2"$.
|
||||
COREAP_16BIT_INIT::
|
||||
JMP @@05
|
||||
|
||||
ALIGN 4,OC_NOP
|
||||
AP_GDT_PTR: DU16 sizeof(CGDT)-1;
|
||||
DU64 0;
|
||||
|
||||
@@05: CLI
|
||||
WBINVD
|
||||
MOV AX,MP_VECT_ADDR/16
|
||||
MOV DS,AX
|
||||
LGDT U32 [CAP16BitInit.ap_gdt_ptr] //See $LK,"mp->ap_gdt_ptr",A="FF:::/Kernel/MultiProc.HC,mp->ap_gdt_ptr:2"$
|
||||
|
||||
MOV EAX,SYS_START_CR0
|
||||
MOV_CR0_EAX
|
||||
DU8 0x66,0xEA; //JMP CGDT.cs32:AP_32BIT_INIT
|
||||
DU32 AP_32BIT_INIT;
|
||||
DU16 CGDT.cs32;
|
||||
COREAP_16BIT_INIT_END::
|
||||
|
||||
USE32
|
||||
AP_32BIT_INIT:
|
||||
MOV AX,CGDT.ds
|
||||
MOV DS,AX
|
||||
MOV ES,AX
|
||||
MOV FS,AX
|
||||
MOV GS,AX
|
||||
MOV SS,AX
|
||||
|
||||
@@05: LOCK
|
||||
BTS U32 [SYS_MP_CNT_LOCK],0
|
||||
JC @@05
|
||||
|
||||
MOV ESI,U32 [SYS_MP_CNT_INITIAL]
|
||||
LOCK
|
||||
INC U32 [SYS_MP_CNT_INITIAL]
|
||||
LOCK
|
||||
BTR U32 [SYS_MP_CNT_LOCK],0
|
||||
|
||||
CMP ESI,MP_PROCESSORS_NUM
|
||||
JAE I32 _SYS_HLT
|
||||
|
||||
IMUL2 ESI,sizeof(CCPU)
|
||||
ADD ESI,U32 [SYS_CPU_STRUCTS]
|
||||
|
||||
LEA ESP,U32 CCPU.start_stk+sizeof(CCPU.start_stk)[ESI]
|
||||
PUSH U32 RFLAGG_START
|
||||
POPFD
|
||||
PUSH U32 0 //Return from next call will be 64-bit
|
||||
CALL SYS_ENTER_LONG_MODE
|
||||
USE64
|
||||
FNINIT
|
||||
MOV RAX,RSI
|
||||
CALL SET_GS_BASE
|
||||
@@10: MOV RAX,U64 CCPU.seth_task[RSI]
|
||||
TEST RAX,RAX
|
||||
JZ @@10
|
||||
MOV U64 CTask.gs[RAX],RSI
|
||||
CALL SET_FS_BASE
|
||||
|
||||
JMP I32 _TASK_CONTEXT_RESTORE
|
||||
}
|
||||
|
||||
U0 TSSBusy(I64 tr,Bool val=OFF)
|
||||
{//See $LK,"::/Demo/Lectures/Ring3.HC"$.
|
||||
LBEqu((&sys_gdt)(U8 *)+tr+4,9,val);
|
||||
}
|
||||
|
||||
CTSS *TSSNew(I64 cpu_num)
|
||||
{
|
||||
U32 *d,*d1;
|
||||
CTSS *tss=CAlloc(sizeof(CTSS));
|
||||
tss->io_map_offset=offset(CTSS.io_map);
|
||||
MemSet(tss->io_map,0xFF,0x10000/8);
|
||||
|
||||
tss->st0=MAlloc(MEM_INTERRUPT_STK);
|
||||
tss->rsp0=tss->st0(U8 *)+MSize(tss->st0);
|
||||
tss->st1=MAlloc(MEM_INTERRUPT_STK);
|
||||
tss->rsp1=tss->st1(U8 *)+MSize(tss->st1);
|
||||
tss->st2=MAlloc(MEM_INTERRUPT_STK);
|
||||
tss->rsp2=tss->st2(U8 *)+MSize(tss->st2);
|
||||
|
||||
tss->tr =offset(CGDT.tr)+cpu_num*16;
|
||||
tss->tr_ring3=offset(CGDT.tr_ring3)+cpu_num*16;
|
||||
|
||||
d=(&sys_gdt)(U8 *)+tss->tr;
|
||||
d1=d(U8 *)+4;
|
||||
*d =0x0000FFFF;
|
||||
*d1=0x008F8900;
|
||||
d(U8 *)+=2;
|
||||
*d|=tss & 0x00FFFFFF;
|
||||
*d1++|=tss & 0xFF000000;
|
||||
*d1++=tss>>32;
|
||||
*d1=0;
|
||||
|
||||
d=(&sys_gdt)(U8 *)+tss->tr_ring3;
|
||||
d1=d(U8 *)+4;
|
||||
*d =0x0000FFFF;
|
||||
*d1=0x008FE900;
|
||||
d(U8 *)+=2;
|
||||
*d|=tss & 0x00FFFFFF;
|
||||
*d1++|=tss & 0xFF000000;
|
||||
*d1++=tss>>32;
|
||||
*d1=0;
|
||||
|
||||
return tss;
|
||||
}
|
||||
|
||||
CCPU *CPUStructInit(I64 num,CCPU *c,CTask *seth_task)
|
||||
{//Seth is null when called by adam on CSysFixedArea.boot_cpu0
|
||||
MemSet(c,0,sizeof(CCPU));
|
||||
c->addr=c;
|
||||
c->num=num;
|
||||
c->idle_factor=0.01;
|
||||
QueInit(&c->next_dying);
|
||||
if (Bt(&sys_run_level,RLf_16MEG_ADAM_HEAP_CTRL)) {
|
||||
c->idle_task=Spawn(0,NULL,"Idle Task",,Fs,,0);
|
||||
LBts(&c->idle_task->task_flags,TASKf_IDLE);
|
||||
c->tss=TSSNew(num);
|
||||
}
|
||||
c->seth_task=seth_task;// It waits for this to be filled-in: $LK,"seth_task",A="FF:::/Kernel/MultiProc.HC,seth_task"$
|
||||
return c;
|
||||
}
|
||||
|
||||
U0 MPInt(U8 num,I64 cpu_num=1)
|
||||
{//Generate interrupt for specified core.
|
||||
if (cpu_num>=mp_cnt) {
|
||||
if (!Bt(&sys_run_level,RLf_MP))
|
||||
return;
|
||||
else
|
||||
throw('MultCore');
|
||||
}
|
||||
PUSHFD
|
||||
CLI //Multitasking safe because each core has a local apic and IRQ's are off
|
||||
while (*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)&0x1000)
|
||||
PAUSE
|
||||
*(dev.uncached_alias+LAPIC_ICR_HIGH)(U32 *)=dev.mp_apic_ids[cpu_num]<<24;
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0x4000+num;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 MPIntAll(U8 num)
|
||||
{//Generate interrupt for all but own core.
|
||||
PUSHFD
|
||||
CLI //Multitasking safe because each core has a local apic and IRQ's are off
|
||||
while (*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)&0x1000)
|
||||
PAUSE
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4800+num;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 MPNMInt()
|
||||
{//Generate nonmaskable interrupt.
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4400;
|
||||
}
|
||||
|
||||
U0 MPHalt()
|
||||
{//Halt all other cores.
|
||||
mp_cnt=1;
|
||||
MPNMInt;
|
||||
Busy(10000);
|
||||
}
|
||||
|
||||
U0 MPAPICInit()
|
||||
{//Called by adam during start-up
|
||||
//and other cores during initialization
|
||||
//after $LK,"Core0StartMP",A="MN:Core0StartMP"$().
|
||||
*(dev.uncached_alias+LAPIC_SVR)(U32 *)|=LAPICF_APIC_ENABLED;
|
||||
dev.mp_apic_ids[Gs->num]=*(dev.uncached_alias+LAPIC_APIC_ID)(U32 *)>>24;
|
||||
*(dev.uncached_alias+LAPIC_LDR)(U32 *)=dev.mp_apic_ids[Gs->num]<<24;
|
||||
*(dev.uncached_alias+LAPIC_DFR)(U32 *)=0xF0000000;
|
||||
|
||||
// MemSet(dev.uncached_alias+LAPIC_IRR,0,0x20);
|
||||
// MemSet(dev.uncached_alias+LAPIC_ISR,0,0x20);
|
||||
// MemSet(dev.uncached_alias+LAPIC_TMR,0,0x20);
|
||||
|
||||
SetRAX(Gs->tss->tr);
|
||||
LTR AX
|
||||
if (Gs->num) {
|
||||
IntInit1;
|
||||
SetRFlags(RFLAGG_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
#assert !offset(CJobCtrl.next_waiting)
|
||||
|
||||
U0 CoreAPSethTask()
|
||||
{
|
||||
CJobCtrl *ctrl=&Fs->srv_ctrl;
|
||||
while (TRUE) {
|
||||
STI
|
||||
do {
|
||||
TaskKillDying;
|
||||
do PAUSE
|
||||
while (LBts(&ctrl->flags,JOBCf_LOCKED));
|
||||
} while (ctrl->next_waiting!=ctrl && JobRunOne(GetRFlags,ctrl));
|
||||
CLI
|
||||
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
Yield;
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
CJob *JobQue(I64 (*fp_addr)(U8 *data),U8 *data=NULL,
|
||||
I64 target_cpu=1,I64 flags=1<<JOBf_FREE_ON_COMPLETE,
|
||||
I64 job_code=JOBT_CALL,U8 *aux_str=NULL,I64 aux1=0,I64 aux2=0)
|
||||
{//Queue multicore jobs, handled by Seth tasks.
|
||||
//Set flags to zero if you wish to get the res.
|
||||
//See $LK,"::/Demo/MultiCore/Lock.HC"$
|
||||
CJobCtrl *ctrl;
|
||||
CJob *tmpc;
|
||||
CTask *seth;
|
||||
if (!(0<=target_cpu<mp_cnt))
|
||||
throw('MultCore');
|
||||
tmpc=ACAlloc(sizeof(CJob));
|
||||
if (aux_str)
|
||||
tmpc->aux_str=AStrNew(aux_str);
|
||||
tmpc->job_code=job_code;
|
||||
tmpc->addr=fp_addr;
|
||||
tmpc->fun_arg=data;
|
||||
tmpc->flags=flags;
|
||||
tmpc->aux1=aux1;
|
||||
tmpc->aux2=aux2;
|
||||
seth=cpu_structs[target_cpu].seth_task;
|
||||
tmpc->ctrl=ctrl=&seth->srv_ctrl;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&ctrl->flags,JOBCf_LOCKED))
|
||||
Yield;
|
||||
if (ctrl->next_waiting==ctrl && LBtr(&seth->task_flags,TASKf_AWAITING_MSG))
|
||||
MPInt(I_WAKE,target_cpu);
|
||||
QueIns(tmpc,ctrl->last_waiting);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
POPFD
|
||||
return tmpc;
|
||||
}
|
||||
|
||||
CTask *SpawnQue(U0 (*fp_addr)(U8 *data),U8 *data=NULL,U8 *task_name=NULL,
|
||||
I64 target_cpu, CTask *parent=NULL, //NULL means adam
|
||||
I64 stk_size=0,I64 flags=1<<JOBf_ADD_TO_QUE)
|
||||
{
|
||||
CTask *res;
|
||||
CJob *tmpc=JobQue(fp_addr,data,target_cpu,
|
||||
flags,JOBT_SPAWN_TASK,task_name,parent,stk_size);
|
||||
CJobCtrl *ctrl;
|
||||
|
||||
while (!Bt(&tmpc->flags,JOBf_DONE)) {
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
Yield;
|
||||
}
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
|
||||
res=tmpc->spawned_task;
|
||||
ctrl=tmpc->ctrl;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&ctrl->flags,JOBCf_LOCKED))
|
||||
Yield;
|
||||
QueRem(tmpc);
|
||||
LBtr(&ctrl->flags,JOBCf_LOCKED);
|
||||
POPFD
|
||||
JobDel(tmpc);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 CoreAPSethInit()
|
||||
{//Called by multicore's seth task after $LK,"Core0StartMP",A="MN:Core0StartMP"$()
|
||||
//as the first thing a CPU does before waiting for jobs.
|
||||
MPAPICInit;
|
||||
Fs->rip=&CoreAPSethTask;
|
||||
TaskContextRestore;
|
||||
}
|
||||
|
||||
U0 Core0StartMP()
|
||||
{//Called by adam during $LK,"start-up",A="FF:::/Kernel/KEnd.HC,Core0StartMP"$.
|
||||
CTask *task;
|
||||
U8 buf[STR_LEN];
|
||||
CAP16BitInit *mp=MP_VECT_ADDR;
|
||||
CCPU *c;
|
||||
I64 i,my_mp_cnt;
|
||||
CRAXRBCRCXRDX ee;
|
||||
|
||||
CPUId(0x1,&ee);
|
||||
if (!Bt(&ee.rdx,9))
|
||||
return;
|
||||
|
||||
PUSHFD
|
||||
CLI
|
||||
if (mp_cnt>1) {
|
||||
my_mp_cnt=mp_cnt;
|
||||
MPHalt; //sets mp_cnt to 1
|
||||
for (i=1;i<my_mp_cnt;i++) {
|
||||
c=&cpu_structs[i];
|
||||
JobQueDel(&c->seth_task->srv_ctrl.next_waiting);
|
||||
JobQueDel(&c->seth_task->srv_ctrl.next_done);
|
||||
}
|
||||
}
|
||||
MemSet(&cpu_structs[1],0,sizeof(CCPU)*(MP_PROCESSORS_NUM-1));
|
||||
|
||||
//When you start-up other cores, they jump to an addr
|
||||
//specified by a byte vect number, $LK,"MPN_VECT",A="MN:MPN_VECT"$ which corresponds
|
||||
//to a location 4096*vect number, $LK,"MP_VECT_ADDR",A="MN:MP_VECT_ADDR"$$WW,0$.
|
||||
MemCpy(mp,COREAP_16BIT_INIT,COREAP_16BIT_INIT_END-COREAP_16BIT_INIT);
|
||||
MemCpy(&mp->ap_gdt_ptr,SYS_GDT_PTR,sizeof(CSysLimitBase));
|
||||
mp_cnt_initial=mp_cnt=1;
|
||||
mp_cnt_lock=0;
|
||||
|
||||
*(dev.uncached_alias+LAPIC_LVT_ERR)(U32 *)=
|
||||
*(dev.uncached_alias+LAPIC_LVT_ERR)(U32 *)&0xFFFFFF00+MPN_VECT;
|
||||
WBINVD //Not sure why this is needed. Might just need delay. $LK,"MemCpy",A="MN:MemCpy"$ above?
|
||||
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4500; //assert init IPI
|
||||
Busy(10000);
|
||||
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4600+MPN_VECT; //start-up
|
||||
Busy(200);
|
||||
*(dev.uncached_alias+LAPIC_ICR_LOW)(U32 *)=0xC4600+MPN_VECT;
|
||||
|
||||
Busy(100000);
|
||||
for (i=0;i<10000;i++)
|
||||
LBts(&mp_cnt_lock,0); //Don't let more through
|
||||
my_mp_cnt=mp_cnt_initial;
|
||||
|
||||
if (my_mp_cnt>MP_PROCESSORS_NUM)
|
||||
my_mp_cnt=MP_PROCESSORS_NUM;
|
||||
|
||||
for (i=1;i<my_mp_cnt;i++) {
|
||||
StrPrint(buf,"Seth Task CPU%02X",i);
|
||||
task=Spawn(&CoreAPSethInit,NULL,buf,,,MEM_SETH_STK,0);
|
||||
task->rflags=RFLAGG_START;
|
||||
//$LK,"CTask",A="MN:CTask"$ alloced off this core's seth_task's heap (Which is Adam)
|
||||
CPUStructInit(i,&cpu_structs[i],task);
|
||||
WBINVD //Not sure why this is needed. Might just need delay.
|
||||
}
|
||||
|
||||
//Make sure they're all up-and-running
|
||||
for (i=1;i<my_mp_cnt;i++)
|
||||
while (!Bt(&cpu_structs[i].seth_task->task_flags,TASKf_AWAITING_MSG))
|
||||
PAUSE;
|
||||
|
||||
POPFD
|
||||
mp_cnt=my_mp_cnt; //Finalize cnt
|
||||
}
|
||||
|
||||
U0 Core0Init()
|
||||
{//Called by adam during start-up
|
||||
CRAXRBCRCXRDX ee;
|
||||
CPUId(0x1,&ee);
|
||||
|
||||
mp_cnt_initial=mp_cnt=1;
|
||||
mp_cnt_lock=0;
|
||||
|
||||
dbg.mp_crash=ACAlloc(sizeof(CMPCrash));
|
||||
|
||||
//Must be in code heap because init code uses 32 bit addr of cpu_struct
|
||||
adam_task->gs=cpu_structs=
|
||||
CAlloc(sizeof(CCPU)*MP_PROCESSORS_NUM,Fs->code_heap);
|
||||
CPUStructInit(0,cpu_structs,adam_task);
|
||||
asm {//RAX has GS
|
||||
IMPORT SET_GS_BASE;
|
||||
CALL SET_GS_BASE
|
||||
}
|
||||
if (Bt(&ee.rdx,9)) {
|
||||
//Unnecessary?
|
||||
// SetMSR(IA32_LAPIC_BASE,dev.uncached_alias+LAPIC_BASE+0x900);
|
||||
MPAPICInit;
|
||||
}
|
||||
}
|
||||
|
||||
interrupt U0 IntMPCrash()
|
||||
{//Entering the debugger from another core causes an interrupt on Core0
|
||||
//Which calls this routine.
|
||||
*(dev.uncached_alias+LAPIC_EOI)(U32 *)=0;
|
||||
mp_cnt=1;
|
||||
Raw(ON);
|
||||
text.raw_flags|=RWF_SHOW_DOLLAR;
|
||||
"MP Crash CPU%02X Task:%08X\n"
|
||||
"RIP:%P\n",dbg.mp_crash->cpu_num,dbg.mp_crash->task,dbg.mp_crash->rip;
|
||||
Panic(dbg.mp_crash->msg,dbg.mp_crash->msg_num);
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
asm {
|
||||
USE32
|
||||
|
||||
SYS_PCIBIOS_SERVICE_DIR:: DU32 0;
|
||||
SYS_PCI_SERVICES:: DU32 0;
|
||||
|
||||
SYS_FIND_PCIBIOS_SERVICE_DIR::
|
||||
MOV ESI,0xE0000
|
||||
MOV ECX,(0x100000-0xE0000)/4
|
||||
@@05: CMP U32 [ESI],'_32_'
|
||||
JNE @@20
|
||||
PUSH ECX
|
||||
XOR ECX,ECX
|
||||
MOV CL,U8 9[ESI]
|
||||
SHL ECX,4
|
||||
@@10: MOV EDI,ESI
|
||||
XOR EAX,EAX
|
||||
XOR EDX,EDX
|
||||
@@15: MOV DL,U8 [EDI]
|
||||
ADD EAX,EDX
|
||||
INC EDI
|
||||
DEC ECX
|
||||
JNZ @@15
|
||||
POP ECX
|
||||
TEST AL,AL
|
||||
JNZ @@20
|
||||
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],ESI
|
||||
MOV ESI,U32 4[ESI]
|
||||
MOV U32 [SYS_PCIBIOS_SERVICE_CALL],ESI
|
||||
RET
|
||||
|
||||
@@20: ADD ESI,4
|
||||
LOOP @@05
|
||||
MOV U32 [SYS_PCIBIOS_SERVICE_DIR],0
|
||||
RET
|
||||
|
||||
SYS_FIND_PCI_SERVICES::
|
||||
MOV ESI,U32 [SYS_PCIBIOS_SERVICE_DIR]
|
||||
TEST ESI,ESI
|
||||
JNZ @@05
|
||||
MOV U32 [SYS_PCI_SERVICES],0
|
||||
RET
|
||||
@@05: MOV EAX,'$$PCI'
|
||||
XOR EBX,EBX
|
||||
DU8 0x9A; //CALL CGDT.cs32:PCIBIOS_SERVICE
|
||||
SYS_PCIBIOS_SERVICE_CALL:: DU32 0;
|
||||
DU16 CGDT.cs32;
|
||||
TEST AL,AL
|
||||
JNZ @@05
|
||||
LEA ESI,U32 [EBX+EDX]
|
||||
MOV U32 [SYS_PCI_SERVICES],ESI
|
||||
RET
|
||||
|
||||
@@05: MOV U32 [SYS_PCI_SERVICES],0
|
||||
RET
|
||||
|
||||
USE64
|
||||
C32_EAX:: DU32 0;
|
||||
C32_EBX:: DU32 0;
|
||||
C32_ECX:: DU32 0;
|
||||
C32_EDX:: DU32 0;
|
||||
C32_ESI:: DU32 0;
|
||||
C32_EDI:: DU32 0;
|
||||
C32_EFLAGS:: DU32 0;
|
||||
|
||||
C32_RSP:: DU64 0;
|
||||
|
||||
_FAR_CALL32::
|
||||
//This calls a 32-bit mode routine.
|
||||
//(We must switch from 64-bit mode to do it.)
|
||||
//
|
||||
//NON REENTRANT
|
||||
//
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
MOV RAX,U64 SF_ARG1[RBP]
|
||||
TEST RAX,RAX
|
||||
JNZ @@05
|
||||
POP RBP
|
||||
RET1 8 //return FALSE
|
||||
@@05: MOV U32 [C32_ADD],EAX
|
||||
PUSH_REGS
|
||||
PUSHFD
|
||||
XOR RAX,RAX
|
||||
PUSH U64 FS:CTask.addr[RAX]
|
||||
PUSH U64 GS:CCPU.addr[RAX]
|
||||
MOV U64 [C32_RSP],RSP
|
||||
PUSH U32 CGDT.ds //STKSEG
|
||||
PUSH U32 BOOT_RAM_LIMIT //STK
|
||||
PUSH U32 0 //FLAGS--interrupts off
|
||||
PUSH U32 CGDT.cs32
|
||||
LEA RAX,[@@15]
|
||||
PUSH RAX
|
||||
IRET
|
||||
USE32
|
||||
@@15:
|
||||
WBINVD
|
||||
//disable paging
|
||||
MOV_EAX_CR0
|
||||
BTR EAX,31
|
||||
MOV_CR0_EAX
|
||||
|
||||
MOV ECX,IA32_EFER
|
||||
XOR EDX,EDX
|
||||
XOR EAX,EAX
|
||||
WRMSR
|
||||
|
||||
MOV AX,CGDT.ds
|
||||
MOV FS,AX
|
||||
MOV GS,AX
|
||||
//SS already set
|
||||
|
||||
MOV EAX,U32 [C32_EAX]
|
||||
MOV EBX,U32 [C32_EBX]
|
||||
MOV ECX,U32 [C32_ECX]
|
||||
MOV EDX,U32 [C32_EDX]
|
||||
MOV ESI,U32 [C32_ESI]
|
||||
MOV EDI,U32 [C32_EDI]
|
||||
MOV U32 [C32_EFLAGS],0
|
||||
|
||||
DU8 0x9A; //CALL CGDT.cs32:[C32_ADD]
|
||||
C32_ADD:: DU32 0;
|
||||
DU16 CGDT.cs32;
|
||||
|
||||
PUSHFD
|
||||
POP U32 [C32_EFLAGS]
|
||||
|
||||
MOV U32 [C32_EAX],EAX
|
||||
MOV U32 [C32_EBX],EBX
|
||||
MOV U32 [C32_ECX],ECX
|
||||
MOV U32 [C32_EDX],EDX
|
||||
MOV U32 [C32_ESI],ESI
|
||||
MOV U32 [C32_EDI],EDI
|
||||
|
||||
PUSH U32 0 //Return from next call will be 64-bit
|
||||
CALL SYS_ENTER_LONG_MODE
|
||||
|
||||
USE64 MOV RSP,U64 [C32_RSP]
|
||||
POP RAX
|
||||
CALL SET_GS_BASE
|
||||
POP RAX
|
||||
CALL SET_FS_BASE
|
||||
|
||||
POPFD
|
||||
POP_REGS
|
||||
XOR RAX,RAX
|
||||
MOV AL,TRUE
|
||||
POP RBP
|
||||
RET1 8
|
||||
}
|
||||
|
||||
_extern C32_EAX U32 c32_eax;
|
||||
_extern C32_EBX U32 c32_ebx;
|
||||
_extern C32_ECX U32 c32_ecx;
|
||||
_extern C32_EDX U32 c32_edx;
|
||||
_extern C32_ESI U32 c32_esi;
|
||||
_extern C32_EDI U32 c32_edi;
|
||||
_extern C32_EFLAGS U32 c32_eflags;
|
||||
_extern SYS_PCI_SERVICES U32 sys_pci_services;
|
||||
|
||||
_extern _FAR_CALL32 Bool FarCall32(U0 (*fp_addr)());//Not reentrant.For PCIBIOS.
|
||||
|
||||
U8 PCIReadU8(I64 bus,I64 dev,I64 fun,I64 rg)
|
||||
{//Read U8 in PCI configspace at bus,dev,fun,reg.
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB108;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
if (FarCall32(sys_pci_services))
|
||||
res=c32_ecx.u8[0];
|
||||
else
|
||||
res=0xFF;
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U16 PCIReadU16(I64 bus,I64 dev,I64 fun,I64 rg)
|
||||
{//Read U16 in PCI configspace at bus,dev,fun,reg.
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB109;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
if (FarCall32(sys_pci_services))
|
||||
res=c32_ecx.u16[0];
|
||||
else
|
||||
res=0xFFFF;
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U32 PCIReadU32(I64 bus,I64 dev,I64 fun,I64 rg)
|
||||
{//Read U32 in PCI configspace at bus,dev,fun,reg.
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB10A;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
if (FarCall32(sys_pci_services))
|
||||
res=c32_ecx;
|
||||
else
|
||||
res=0xFFFFFFFF;
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 PCIWriteU8(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
|
||||
{//Write U8 in PCI configspace at bus,dev,fun,reg.
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB10B;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
c32_ecx=val;
|
||||
FarCall32(sys_pci_services);
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 PCIWriteU16(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
|
||||
{//Write U16 in PCI configspace at bus,dev,fun,reg.
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB10C;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
c32_ecx=val;
|
||||
FarCall32(sys_pci_services);
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 PCIWriteU32(I64 bus,I64 dev,I64 fun,I64 rg,I64 val)
|
||||
{//Write U32 in PCI configspace at bus,dev,fun,reg.
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB10D;
|
||||
c32_ebx=bus<<8+dev<<3+fun;
|
||||
c32_edi=rg;
|
||||
c32_ecx=val;
|
||||
FarCall32(sys_pci_services);
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
}
|
||||
|
||||
I64 PCIClassFind(I64 class_code,I64 n)
|
||||
{/*Find bus,dev,fun of Nth class_code dev.
|
||||
|
||||
class_code is low three bytes
|
||||
n is index starting at zero
|
||||
Return: -1 not found
|
||||
else bus,dev,fun.
|
||||
*/
|
||||
I64 res;
|
||||
PUSHFD
|
||||
CLI
|
||||
while (LBts(&sys_semas[SEMA_FAR_CALL32],0))
|
||||
Yield;
|
||||
c32_eax=0xB103;
|
||||
c32_esi=n;
|
||||
c32_ecx=class_code;
|
||||
if (FarCall32(sys_pci_services) && !c32_eax.u8[1])
|
||||
res=c32_ebx.u8[1]<<16+(c32_ebx&0xF8)<<5+c32_ebx&7;
|
||||
else
|
||||
res=-1;
|
||||
LBtr(&sys_semas[SEMA_FAR_CALL32],0);
|
||||
POPFD
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
U0 QSortI64(I64 *base,I64 num, I64 (*fp_compare)(I64 e1,I64 e2))
|
||||
{/*Quick Sort for width==8.
|
||||
fp_compare() passes by value instead of ref.
|
||||
|
||||
For ascending strings: return StrCmp(e1,e2);
|
||||
For ascending ints : return e1-e2;
|
||||
|
||||
Maybe, look at $LK,"::/Demo/MultiCore/MPRadix.HC"$.
|
||||
*/
|
||||
I64 i,*left,*right,pivot;
|
||||
if (num>1) {
|
||||
left =base;
|
||||
right=base+num-1;
|
||||
pivot=base[num/2];
|
||||
do {
|
||||
while ((*fp_compare)(*left,pivot)<0)
|
||||
left++;
|
||||
while ((*fp_compare)(*right,pivot)>0)
|
||||
right--;
|
||||
if (left<=right)
|
||||
SwapI64(left++,right--);
|
||||
} while (left<=right);
|
||||
i=right+1-base;
|
||||
if (1<i<num)
|
||||
QSortI64(base,i,fp_compare);
|
||||
i=base+num-left;
|
||||
if (1<i<num)
|
||||
QSortI64(left,i,fp_compare);
|
||||
}
|
||||
}
|
||||
|
||||
U0 QSort2a(U8 **base,I64 num,I64 (*fp_compare)(U8 **_e1,U8 **_e2))
|
||||
{//Not public.For case of width==size(U8 *)==8.
|
||||
//fp_compare() passes by ref.
|
||||
I64 i;
|
||||
U8 **left,**right,*pivot;
|
||||
left =base;
|
||||
right=base+num-1;
|
||||
pivot=base[num/2];
|
||||
do {
|
||||
while ((*fp_compare)(left,&pivot)<0)
|
||||
left++;
|
||||
while ((*fp_compare)(right,&pivot)>0)
|
||||
right--;
|
||||
if (left<=right)
|
||||
SwapI64(left++,right--);
|
||||
} while (left<=right);
|
||||
i=right+1-base;
|
||||
if (1<i<num)
|
||||
QSort2a(base,i,fp_compare);
|
||||
i=base+num-left;
|
||||
if (1<i<num)
|
||||
QSort2a(left,i,fp_compare);
|
||||
}
|
||||
U0 QSort2b(U8 *base,I64 num, I64 width,
|
||||
I64 (*fp_compare)(U8 *e1,U8 *e2),U8 *tmp)
|
||||
{//Not public
|
||||
I64 i;
|
||||
U8 *left,*right,*pivot=tmp+width;
|
||||
left =base;
|
||||
right=base+(num-1)*width;
|
||||
MemCpy(pivot,base+num/2*width,width);
|
||||
do {
|
||||
while ((*fp_compare)(left,pivot)<0)
|
||||
left+=width;
|
||||
while ((*fp_compare)(right,pivot)>0)
|
||||
right-=width;
|
||||
if (left<=right) {
|
||||
if (left!=right) {
|
||||
MemCpy(tmp,right,width);
|
||||
MemCpy(right,left,width);
|
||||
MemCpy(left,tmp,width);
|
||||
}
|
||||
left+=width;
|
||||
right-=width;
|
||||
}
|
||||
} while (left<=right);
|
||||
i=1+(right-base)/width;
|
||||
if (1<i<num)
|
||||
QSort2b(base,i,width,fp_compare,tmp);
|
||||
i=num+(base-left)/width;
|
||||
if (1<i<num)
|
||||
QSort2b(left,i,width,fp_compare,tmp);
|
||||
}
|
||||
U0 QSort(U8 *base,I64 num, I64 width, I64 (*fp_compare)(U8 *e1,U8 *e2))
|
||||
{/*Quick Sort: fp_compare() passes by ref.
|
||||
|
||||
For ascending strings: return StrCmp(*e1,*e2);
|
||||
For ascending ints : return *e1-*e2;
|
||||
Don't return e1-e2 if numbers can overflow, return -1,0 or 1.
|
||||
|
||||
Maybe, look at $LK,"::/Demo/MultiCore/MPRadix.HC"$.
|
||||
*/
|
||||
U8 *tmp;
|
||||
if (width && num>1) {
|
||||
if (width==sizeof(U8 *)) //assign instead of MemCpy for width 8
|
||||
QSort2a(base,num,fp_compare);
|
||||
else {
|
||||
tmp=MAlloc(width*2);
|
||||
QSort2b(base,num,width,fp_compare,tmp);
|
||||
Free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/*On each core, tasks are linked in a
|
||||
circular doubly-linked list queue with
|
||||
the Seth task as the head. On Core0,
|
||||
the queue order represents the front-to-back
|
||||
window stack order with the window mgr
|
||||
as the wallpaper.
|
||||
|
||||
The scheduler is round-robin. It checks
|
||||
if a task is ready and runs it or skips it.
|
||||
Swapping tasks just involves storing and
|
||||
restoring regs (no disk I/O for virtual
|
||||
memory and no addr map changes). It is
|
||||
always fully identity-mapped on all cores.
|
||||
Tasks can be switched in half a microsecond.
|
||||
|
||||
The scheduler checks if a task is
|
||||
waiting for a certain time or waiting
|
||||
on a message and skips if not ready.
|
||||
A task runs until it voluntarily yields ctrl
|
||||
with a call to $LK,"Yield",A="MN:Yield"$(). Tasks waiting on I/O
|
||||
often loop, checking for a status and
|
||||
$LK,"Yield",A="MN:Yield"$ing. This does not really degrade
|
||||
performance, but pegs the CPU Load.
|
||||
|
||||
The scheduler checks for a few keys:
|
||||
|
||||
<CTRL-ALT-x> kill a task.
|
||||
<CTRL-ALT-DEL> reboots.
|
||||
<CTRL-ALT-n> Next task.
|
||||
<CTRL-ALT-c> breaks execution of a program.
|
||||
|
||||
Each core has its own circular task queue.
|
||||
For AP processors, they have a "Seth" task
|
||||
which stays in a loop waiting for jobs or
|
||||
requests to spawn tasks. See $LK,"CoreAPSethTask",A="MN:CoreAPSethTask"$().
|
||||
$HL,1$*/
|
||||
|
||||
U0 TaskFocusNext()
|
||||
{
|
||||
CTask *task,*_task=sys_focus_task;
|
||||
sys_focus_task=NULL;
|
||||
if (!_task) _task=adam_task;
|
||||
task=_task->next_task;
|
||||
do {
|
||||
if (!Bt(&task->win_inhibit,WIf_SELF_FOCUS)) {
|
||||
sys_focus_task=task;
|
||||
CallExtNum(EXT_WIN_TO_TOP,task,TRUE);
|
||||
return;
|
||||
}
|
||||
task=task->next_task;
|
||||
} while (task!=_task);
|
||||
}
|
||||
|
||||
asm {
|
||||
TASK_CONTEXT_SAVE::
|
||||
//OUT: RSI=FS
|
||||
PUSH RSI
|
||||
PUSHFD
|
||||
XOR RSI,RSI
|
||||
MOV RSI,FS:CTask.addr[RSI]
|
||||
POP U64 CTask.rflags[RSI]
|
||||
POP U64 CTask.rsi[RSI]
|
||||
MOV U64 CTask.rax[RSI],RAX
|
||||
|
||||
/*Divert the stk to the Task memory
|
||||
and push onto it and divert it back.
|
||||
It's a little faster.
|
||||
*/
|
||||
MOV RAX,RSP
|
||||
LEA RSP,U64 CTask.r15+8[RSI]
|
||||
PUSH R15
|
||||
PUSH R14
|
||||
PUSH R13
|
||||
PUSH R12
|
||||
PUSH R11
|
||||
PUSH R10
|
||||
PUSH R9
|
||||
PUSH R8
|
||||
PUSH RDI
|
||||
PUSH RBP
|
||||
PUSH RBX
|
||||
PUSH RDX
|
||||
PUSH RCX
|
||||
MOV RSP,RAX
|
||||
|
||||
MOV RAX,U64 CTask.fpu_mmx[RSI]
|
||||
FXSAVE U64 [RAX]
|
||||
|
||||
MOV RDX,U64 CTask.bpt_lst[RSI]
|
||||
@@05: TEST RDX,RDX
|
||||
JZ @@10
|
||||
MOV RDI,U64 CBpt.addr[RDX]
|
||||
MOV AL,U8 CBpt.val[RDX]
|
||||
MOV U8 [RDI],AL
|
||||
MOV RDX,U64 CBpt.next[RDX]
|
||||
JMP @@05
|
||||
@@10: RET
|
||||
//************************************
|
||||
_TASK_CONTEXT_RESTORE::
|
||||
XOR RAX,RAX
|
||||
INC U64 GS:CCPU.swap_cnter[RAX]
|
||||
MOV RSI,FS:CTask.addr[RAX]
|
||||
BT U32 CTask.rflags[RSI],RFLAGf_INT
|
||||
JNC @@05
|
||||
BTS U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK
|
||||
@@05: BT U64 CTask.task_flags[RSI],TASKf_DISABLE_BPTS
|
||||
JC @@15
|
||||
MOV RDX,U64 CTask.bpt_lst[RSI]
|
||||
@@10: TEST RDX,RDX
|
||||
JZ @@15
|
||||
MOV RDI,U64 CBpt.addr[RDX]
|
||||
MOV U8 [RDI],OC_BPT
|
||||
MOV RDX,U64 CBpt.next[RDX]
|
||||
JMP @@10
|
||||
|
||||
@@15: INC U64 CTask.swap_cnter[RSI]
|
||||
|
||||
MOV RAX,U64 CTask.fpu_mmx[RSI]
|
||||
FXRSTOR U64 [RAX]
|
||||
|
||||
MOV RAX,RSP
|
||||
LEA RSP,U64 CTask.rcx[RSI]
|
||||
POP RCX
|
||||
POP RDX
|
||||
POP RBX
|
||||
POP RBP
|
||||
POP RDI
|
||||
POP R8
|
||||
POP R9
|
||||
POP R10
|
||||
POP R11
|
||||
POP R12
|
||||
POP R13
|
||||
POP R14
|
||||
POP R15
|
||||
MOV RSP,RAX
|
||||
|
||||
MOV RAX,U64 CTask.rax[RSI]
|
||||
PUSH CGDT.ds
|
||||
PUSH U64 CTask.rsp[RSI]
|
||||
PUSH U64 CTask.rflags[RSI]
|
||||
PUSH CGDT.cs64
|
||||
PUSH U64 CTask.rip[RSI]
|
||||
MOV RSI,U64 CTask.rsi[RSI]
|
||||
IRET
|
||||
//************************************
|
||||
END_RSI_TASK:
|
||||
MOV RAX,RSI
|
||||
CALL SET_FS_BASE
|
||||
_TASK_END_NOW::
|
||||
CALL &TaskEnd
|
||||
MOV RSI,RAX
|
||||
CALL SET_FS_BASE
|
||||
JMP I8 RESTORE_RSI_TASK
|
||||
|
||||
_YIELD::
|
||||
PUSHFD
|
||||
TEST U8 [SYS_SEMAS+SEMA_SINGLE_USER*DFT_CACHE_LINE_WIDTH],1
|
||||
JZ @@05
|
||||
POPFD //If single user, don't change task.
|
||||
RET
|
||||
|
||||
@@05: CLI
|
||||
CALL TASK_CONTEXT_SAVE
|
||||
MOV EBX,U32 _RET
|
||||
MOV U64 CTask.rip[RSI],RBX
|
||||
POP U64 CTask.rflags[RSI]
|
||||
MOV U64 CTask.rsp[RSI],RSP
|
||||
MOV RSI,U64 CTask.next_task[RSI]
|
||||
|
||||
RESTORE_RSI_TASK:
|
||||
TEST U64 [SYS_CTRL_ALT_FLAGS],1<<CTRL_ALT_DEL|
|
||||
1<<CTRL_ALT_TAB|1<<CTRL_ALT_X|1<<CTRL_ALT_C
|
||||
JNZ HANDLE_SYSF_KEY_EVENT
|
||||
|
||||
RESTORE_RSI_TASK2:
|
||||
@@20: BT U64 CTask.task_flags[RSI],TASKf_KILL_TASK
|
||||
JC END_RSI_TASK
|
||||
TEST U64 CTask.task_flags[RSI],
|
||||
1<<TASKf_AWAITING_MSG|1<<TASKf_SUSPENDED
|
||||
JNZ @@25
|
||||
|
||||
MOV RAX,U64 [&cnts.jiffies]
|
||||
CMP U64 CTask.wake_jiffy[RSI],RAX
|
||||
JG @@25 //Jmp if not ready, yet.
|
||||
|
||||
MOV RAX,RSI
|
||||
CALL SET_FS_BASE
|
||||
JMP I32 _TASK_CONTEXT_RESTORE
|
||||
|
||||
@@25: MOV RSI,U64 CTask.next_task[RSI]
|
||||
XOR RAX,RAX
|
||||
CMP U64 GS:CCPU.seth_task[RAX],RSI
|
||||
JNE @@20 //Jmp if not Seth
|
||||
BTR U32 GS:CCPU.cpu_flags[RAX],CPUf_RAN_A_TASK
|
||||
JC @@20 //Jmp if had chance for IRQ already
|
||||
MOV RAX,U64 GS:CCPU.idle_task[RAX]
|
||||
MOV RSP,U64 CTask.stk[RAX]
|
||||
ADD RSP,MEM_DFT_STK+CTaskStk.stk_base //Rst to top
|
||||
CALL SET_FS_BASE
|
||||
STI //Restore idle task so we can unmask IRQs.
|
||||
HLT
|
||||
SYS_IDLE_PT::
|
||||
CLI
|
||||
|
||||
RESTORE_SETH_TASK_IF_READY:
|
||||
XOR RAX,RAX
|
||||
MOV RSI,GS:CCPU.seth_task[RAX]
|
||||
JMP RESTORE_RSI_TASK
|
||||
|
||||
HANDLE_SYSF_KEY_EVENT:
|
||||
MOV RAX,RSI
|
||||
CALL SET_FS_BASE
|
||||
XOR RBX,RBX
|
||||
MOV RAX,GS:CCPU.num[RBX]
|
||||
TEST RAX,RAX
|
||||
JNZ I32 RESTORE_RSI_TASK2
|
||||
|
||||
MOV EAX,U32 SYS_CTRL_ALT_FLAGS
|
||||
LOCK
|
||||
BTR U32 [RAX],CTRL_ALT_DEL
|
||||
JC I32 &Reboot
|
||||
|
||||
CMP U64 GS:CCPU.idle_task[RBX],RSI
|
||||
JE RESTORE_SETH_TASK_IF_READY
|
||||
|
||||
LOCK
|
||||
BTR U32 [RAX],CTRL_ALT_TAB
|
||||
JNC @@05
|
||||
CALL &TaskFocusNext
|
||||
JMP I32 RESTORE_FS_TASK
|
||||
|
||||
@@05: LOCK
|
||||
BTR U32 [RAX],CTRL_ALT_X
|
||||
JC END_FOCUS_USER
|
||||
LOCK
|
||||
BTR U32 [RAX],CTRL_ALT_C
|
||||
JNC I32 RESTORE_RSI_TASK
|
||||
|
||||
BREAK_FOCUS_USER:
|
||||
MOV RSI,U64 [SYS_FOCUS_TASK]
|
||||
TEST RSI,RSI
|
||||
JZ RESTORE_SETH_TASK_IF_READY
|
||||
BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS
|
||||
JC I32 RESTORE_RSI_TASK
|
||||
LOCK
|
||||
BTR U64 CTask.task_flags[RSI],TASKf_BREAK_LOCKED
|
||||
JNC @@10
|
||||
LOCK
|
||||
BTS U64 CTask.task_flags[RSI],TASKf_PENDING_BREAK
|
||||
JMP I32 RESTORE_RSI_TASK
|
||||
|
||||
@@10: MOV RAX,&Break
|
||||
MOV U64 CTask.rip[RSI],RAX
|
||||
BT U64 CTask.task_flags[RSI],TASKf_BREAK_TO_SHIFT_ESC
|
||||
JC I32 RESTORE_RSI_TASK
|
||||
|
||||
//Do these now, in case interrupt happens.
|
||||
MOV U64 CTask.wake_jiffy[RSI],0
|
||||
PUSH RSI
|
||||
CALL &TaskRstAwaitingMsg
|
||||
JMP I32 RESTORE_RSI_TASK
|
||||
|
||||
END_FOCUS_USER:
|
||||
MOV RSI,U64 [SYS_FOCUS_TASK]
|
||||
CALL &TaskFocusNext
|
||||
TEST RSI,RSI
|
||||
JZ I32 RESTORE_SETH_TASK_IF_READY
|
||||
MOV RAX,RSI
|
||||
CALL SET_FS_BASE
|
||||
BT U64 CTask.win_inhibit[RSI],WIf_SELF_FOCUS
|
||||
JC I32 RESTORE_RSI_TASK
|
||||
LOCK
|
||||
BTS U64 CTask.task_flags[RSI],TASKf_KILL_TASK
|
||||
JMP I32 END_RSI_TASK
|
||||
|
||||
RESTORE_FS_TASK:
|
||||
XOR RSI,RSI
|
||||
MOV RSI,FS:CTask.addr[RSI]
|
||||
JMP I32 RESTORE_RSI_TASK
|
||||
}
|
||||
|
||||
_extern _TASK_CONTEXT_RESTORE U0 TaskContextRestore(); //Restore a task context.
|
||||
_extern _YIELD U0 Yield(); //Yield cpu to next task.
|
||||
_extern _TASK_END_NOW U0 TaskEndNow(); //Terminate current task.
|
||||
|
||||
U0 TaskQueIns(CTask *task,CTask *pred=NULL)
|
||||
{//Insert a task in the scheduler running task queue.
|
||||
//You have no business with this, probably.
|
||||
CTask *last;
|
||||
PUSHFD
|
||||
CLI
|
||||
if (!pred) pred=Fs;
|
||||
last=pred->last_task;
|
||||
last->next_task=pred->last_task=task;
|
||||
task->last_task=last;
|
||||
task->next_task=pred;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 TaskQueRem(CTask *task)
|
||||
{//Remove a task from the scheduler running task queue.
|
||||
//Use $LK,"Suspend",A="MN:Suspend"$().
|
||||
CTask *next,*last;
|
||||
PUSHFD
|
||||
CLI
|
||||
next=task->next_task;
|
||||
last=task->last_task;
|
||||
last->next_task=next;
|
||||
next->last_task=last;
|
||||
POPFD
|
||||
}
|
||||
|
||||
U0 TaskQueInsChild(CTask *task)
|
||||
{
|
||||
CTask *last,*pred;
|
||||
PUSHFD
|
||||
CLI
|
||||
pred=task->parent_task->last_child_task;
|
||||
last=pred->last_sibling_task;
|
||||
last->next_sibling_task=pred->last_sibling_task=task;
|
||||
task->last_sibling_task=last;
|
||||
task->next_sibling_task=pred;
|
||||
POPFD
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
asm {
|
||||
NORMAL_KEY_SCAN_DECODE_TABLE::
|
||||
DU8 0,CH_ESC,"1234567890-=",CH_BACKSPACE,'\t';
|
||||
DU8 "qwertyuiop[]",'\n',0,"as";
|
||||
DU8 "dfghjkl;'\`",0,"\\zxcv";
|
||||
DU8 "bnm,./",0,'*',0,CH_SPACE,0,0,0,0,0,0;
|
||||
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
|
||||
SHIFT_KEY_SCAN_DECODE_TABLE::
|
||||
DU8 0,CH_SHIFT_ESC,"!@#$$%^&*()_+",CH_BACKSPACE,'\t';
|
||||
DU8 "QWERTYUIOP{}",'\n',0,"AS";
|
||||
DU8 "DFGHJKL:\"~",0,"|ZXCV";
|
||||
DU8 "BNM<>?",0,'*',0,CH_SHIFT_SPACE,0,0,0,0,0,0;
|
||||
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
|
||||
CTRL_KEY_SCAN_DECODE_TABLE::
|
||||
DU8 0,CH_ESC,"1234567890-=",CH_BACKSPACE,'\t';
|
||||
DU8 CH_CTRLQ,CH_CTRLW,CH_CTRLE,CH_CTRLR,CH_CTRLT,CH_CTRLY,CH_CTRLU,
|
||||
CH_CTRLI,CH_CTRLO,CH_CTRLP,"[]",'\n',0,CH_CTRLA,CH_CTRLS;
|
||||
DU8 CH_CTRLD,CH_CTRLF,CH_CTRLG,CH_CTRLH,CH_CTRLJ,CH_CTRLK,CH_CTRLL,
|
||||
";'\`",0,"\\",CH_CTRLZ,CH_CTRLX,CH_CTRLC,CH_CTRLV;
|
||||
DU8 CH_CTRLB,CH_CTRLN,CH_CTRLM,",./",0,'*',0,CH_SPACE,0,0,0,0,0,0;
|
||||
DU8 0,0,0,0,0,0,0,0,0,0,'-',0,0,0,'+',0;
|
||||
}
|
||||
|
||||
U0 KbdCmdSend(I64 port, U8 val)
|
||||
{
|
||||
F64 timeout=tS+0.125;
|
||||
while (tS<timeout) {
|
||||
if (!(InU8(KBD_CTRL)&2)) {
|
||||
OutU8(port,val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
I64 KbdCmdRead()
|
||||
{
|
||||
F64 timeout=tS+0.125;
|
||||
while (tS<timeout)
|
||||
if (InU8(KBD_CTRL)&1)
|
||||
return InU8(KBD_PORT);
|
||||
throw;
|
||||
}
|
||||
|
||||
U0 KbdCmdFlush()
|
||||
{
|
||||
F64 timeout=tS+0.03;
|
||||
while (tS<timeout)
|
||||
InU8(KBD_PORT);
|
||||
}
|
||||
|
||||
U0 KbdLEDsSet(I64 sc)
|
||||
{
|
||||
U8 v=0;
|
||||
BEqu(&v,0,Bt(&sc,SCf_SCROLL));
|
||||
BEqu(&v,1,Bt(&sc,SCf_NUM));
|
||||
BEqu(&v,2,Bt(&sc,SCf_CAPS));
|
||||
try {
|
||||
KbdCmdSend(KBD_PORT,0xED);
|
||||
KbdCmdSend(KBD_PORT,v);
|
||||
} catch
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
|
||||
U0 KbdMsCmdAck(...)
|
||||
{
|
||||
I64 i,ack,timeout;
|
||||
for (i=0;i<argc;i++) {
|
||||
timeout=5;
|
||||
do {
|
||||
ack=0;
|
||||
try {
|
||||
KbdCmdSend(KBD_CTRL,0xD4);
|
||||
KbdCmdSend(KBD_PORT,argv[i]);
|
||||
ack=KbdCmdRead;
|
||||
} catch {
|
||||
KbdCmdFlush;
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
} while (ack!=0xFA && --timeout);
|
||||
if (!timeout)
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
U0 KbdTypeMatic(U8 delay)
|
||||
{//Set speed of repeated keys.
|
||||
try {
|
||||
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
|
||||
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
|
||||
KbdCmdSend(KBD_PORT,0xF3);
|
||||
KbdCmdSend(KBD_PORT,delay); //Typematic rate
|
||||
KbdCmdSend(KBD_CTRL,0xA8); //Enable Mouse
|
||||
} catch {
|
||||
KbdCmdFlush;
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
I64 Char2ScanCode(I64 ch,I64 sc_flags=0)
|
||||
{//ASCII val to scan code (Slow).
|
||||
I64 i;
|
||||
U8 *table;
|
||||
if (sc_flags) {
|
||||
table=NORMAL_KEY_SCAN_DECODE_TABLE;
|
||||
if (sc_flags & SCF_CTRL || ch<26)
|
||||
table=CTRL_KEY_SCAN_DECODE_TABLE;
|
||||
else if (sc_flags & SCF_SHIFT || 'A'<=ch<='Z') {
|
||||
if (!(sc_flags & SCF_CAPS))
|
||||
table=SHIFT_KEY_SCAN_DECODE_TABLE;
|
||||
} else {
|
||||
if (sc_flags & SCF_CAPS)
|
||||
table=SHIFT_KEY_SCAN_DECODE_TABLE;
|
||||
}
|
||||
for (i=0;i<0x50;i++)
|
||||
if (table[i]==ch)
|
||||
return i|sc_flags;
|
||||
return sc_flags;
|
||||
} else {
|
||||
table=NORMAL_KEY_SCAN_DECODE_TABLE;
|
||||
for (i=0;i<0x50;i++)
|
||||
if (table[i]==ch)
|
||||
return i;
|
||||
table=SHIFT_KEY_SCAN_DECODE_TABLE;
|
||||
for (i=0;i<0x50;i++)
|
||||
if (table[i]==ch)
|
||||
return i|SCF_SHIFT;
|
||||
table=CTRL_KEY_SCAN_DECODE_TABLE;
|
||||
for (i=0;i<0x50;i++)
|
||||
if (table[i]==ch)
|
||||
return i|SCF_CTRL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
U8 ScanCode2Char(I64 sc)
|
||||
{//Scan code to ASCII val.
|
||||
U8 *table=NORMAL_KEY_SCAN_DECODE_TABLE;
|
||||
if (sc&SCF_E0_PREFIX)
|
||||
return 0;
|
||||
if (sc&SCF_CTRL)
|
||||
table=CTRL_KEY_SCAN_DECODE_TABLE;
|
||||
else if (sc&SCF_SHIFT) {
|
||||
if (!(sc&SCF_CAPS))
|
||||
table=SHIFT_KEY_SCAN_DECODE_TABLE;
|
||||
} else {
|
||||
if (sc&SCF_CAPS)
|
||||
table=SHIFT_KEY_SCAN_DECODE_TABLE;
|
||||
}
|
||||
sc&=0x7F;
|
||||
if (sc>=0x50)
|
||||
return 0;
|
||||
else
|
||||
return table[sc];
|
||||
}
|
||||
|
||||
U8 scan_code_map[0x100]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,SC_SHIFT,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,SC_ENTER,SC_CTRL,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0x35,0,0,SC_ALT,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,SC_HOME,
|
||||
SC_CURSOR_UP,SC_PAGE_UP,0,SC_CURSOR_LEFT,0,SC_CURSOR_RIGHT,0,SC_END,
|
||||
SC_CURSOR_DOWN,SC_PAGE_DOWN,SC_INS,SC_DELETE,0,0,0,0,
|
||||
0,0,0,0,SC_GUI,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
U8 num_lock_map[0x100]={
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,8,9,10,0,5,6,7,0,2,
|
||||
3,4,11,0x34,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,SC_ENTER,SC_CTRL,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0x35,0,0,SC_ALT,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,SC_HOME,
|
||||
SC_CURSOR_UP,SC_PAGE_UP,0,SC_CURSOR_LEFT,0,SC_CURSOR_RIGHT,0,SC_END,
|
||||
SC_CURSOR_DOWN,SC_PAGE_DOWN,SC_INS,SC_DELETE,0,0,0,0,
|
||||
0,0,0,0,SC_GUI,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
U8 *Char2KeyName(I64 ch,Bool include_ctrl=TRUE)
|
||||
{//ASCII val to key name.
|
||||
I64 i;
|
||||
U8 buf[STR_LEN];
|
||||
if (ch<=CH_SPACE) {
|
||||
switch [ch] {
|
||||
case '\n':
|
||||
StrCpy(buf,"ENTER");
|
||||
break;
|
||||
case CH_BACKSPACE:
|
||||
StrCpy(buf,"BACKSPACE");
|
||||
break;
|
||||
case '\t':
|
||||
StrCpy(buf,"TAB");
|
||||
break;
|
||||
case CH_ESC:
|
||||
StrCpy(buf,"ESC");
|
||||
break;
|
||||
case CH_SHIFT_ESC:
|
||||
StrCpy(buf,"SHIFT_ESC");
|
||||
break;
|
||||
case 0: //nobound switch
|
||||
case 29:
|
||||
case 30:
|
||||
*buf=0;
|
||||
break;
|
||||
case CH_SHIFT_SPACE:
|
||||
StrCpy(buf,"SHIFT_SPACE");
|
||||
break;
|
||||
case CH_SPACE:
|
||||
StrCpy(buf,"SPACE");
|
||||
break;
|
||||
default:
|
||||
if (include_ctrl)
|
||||
StrCpy(buf,"CTRL ");
|
||||
buf[i=StrLen(buf)]=ch-1+'a';
|
||||
buf[i+1]=0;
|
||||
break;
|
||||
}
|
||||
} else if (Bt(char_bmp_printable,ch)) {
|
||||
*buf=ch;
|
||||
buf[1]=0;
|
||||
} else
|
||||
*buf=0;
|
||||
return StrNew(buf);
|
||||
}
|
||||
|
||||
U8 *ScanCode2KeyName(I64 sc)
|
||||
{//Scan code to key name.
|
||||
I64 ch;
|
||||
U8 buf[STR_LEN],*st;
|
||||
*buf=0;
|
||||
if (sc&SCF_CTRL)
|
||||
CatPrint(buf,"CTRL ");
|
||||
if (sc&SCF_ALT)
|
||||
CatPrint(buf,"ALT ");
|
||||
if (sc&SCF_SHIFT)
|
||||
CatPrint(buf,"SHIFT ");
|
||||
if (sc&SCF_NO_SHIFT)
|
||||
CatPrint(buf," ");
|
||||
if (ch=ScanCode2Char(sc&255)) {
|
||||
st=Char2KeyName(ch,FALSE);
|
||||
StrCpy(buf+StrLen(buf),st);
|
||||
Free(st);
|
||||
} else {
|
||||
switch (sc&255) {
|
||||
case SC_BACKSPACE:CatPrint(buf,"BACK"); break;
|
||||
case SC_CAPS: CatPrint(buf,"CAPS"); break;
|
||||
case SC_NUM: CatPrint(buf,"NUM"); break;
|
||||
case SC_SCROLL: CatPrint(buf,"SCROLL"); break;
|
||||
case SC_CURSOR_UP:CatPrint(buf,"UP"); break;
|
||||
case SC_CURSOR_DOWN:CatPrint(buf,"DOWN"); break;
|
||||
case SC_CURSOR_LEFT:CatPrint(buf,"LEFT"); break;
|
||||
case SC_CURSOR_RIGHT:CatPrint(buf,"RIGHT"); break;
|
||||
case SC_PAGE_UP: CatPrint(buf,"PAGE_UP"); break;
|
||||
case SC_PAGE_DOWN:CatPrint(buf,"PAGE_DOWN");break;
|
||||
case SC_HOME: CatPrint(buf,"HOME"); break;
|
||||
case SC_END: CatPrint(buf,"END"); break;
|
||||
case SC_INS: CatPrint(buf,"INS"); break;
|
||||
case SC_DELETE: CatPrint(buf,"DELETE"); break;
|
||||
case SC_F1: CatPrint(buf,"F1"); break;
|
||||
case SC_F2: CatPrint(buf,"F2"); break;
|
||||
case SC_F3: CatPrint(buf,"F3"); break;
|
||||
case SC_F4: CatPrint(buf,"F4"); break;
|
||||
case SC_F5: CatPrint(buf,"F5"); break;
|
||||
case SC_F6: CatPrint(buf,"F6"); break;
|
||||
case SC_F7: CatPrint(buf,"F7"); break;
|
||||
case SC_F8: CatPrint(buf,"F8"); break;
|
||||
case SC_F9: CatPrint(buf,"F9"); break;
|
||||
case SC_F10: CatPrint(buf,"F10"); break;
|
||||
case SC_F11: CatPrint(buf,"F11"); break;
|
||||
case SC_F12: CatPrint(buf,"F12"); break;
|
||||
case SC_GUI: CatPrint(buf,"WINDOWS"); break;
|
||||
case SC_PRTSCRN1: CatPrint(buf,"PRTSCRN1"); break;
|
||||
case SC_PRTSCRN2: CatPrint(buf,"PRTSCRN2"); break;
|
||||
}
|
||||
}
|
||||
return StrNew(buf);
|
||||
}
|
||||
|
||||
U0 KbdBuildSC(U8 raw_byte,Bool in_irq,U8 *_last_raw_byte,I64 *_last_sc)
|
||||
{
|
||||
I64 ch,sc_flags,sc,sc2,sc_raw,new_key_f;
|
||||
Bool set_LEDs=FALSE;
|
||||
if (raw_byte==0xE0) {
|
||||
*_last_sc&=~0x1FF;
|
||||
*_last_raw_byte=raw_byte;
|
||||
return;
|
||||
}
|
||||
sc=raw_byte;
|
||||
BEqu(&sc,SCf_E0_PREFIX,*_last_raw_byte==0xE0);
|
||||
BEqu(&sc,SCf_KEY_UP,raw_byte & 0x80);
|
||||
*_last_raw_byte=raw_byte;
|
||||
|
||||
sc_flags=_last_sc->u32[0]&~0x1FF;
|
||||
sc_raw=sc;
|
||||
|
||||
if (sc_flags & SCF_NUM) {
|
||||
if (sc2=num_lock_map[sc.u8[0]])
|
||||
sc.u8[0]=sc2;
|
||||
} else {
|
||||
if (sc2=scan_code_map[sc.u8[0]])
|
||||
sc.u8[0]=sc2;
|
||||
}
|
||||
|
||||
new_key_f=SCF_NEW_KEY;
|
||||
if (sc&SCF_KEY_UP)
|
||||
switch (sc&~SCF_KEY_UP) {
|
||||
case SC_SHIFT: sc_flags&=~SCF_SHIFT; break;
|
||||
case SC_CTRL: sc_flags&=~SCF_CTRL; break;
|
||||
case SC_ALT: sc_flags&=~SCF_ALT; break;
|
||||
case SC_DELETE: sc_flags&=~SCF_DELETE; break;
|
||||
case SC_INS: sc_flags&=~SCF_INS; break;
|
||||
case SC_CAPS: sc_flags^=SCF_CAPS; set_LEDs=TRUE; break;
|
||||
case SC_NUM: sc_flags^=SCF_NUM; set_LEDs=TRUE; break;
|
||||
case SC_SCROLL: sc_flags^=SCF_SCROLL; set_LEDs=TRUE; break;
|
||||
}
|
||||
else
|
||||
switch (sc) {
|
||||
case SC_SHIFT:
|
||||
if (Bts(&sc_flags,SCf_SHIFT)) new_key_f=0;
|
||||
break;
|
||||
case SC_CTRL:
|
||||
if (Bts(&sc_flags,SCf_CTRL)) new_key_f=0;
|
||||
break;
|
||||
case SC_ALT:
|
||||
if (Bts(&sc_flags,SCf_ALT)) new_key_f=0;
|
||||
break;
|
||||
case SC_DELETE:
|
||||
sc_flags|=SCF_DELETE;
|
||||
break;
|
||||
case SC_INS:
|
||||
sc_flags|=SCF_INS;
|
||||
break;
|
||||
}
|
||||
|
||||
sc_flags|=new_key_f;
|
||||
sc=sc_flags|sc|(sc_flags|sc_raw)<<32;
|
||||
if (sc_flags & SCF_CTRL && sc_flags & SCF_ALT) {
|
||||
if (!(sc&SCF_KEY_UP)) {
|
||||
if (sc&255==SC_DELETE && !(sc_flags & SCF_SHIFT))
|
||||
CtrlAltDel(sc);
|
||||
else {
|
||||
if (sc&255==SC_ESC)
|
||||
ch='t';
|
||||
else if (sc&255==SC_TAB)
|
||||
ch='n';
|
||||
else
|
||||
ch=ScanCode2Char(sc&255);
|
||||
if ('a'<=ch<='z') {
|
||||
sc&=~(SCF_NEW_KEY|SCF_NEW_KEY<<32);
|
||||
ch-='a';
|
||||
kbd.last_down_scan_code=sc;
|
||||
if (keydev.fp_ctrl_alt_cbs[ch] &&
|
||||
Bt(&keydev.ctrl_alt_in_irq_flags,ch)==in_irq &&
|
||||
(!(sc_flags & SCF_SHIFT)&&keydev.ctrl_alt_no_shift_descs[ch]) ||
|
||||
sc_flags & SCF_SHIFT && keydev.ctrl_alt_shift_descs[ch])
|
||||
(*keydev.fp_ctrl_alt_cbs[ch])(sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (set_LEDs && !in_irq)
|
||||
KbdLEDsSet(sc);
|
||||
*_last_sc=sc;
|
||||
}
|
||||
|
||||
U0 KbdPktRead()
|
||||
{
|
||||
static U8 last_raw_byte=0;
|
||||
static I64 last_sc=0;
|
||||
U8 raw_byte;
|
||||
if (GetTSC>kbd.timestamp+cnts.time_stamp_freq>>3)
|
||||
FifoU8Flush(kbd.fifo);
|
||||
kbd.timestamp=GetTSC;
|
||||
raw_byte=InU8(KBD_PORT);
|
||||
KbdBuildSC(raw_byte,TRUE,&last_raw_byte,&last_sc);
|
||||
if (!FifoU8Cnt(kbd.fifo)) {
|
||||
FifoU8Ins(kbd.fifo,raw_byte);
|
||||
if (raw_byte!=0xE0) {
|
||||
while (FifoU8Rem(kbd.fifo,&raw_byte))
|
||||
FifoU8Ins(kbd.fifo2,raw_byte);
|
||||
}
|
||||
} else {
|
||||
FifoU8Ins(kbd.fifo,raw_byte);
|
||||
while (FifoU8Rem(kbd.fifo,&raw_byte))
|
||||
FifoU8Ins(kbd.fifo2,raw_byte);
|
||||
}
|
||||
}
|
||||
|
||||
interrupt U0 IRQKbd()
|
||||
{
|
||||
CLD
|
||||
OutU8(0x20,0x20);
|
||||
kbd.irqs_working=TRUE;
|
||||
if (ms_hard.install_in_progress) {
|
||||
kbd.rst=TRUE;
|
||||
return;
|
||||
}
|
||||
keydev.ctrl_alt_ret_addr=GetRBP()(I64)+8;
|
||||
KbdPktRead;
|
||||
}
|
||||
|
||||
U0 KbdInit()
|
||||
{
|
||||
try {
|
||||
KbdCmdFlush;
|
||||
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
|
||||
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
|
||||
KbdCmdSend(KBD_PORT,0xF0);
|
||||
KbdCmdSend(KBD_PORT,0x02);
|
||||
KbdLEDsSet(kbd.scan_code);
|
||||
} catch {
|
||||
KbdCmdFlush;
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
IntEntrySet(0x21,&IRQKbd);
|
||||
OutU8(0x21,InU8(0x21)&~2);
|
||||
}
|
||||
|
||||
U0 KbdHndlr()
|
||||
{
|
||||
static U8 last_raw_byte=0;
|
||||
U8 raw_byte;
|
||||
FifoU8Rem(kbd.fifo2,&raw_byte);
|
||||
KbdBuildSC(raw_byte,FALSE,&last_raw_byte,&kbd.scan_code);
|
||||
if (raw_byte==0xE0) {
|
||||
FifoU8Rem(kbd.fifo2,&raw_byte);
|
||||
KbdBuildSC(raw_byte,FALSE,&last_raw_byte,&kbd.scan_code);
|
||||
}
|
||||
if (Btr(&kbd.scan_code,SCf_NEW_KEY)) {
|
||||
kbd.new_key_timestamp=kbd.timestamp;
|
||||
Btr(&kbd.scan_code,32+SCf_NEW_KEY);
|
||||
FifoI64Ins(kbd.scan_code_fifo,kbd.scan_code);
|
||||
kbd.cnt++;
|
||||
if (!(kbd.scan_code&SCF_KEY_UP)) {
|
||||
kbd.last_down_scan_code=kbd.scan_code;
|
||||
Bts(kbd.down_bitmap,kbd.scan_code.u8[0]);
|
||||
Bts(kbd.down_bitmap2,kbd.scan_code.u8[4]);
|
||||
} else {
|
||||
Btr(kbd.down_bitmap,kbd.scan_code.u8[0]);
|
||||
Btr(kbd.down_bitmap2,kbd.scan_code.u8[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I64 KbdMsgsQue()
|
||||
{
|
||||
I64 arg1,arg2,msg_code=MSG_NULL;
|
||||
CTask *task_focus;
|
||||
if (task_focus=sys_focus_task) {
|
||||
while (FifoI64Rem(kbd.scan_code_fifo,&arg2)) {
|
||||
arg1=ScanCode2Char(arg2);
|
||||
if (arg2 & SCF_KEY_UP) {
|
||||
TaskMsg(task_focus,0,MSG_KEY_UP,arg1,arg2,0);
|
||||
msg_code=MSG_KEY_UP;
|
||||
} else {
|
||||
TaskMsg(task_focus,0,MSG_KEY_DOWN,arg1,arg2,0);
|
||||
msg_code=MSG_KEY_DOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
return msg_code;
|
||||
}
|
||||
|
||||
I64 KbdMsEvtTime()
|
||||
{//Timestamp of last key or mouse event.
|
||||
if (ms_hard.timestamp>kbd.timestamp)
|
||||
return ms_hard.timestamp;
|
||||
else
|
||||
return kbd.new_key_timestamp;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#exe {Cd(__DIR__);};
|
||||
#include "Keyboard"
|
||||
#include "Mouse"
|
||||
#include "Message"
|
||||
#exe {Cd("..");};
|
||||
@@ -0,0 +1,244 @@
|
||||
U0 InputFilterTask()
|
||||
{
|
||||
CJob *tmpc,*tmpc1;
|
||||
Bool old_filter;
|
||||
I64 old_flags=GetRFlags;
|
||||
Fs->win_inhibit=WIG_USER_TASK_DFT;
|
||||
LBts(&Fs->task_flags,TASKf_INPUT_FILTER_TASK);
|
||||
old_filter=LBts(&Fs->last_input_filter_task->task_flags,TASKf_FILTER_INPUT);
|
||||
LBEqu(&Fs->task_flags,TASKf_FILTER_INPUT,old_filter);
|
||||
while (TRUE) {
|
||||
CLI
|
||||
JobsHndlr(old_flags);
|
||||
tmpc1=&Fs->srv_ctrl.next_waiting;
|
||||
tmpc=tmpc1->next;
|
||||
if (tmpc==tmpc1)
|
||||
break;
|
||||
else {
|
||||
if (tmpc->job_code==JOBT_TEXT_INPUT) {
|
||||
QueRem(tmpc);
|
||||
SetRFlags(old_flags);
|
||||
try
|
||||
ExePrint("%s",tmpc->aux_str);
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
JobDel(tmpc);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
Fs->next_input_filter_task->last_input_filter_task=Fs->last_input_filter_task;
|
||||
Fs->last_input_filter_task->next_input_filter_task=Fs->next_input_filter_task;
|
||||
if (!old_filter)
|
||||
LBtr(&Fs->last_input_filter_task->task_flags,TASKf_FILTER_INPUT);
|
||||
SetRFlags(old_flags);
|
||||
}
|
||||
|
||||
I64 ScanMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,I64 mask=~1,CTask *task=NULL)
|
||||
{/*Check for a message of type specified by a one in the mask.
|
||||
Throw-out messages not in mask.
|
||||
If no message fit mask, return NULL immediately.
|
||||
Remove desired message, return $LK,"msg_code",A="MN:MSG_CMD"$.
|
||||
Note: This delivers messages from parent down to pop-up.
|
||||
*/
|
||||
I64 res,old_flags;
|
||||
CJob *tmpc,*tmpc1;
|
||||
if (!task) task=Fs;
|
||||
old_flags=GetRFlags;
|
||||
tmpc1=&task->srv_ctrl.next_waiting;
|
||||
while (TRUE) {
|
||||
CLI
|
||||
if (task==Fs)
|
||||
JobsHndlr(old_flags);
|
||||
tmpc=tmpc1->next;
|
||||
if (tmpc==tmpc1)
|
||||
break;
|
||||
else {
|
||||
if (tmpc->job_code==JOBT_MSG) {
|
||||
QueRem(tmpc);
|
||||
SetRFlags(old_flags);
|
||||
res=tmpc->msg_code;
|
||||
if (_arg1)
|
||||
*_arg1=tmpc->aux1;
|
||||
if (_arg2)
|
||||
*_arg2=tmpc->aux2;
|
||||
JobDel(tmpc);
|
||||
if ((res!=MSG_KEY_DOWN || !(tmpc->aux2&SCF_KEY_DESC) ||
|
||||
!Bt(&task->win_inhibit,WIf_SELF_KEY_DESC)) && Bt(&mask,res))
|
||||
goto sm_done;
|
||||
}
|
||||
}
|
||||
SetRFlags(old_flags);
|
||||
}
|
||||
res=MSG_NULL;
|
||||
if (_arg1)
|
||||
*_arg1=0;
|
||||
if (_arg2)
|
||||
*_arg2=0;
|
||||
if (task->parent_task&&task->parent_task->popup_task==task) {
|
||||
SetRFlags(old_flags);
|
||||
return ScanMsg(_arg1,_arg2,mask,task->parent_task);
|
||||
}
|
||||
sm_done:
|
||||
SetRFlags(old_flags);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 FlushMsgs(CTask *task=NULL)
|
||||
{//Throw away all messages. Return count.
|
||||
I64 res=0,arg1,arg2;
|
||||
while (ScanMsg(&arg1,&arg2,~1,task))
|
||||
res++;
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 GetMsg(I64 *_arg1=NULL,I64 *_arg2=NULL,I64 mask=~1,CTask *task=NULL)
|
||||
{//Wait for a message of type specified by a one in the mask.
|
||||
//Throw-out all messages not in mask.
|
||||
//Returns $LK,"msg_code",A="MN:MSG_CMD"$. See $LK,"::/Demo/MsgLoop.HC"$.
|
||||
I64 res;
|
||||
if (!task) task=Fs;
|
||||
LBtr(&task->task_flags,TASKf_IDLE);
|
||||
while (!(res=ScanMsg(_arg1,_arg2,mask,task))) {
|
||||
LBts(&task->task_flags,TASKf_IDLE);
|
||||
Yield;
|
||||
}
|
||||
LBtr(&task->task_flags,TASKf_IDLE);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 ScanChar()
|
||||
{//Checks for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ and returns 0 immediately if no key.
|
||||
//Waits for $LK,"MSG_KEY_UP",A="MN:MSG_KEY_UP"$ of non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key and returns $LK,"ASCII",A="MN:CH_CTRLA"$ if key.
|
||||
//$LK,"ScanMsg",A="MN:ScanMsg"$() throws away other message types.
|
||||
I64 arg1a,arg2a,arg1b,arg2b;
|
||||
if (!ScanMsg(&arg1a,&arg2a,1<<MSG_KEY_DOWN)||!arg1a)
|
||||
return 0;
|
||||
else
|
||||
do GetMsg(&arg1b,&arg2b,1<<MSG_KEY_UP);
|
||||
while (!arg1b); //Be careful of $LK,"SC_SHIFT",A="MN:SC_SHIFT"$ and $LK,"SC_CTRL",A="MN:SC_CTRL"$, etc.
|
||||
return arg1a;
|
||||
}
|
||||
|
||||
Bool ScanKey(I64 *_ch=NULL,I64 *_scan_code=NULL,Bool echo=FALSE)
|
||||
{//Checks for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ and returns FALSE immediately if no key.
|
||||
//Sets $LK,"ASCII",A="MN:CH_CTRLA"$ and $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
|
||||
//Removes key message and returns TRUE.
|
||||
//$LK,"ScanMsg",A="MN:ScanMsg"$() throws away other message types.
|
||||
I64 ch=0,sc=0;
|
||||
if (ScanMsg(&ch,&sc,1<<MSG_KEY_DOWN)) {
|
||||
if (_ch) *_ch=ch;
|
||||
if (_scan_code) *_scan_code=sc;
|
||||
if (echo)
|
||||
PutKey(ch,sc);
|
||||
return TRUE;
|
||||
} else {
|
||||
if (_ch) *_ch=0;
|
||||
if (_scan_code) *_scan_code=0;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
I64 GetKey(I64 *_scan_code=NULL,Bool echo=FALSE,Bool raw_cursor=FALSE)
|
||||
{//Waits for $LK,"MSG_KEY_DOWN",A="MN:MSG_KEY_DOWN"$ message and returns $LK,"ASCII",A="MN:CH_CTRLA"$.
|
||||
//Sets $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
|
||||
//$LK,"ScanKey",A="MN:ScanKey"$() throws away other message types.
|
||||
I64 ch,sc;
|
||||
Bool cursor_on=FALSE;
|
||||
while (!ScanKey(&ch,&sc,FALSE)) {
|
||||
if (IsRaw && raw_cursor) {
|
||||
if (!cursor_on && ToI64(GetTSC*5/cnts.time_stamp_freq)&1) {
|
||||
'Û';
|
||||
cursor_on=TRUE;
|
||||
} else if (cursor_on && !(ToI64(GetTSC*5/cnts.time_stamp_freq)&1)) {
|
||||
'' CH_BACKSPACE;
|
||||
cursor_on=FALSE;
|
||||
}
|
||||
}
|
||||
LBts(&Fs->task_flags,TASKf_IDLE);
|
||||
if (IsDbgMode) {
|
||||
//We don't want interrupt-driven keyboard when in debugger
|
||||
//because that could have side-effects or crash, so we poll
|
||||
//keyboard when in debugger with interrupts off.
|
||||
PUSHFD
|
||||
CLI
|
||||
KbdMsHndlr(TRUE,FALSE);
|
||||
KbdMsgsQue;
|
||||
POPFD
|
||||
} else {
|
||||
LBts(&Fs->task_flags,TASKf_AWAITING_MSG);
|
||||
Yield;
|
||||
}
|
||||
LBtr(&Fs->task_flags,TASKf_IDLE);
|
||||
}
|
||||
if (IsRaw && raw_cursor && cursor_on)
|
||||
'' CH_BACKSPACE;
|
||||
if (echo)
|
||||
PutKey(ch,sc);
|
||||
if (_scan_code) *_scan_code=sc;
|
||||
return ch;
|
||||
}
|
||||
|
||||
I64 GetChar(I64 *_scan_code=NULL,Bool echo=TRUE,Bool raw_cursor=FALSE)
|
||||
{//Waits for non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key.
|
||||
//Sets $LK,"scan_code",A="FI:::/Doc/CharOverview.DD"$.
|
||||
I64 ch1;
|
||||
do ch1=GetKey(_scan_code,FALSE,raw_cursor);
|
||||
while (!ch1);
|
||||
if (echo)
|
||||
"$$PT$$%c$$FG$$",ch1;
|
||||
return ch1;
|
||||
}
|
||||
|
||||
U8 *GetStr(U8 *msg=NULL,U8 *dft=NULL,I64 flags=0)
|
||||
{//Returns a $LK,"MAlloc",A="MN:MAlloc"$()ed prompted string. See $LK,"Flags",A="MN:GSF_SHIFT_ESC_EXIT"$.
|
||||
U8 *st;
|
||||
if (msg)
|
||||
"" msg,dft;
|
||||
st=(*fp_getstr2)(flags);
|
||||
if (!*st) {
|
||||
Free(st);
|
||||
if (dft)
|
||||
return StrNew(dft);
|
||||
else
|
||||
return StrNew("");
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
I64 GetS(U8 *buf,I64 size,Bool allow_ext=TRUE)
|
||||
{//Prompt into fixed length string. Size must include terminator.
|
||||
U8 *st;
|
||||
I64 ch,i=0;
|
||||
if (!size || !buf) return 0;
|
||||
if (allow_ext) {
|
||||
st=GetStr;
|
||||
if (StrLen(st)>size-1) {
|
||||
MemCpy(buf,st,size-1);
|
||||
buf[size-1]=0;
|
||||
} else
|
||||
StrCpy(buf,st);
|
||||
i=StrLen(buf);
|
||||
Free(st);
|
||||
} else {
|
||||
while (TRUE) {
|
||||
ch=GetChar(,FALSE,IsDbgMode);
|
||||
if (ch=='\n') {
|
||||
'' ch;
|
||||
break;
|
||||
} else if (ch==CH_BACKSPACE) {
|
||||
if (i>0) {
|
||||
i--;
|
||||
'' ch;
|
||||
}
|
||||
} else {
|
||||
if (i<size-1) {
|
||||
buf[i++]=ch;
|
||||
'' ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf[i]=0;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
U0 GridInit()
|
||||
{//Init mouse grid struct. See $LK,"::/Demo/Graphics/Grid.HC"$.
|
||||
ms_grid.x=ms_grid.y=ms_grid.z=8;
|
||||
ms_grid.x_offset=ms_grid.y_offset=ms_grid.z_offset=0;
|
||||
ms_grid.x_speed =ms_grid.y_speed =ms_grid.z_speed =1;
|
||||
ms_grid.show=ms_grid.snap=ms_grid.coord=FALSE;
|
||||
}
|
||||
|
||||
U0 MsUpdate(I64 x,I64 y,I64 z,Bool l,Bool r)
|
||||
{
|
||||
ms.presnap.x=ToI64(ms.scale.x*x)+ms.offset.x;
|
||||
ms.presnap.y=ToI64(ms.scale.y*y)+ms.offset.y;
|
||||
ms.presnap.z=ToI64(ms.scale.z*z)+ms.offset.z;
|
||||
if (ms_grid.snap) {
|
||||
ms.pos.x=Trunc(ms.presnap.x/ms_grid.x)*ms_grid.x+ms_grid.x_offset;
|
||||
ms.pos.y=Trunc(ms.presnap.y/ms_grid.y)*ms_grid.y+ms_grid.y_offset;
|
||||
ms.pos.z=Trunc(ms.presnap.z/ms_grid.z)*ms_grid.z+ms_grid.z_offset;
|
||||
} else {
|
||||
ms.pos.x=ms.presnap.x;
|
||||
ms.pos.y=ms.presnap.y;
|
||||
ms.pos.z=ms.presnap.z;
|
||||
}
|
||||
|
||||
ms.pos.x=ClampI64(ms.pos.x,0,GR_WIDTH-1);
|
||||
ms.pos.y=ClampI64(ms.pos.y,0,GR_HEIGHT-1);
|
||||
ms.pos_text.x=ms.pos.x/FONT_WIDTH;
|
||||
if (ms.pos_text.x>=text.cols) {
|
||||
ms.pos_text.x=text.cols-1;
|
||||
ms.pos.x=text.cols*FONT_WIDTH-1;
|
||||
}
|
||||
ms.pos_text.y=ms.pos.y/FONT_HEIGHT;
|
||||
if (ms.pos_text.y>=text.rows) {
|
||||
ms.pos_text.y=text.rows-1;
|
||||
ms.pos.y=text.rows*FONT_HEIGHT-1;
|
||||
}
|
||||
ms.lb=l;
|
||||
ms.rb=r;
|
||||
LBEqu(&kbd.scan_code,SCf_MS_L_DOWN,ms.lb);
|
||||
LBEqu(&kbd.scan_code,SCf_MS_R_DOWN,ms.rb);
|
||||
}
|
||||
|
||||
U0 MsSet(I64 x=I64_MAX,I64 y=I64_MAX,I64 z=I64_MAX,I64 l=I64_MAX,I64 r=I64_MAX)
|
||||
{//Note: Generates a message. See $LK,"MsSet",A="FF:::/Demo/Games/Zing.HC,MsSet"$().
|
||||
if (!(0<=x<GR_WIDTH))
|
||||
x=ms.pos.x;
|
||||
if (!(0<=y<GR_HEIGHT))
|
||||
y=ms.pos.y;
|
||||
if (z==I64_MAX)
|
||||
z=ms.pos.z;
|
||||
|
||||
if (!(FALSE<=l<=TRUE))
|
||||
l=ms.lb;
|
||||
if (!(FALSE<=r<=TRUE))
|
||||
r=ms.rb;
|
||||
|
||||
x=(x-ms.offset.x)/ms.scale.x;
|
||||
y=(y-ms.offset.y)/ms.scale.y;
|
||||
z=(z-ms.offset.z)/ms.scale.z;
|
||||
MsUpdate(x,y,z,l,r);
|
||||
MsHardSet(x,y,z,l,r);
|
||||
}
|
||||
|
||||
U0 MsInit()
|
||||
{
|
||||
MemSet(&ms,0,sizeof(CMsStateGlbls));
|
||||
MemSet(&ms_last,0,sizeof(CMsStateGlbls));
|
||||
ms.offset.x=ms.offset.y=ms.offset.z=0;
|
||||
ms.scale.x=ms.scale.y=ms.scale.z=1.0;
|
||||
ms.pos_text.x=ms.pos_text.y=ms.pos_text.z=0;
|
||||
ms.has_wheel=FALSE;
|
||||
ms.show=TRUE;
|
||||
ms.speed=0;
|
||||
ms.timestamp=GetTSC;
|
||||
ms.dbl_time=0.350;
|
||||
GridInit;
|
||||
}
|
||||
|
||||
U0 MsHardPktRead()
|
||||
{
|
||||
U8 j;
|
||||
if (GetTSC>ms_hard.timestamp+cnts.time_stamp_freq>>3)
|
||||
FifoU8Flush(ms_hard.fifo);
|
||||
ms_hard.timestamp=GetTSC;
|
||||
FifoU8Ins(ms_hard.fifo,InU8(KBD_PORT));
|
||||
if (FifoU8Cnt(ms_hard.fifo)==ms_hard.pkt_size)
|
||||
while (FifoU8Rem(ms_hard.fifo,&j))
|
||||
FifoU8Ins(ms_hard.fifo2,j);
|
||||
}
|
||||
|
||||
interrupt U0 IRQMsHard()
|
||||
{
|
||||
CLD
|
||||
OutU8(0xA0,0x20);
|
||||
OutU8(0x20,0x20);
|
||||
ms_hard.irqs_working=TRUE;
|
||||
if (ms_hard.install_in_progress || !ms_hard.installed) {
|
||||
kbd.rst=TRUE;
|
||||
return;
|
||||
}
|
||||
MsHardPktRead;
|
||||
}
|
||||
|
||||
U0 MsHardGetType()
|
||||
{
|
||||
I64 b;
|
||||
KbdMsCmdAck(0xF2);
|
||||
b=KbdCmdRead;
|
||||
if (b==3)
|
||||
ms_hard.has_wheel=TRUE;
|
||||
else if (b==4)
|
||||
ms_hard.has_ext_bttns=TRUE;
|
||||
}
|
||||
|
||||
Bool MsHardRst()
|
||||
{
|
||||
U8 b,*_b;
|
||||
F64 timeout;
|
||||
Bool res=FALSE;
|
||||
|
||||
ms_hard.has_wheel=FALSE;
|
||||
ms_hard.has_ext_bttns=FALSE;
|
||||
|
||||
if (*0x40E(U16 *)==0x9FC0) {
|
||||
_b=0x9FC00+0x30;
|
||||
*_b=1; //This enables my mouse. It might be for one machine.
|
||||
//USB DMA packets, set-up by BIOS to make legacy PS/2?
|
||||
}
|
||||
|
||||
try {
|
||||
KbdCmdFlush;
|
||||
KbdCmdSend(KBD_CTRL,0xAD); //Disable Kbd
|
||||
KbdCmdSend(KBD_CTRL,0xA8); //Enable Mouse
|
||||
|
||||
KbdMsCmdAck(0xFF); //Rst
|
||||
|
||||
timeout=tS+10.0;
|
||||
do
|
||||
try {
|
||||
KbdCmdRead;
|
||||
timeout=0; //force exit
|
||||
} catch
|
||||
Fs->catch_except=TRUE;
|
||||
while (tS<timeout);
|
||||
|
||||
try
|
||||
KbdCmdRead;
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
|
||||
KbdMsCmdAck(0xF3,200,0xF3,100,0xF3,80);
|
||||
MsHardGetType;
|
||||
KbdMsCmdAck(0xF3,10);
|
||||
MsHardGetType;
|
||||
KbdMsCmdAck(0xE8,0x03,0xE6,0xF3,100,0xF4);
|
||||
res=TRUE;
|
||||
|
||||
//Enable IRQ 12
|
||||
KbdCmdSend(KBD_CTRL,0x20);
|
||||
b=KbdCmdRead;
|
||||
KbdCmdSend(KBD_CTRL,0x60);
|
||||
KbdCmdSend(KBD_PORT,(b|2)&~0x20);
|
||||
|
||||
} catch
|
||||
Fs->catch_except=TRUE;
|
||||
|
||||
//This is been added to override failure
|
||||
//because the mouse sometimes still works.
|
||||
res=TRUE;
|
||||
|
||||
try
|
||||
KbdCmdSend(KBD_CTRL,0xAE); //Enable Keyboard
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
if (ms_hard.has_wheel || ms_hard.has_ext_bttns)
|
||||
ms_hard.pkt_size=4;
|
||||
else
|
||||
ms_hard.pkt_size=3;
|
||||
if (!res)
|
||||
try
|
||||
KbdCmdSend(KBD_CTRL,0xA7); //Disable Mouse
|
||||
catch
|
||||
Fs->catch_except=TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 MsHardSpeedSet()
|
||||
{
|
||||
I64 dd,tmp;
|
||||
if ((dd=SqrI64(ms_hard_last.pos.x-ms_hard.pos.x)
|
||||
+SqrI64(ms_hard_last.pos.y-ms_hard.pos.y)) &&
|
||||
(tmp=ms_hard.timestamp-ms_hard_last.timestamp))
|
||||
ms_hard.speed=Sqrt(dd)*cnts.time_stamp_freq/tmp;
|
||||
ms_hard_last.timestamp=ms_hard.timestamp;
|
||||
}
|
||||
|
||||
U0 MsHardSetPre()
|
||||
{
|
||||
I64 old_timestamp=ms_hard_last.timestamp;
|
||||
MemCpy(&ms_hard_last,&ms_hard,sizeof(CMsHardStateGlbls));
|
||||
ms_hard_last.timestamp=old_timestamp;
|
||||
}
|
||||
|
||||
U0 MsHardSetPost()
|
||||
{
|
||||
I64 i;
|
||||
ms_hard.pos.x=ms_hard.prescale.x*ms_hard.scale.x*ms_grid.x_speed;
|
||||
ms_hard.pos.y=ms_hard.prescale.y*ms_hard.scale.y*ms_grid.y_speed;
|
||||
ms_hard.pos.z=ms_hard.prescale.z*ms_hard.scale.z*ms_grid.z_speed;
|
||||
|
||||
i=Trunc(ms.scale.x*ms_hard.pos.x/ms_grid.x)*ms_grid.x+ms.offset.x;
|
||||
//TODO ms_grid.x_offset?
|
||||
if (i<0)
|
||||
ms.offset.x-=i;
|
||||
else if (i>=GR_WIDTH)
|
||||
ms.offset.x+=GR_WIDTH-1-i;
|
||||
|
||||
i=Trunc(ms.scale.y*ms_hard.pos.y/ms_grid.y)*ms_grid.y+ms.offset.y;
|
||||
if (i<0)
|
||||
ms.offset.y-=i;
|
||||
else if (i>=GR_HEIGHT)
|
||||
ms.offset.y+=GR_HEIGHT-1-i;
|
||||
|
||||
if (ms_hard.pos.x!=ms_hard_last.pos.x || ms_hard.pos.y!=ms_hard_last.pos.y ||
|
||||
ms_hard.pos.z!=ms_hard_last.pos.z) {
|
||||
ms_hard.evt=TRUE;
|
||||
MsHardSpeedSet;
|
||||
} else
|
||||
for (i=0;i<5;i++)
|
||||
if (ms_hard.bttns[i]!=ms_hard_last.bttns[i]) {
|
||||
ms_hard.evt=TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 MsHardHndlr()
|
||||
{
|
||||
I64 i,dx,dy,dz;
|
||||
U8 ms_buf[4];
|
||||
|
||||
MsHardSetPre;
|
||||
for (i=0;i<4;i++)
|
||||
ms_buf[i]=0;
|
||||
for (i=0;i<ms_hard.pkt_size;i++)
|
||||
if (!FifoU8Rem(ms_hard.fifo2,&ms_buf[i]))
|
||||
ms_buf[i]=0;
|
||||
|
||||
ms_hard.bttns[0] = ms_buf[0] & 1;
|
||||
ms_hard.bttns[1] = (ms_buf[0] & 2) >> 1;
|
||||
ms_hard.bttns[2] = (ms_buf[0] & 4) >> 2;
|
||||
ms_hard.bttns[3] = (ms_buf[3] & 0x10) >> 4;
|
||||
ms_hard.bttns[4] = (ms_buf[3] & 0x20) >> 5;
|
||||
if (ms_buf[0] & 0x10)
|
||||
dx=ms_buf[1]-256;
|
||||
else
|
||||
dx=ms_buf[1];
|
||||
if (ms_buf[0] & 0x20)
|
||||
dy=256-ms_buf[2];
|
||||
else
|
||||
dy=-ms_buf[2];
|
||||
if (ms_buf[3] & 0x08)
|
||||
dz=ms_buf[3]&7-8;
|
||||
else
|
||||
dz=ms_buf[3]&7;
|
||||
|
||||
ms_hard.prescale.x+=dx;
|
||||
ms_hard.prescale.y+=dy;
|
||||
ms_hard.prescale.z+=dz;
|
||||
|
||||
MsHardSetPost;
|
||||
}
|
||||
|
||||
U0 MsHardSet(I64 x,I64 y,I64 z,I64 l,I64 r)
|
||||
{
|
||||
ms_hard.timestamp=GetTSC;
|
||||
MsHardSetPre;
|
||||
ms_hard.prescale.x=x/ms_hard.scale.x/ms_grid.x_speed;
|
||||
ms_hard.prescale.y=y/ms_hard.scale.y/ms_grid.y_speed;
|
||||
ms_hard.prescale.z=z/ms_hard.scale.z/ms_grid.z_speed;
|
||||
ms_hard.bttns[0]=l;
|
||||
ms_hard.bttns[1]=r;
|
||||
MsHardSetPost;
|
||||
}
|
||||
|
||||
U0 KbdMsRst()
|
||||
{
|
||||
KbdCmdFlush;
|
||||
FifoU8Flush(kbd.fifo2);
|
||||
FifoU8Flush(ms_hard.fifo2);
|
||||
FifoI64Flush(kbd.scan_code_fifo);
|
||||
kbd.scan_code=0;
|
||||
kbd.rst=FALSE;
|
||||
}
|
||||
|
||||
Bool MsHardDrvrInstall(I64 dummy=0) //can be spawned
|
||||
{
|
||||
no_warn dummy;
|
||||
I64 i;
|
||||
ms_hard.install_in_progress=TRUE;
|
||||
OutU8(0xA1,InU8(0xA1)|0x10);
|
||||
ms_hard.installed=ms_hard.irqs_working=FALSE;
|
||||
IntEntrySet(0x2C,&IRQMsHard);
|
||||
for(i=0;i<5;i++)
|
||||
ms_hard.bttns[i]=0;
|
||||
if (i=MsHardRst)
|
||||
OutU8(0xA1,InU8(0xA1)&~0x10);
|
||||
KbdMsRst;
|
||||
ms_hard.install_attempts++;
|
||||
ms_hard.installed=ms_hard.evt=i;
|
||||
ms_hard.install_in_progress=FALSE;
|
||||
return ms_hard.installed;
|
||||
}
|
||||
|
||||
U0 KbdMsHndlr(Bool poll_kbd,Bool poll_ms)
|
||||
{
|
||||
if (ms_hard.install_in_progress) {
|
||||
Yield;
|
||||
return;
|
||||
}
|
||||
if (kbd.rst)
|
||||
KbdMsRst;
|
||||
else {
|
||||
if (poll_ms && ms_hard.installed && !ms_hard.irqs_working) {
|
||||
PUSHFD
|
||||
CLI
|
||||
while (InU8(KBD_CTRL)&1)
|
||||
MsHardPktRead;
|
||||
POPFD
|
||||
}
|
||||
|
||||
if (poll_kbd)
|
||||
while (InU8(KBD_CTRL)&1)
|
||||
KbdPktRead;
|
||||
|
||||
if (kbd.rst)
|
||||
KbdMsRst;
|
||||
else {
|
||||
while (FifoU8Cnt(kbd.fifo2))
|
||||
KbdHndlr;
|
||||
while (FifoU8Cnt(ms_hard.fifo2))
|
||||
if (ms_hard.installed)
|
||||
MsHardHndlr;
|
||||
else
|
||||
KbdMsRst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 KbdMsInit()
|
||||
{
|
||||
MemSet(&kbd,0,sizeof(CKbdStateGlbls));
|
||||
kbd.fifo=FifoU8New(8);
|
||||
kbd.fifo2=FifoU8New(0x1000);
|
||||
kbd.scan_code_fifo=FifoI64New(0x1000);
|
||||
kbd.irqs_working=FALSE;
|
||||
MemSet(&ms_hard,0,sizeof(CMsHardStateGlbls));
|
||||
ms_hard.fifo=FifoU8New(8);
|
||||
ms_hard.fifo2=FifoU8New(0x1000);
|
||||
ms_hard.scale.x=0.5;
|
||||
ms_hard.scale.y=0.5;
|
||||
ms_hard.scale.z=1.0;
|
||||
ms_hard.prescale.x=GR_WIDTH/ms_hard.scale.x/2.0;
|
||||
ms_hard.prescale.y=GR_HEIGHT/ms_hard.scale.y/2.0;
|
||||
ms_hard.prescale.z=0/ms_hard.scale.z;
|
||||
ms_hard.pos.x=GR_WIDTH>>1;
|
||||
ms_hard.pos.y=GR_HEIGHT>>1;
|
||||
MemCpy(&ms_hard_last,&ms_hard,sizeof(CMsHardStateGlbls));
|
||||
}
|
||||
@@ -0,0 +1,686 @@
|
||||
U8 *StrPrintHex(U8 *dst,I64 num;I64 width)
|
||||
{
|
||||
U8 *res=dst+width;
|
||||
dst=res;
|
||||
while (width--) {
|
||||
*--dst="0123456789ABCDEF"(U8 *)[num&15];
|
||||
num>>=4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 PutHex(I64 num,I64 width)
|
||||
{
|
||||
U8 buf[17];
|
||||
if (width>16) width=16;
|
||||
*StrPrintHex(buf,num,width)=0;
|
||||
"%s",buf;
|
||||
}
|
||||
|
||||
asm {
|
||||
// IN: RAX=NUM TO PRINT
|
||||
PUT_HEX_U64::
|
||||
PUSH_C_REGS
|
||||
PUSH 16
|
||||
PUSH RAX
|
||||
CALL &PutHex
|
||||
POP_C_REGS
|
||||
RET
|
||||
PUT_HEX_U32::
|
||||
PUSH_C_REGS
|
||||
PUSH 8
|
||||
PUSH RAX
|
||||
CALL &PutHex
|
||||
POP_C_REGS
|
||||
RET
|
||||
PUT_HEX_U16::
|
||||
PUSH_C_REGS
|
||||
PUSH 4
|
||||
PUSH RAX
|
||||
CALL &PutHex
|
||||
POP_C_REGS
|
||||
RET
|
||||
PUT_HEX_U8::
|
||||
PUSH_C_REGS
|
||||
PUSH 2
|
||||
PUSH RAX
|
||||
CALL &PutHex
|
||||
POP_C_REGS
|
||||
RET
|
||||
PUT_CHARS::
|
||||
// IN: RAX=Char
|
||||
PUSH_C_REGS
|
||||
PUSH RAX
|
||||
CALL &PutChars
|
||||
POP_C_REGS
|
||||
RET
|
||||
PUT_STR::
|
||||
// IN: RSI=String
|
||||
PUSH_C_REGS
|
||||
PUSH RSI
|
||||
CALL &PutS
|
||||
POP_C_REGS
|
||||
RET
|
||||
_STRCPY::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
TEST RDI,RDI
|
||||
JZ @@15
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
TEST RSI,RSI
|
||||
JNZ @@05
|
||||
XOR RAX,RAX
|
||||
JMP @@10
|
||||
@@05: LODSB
|
||||
@@10: STOSB
|
||||
TEST AL,AL
|
||||
JNZ @@05
|
||||
@@15: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_STRCMP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
@@05: LODSB
|
||||
TEST AL,AL
|
||||
JZ @@20
|
||||
SCASB
|
||||
JE @@05
|
||||
JA @@15
|
||||
@@10: MOV RAX,1
|
||||
JMP @@25
|
||||
@@15: MOV RAX,-1
|
||||
JMP @@25
|
||||
@@20: SCASB
|
||||
JNE @@10
|
||||
XOR RAX,RAX
|
||||
@@25: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
TO_UPPER::
|
||||
CMP AL,'a'
|
||||
JB @@05
|
||||
CMP AL,'z'
|
||||
JA @@05
|
||||
ADD AL,'A'-'a'
|
||||
@@05: RET
|
||||
_STRICMP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
@@05: LODSB
|
||||
TEST AL,AL
|
||||
JZ @@30
|
||||
CMP AL,'a'
|
||||
JB @@10
|
||||
CMP AL,'z'
|
||||
JA @@10
|
||||
ADD AL,'A'-'a'
|
||||
@@10: MOV BL,U8 [RDI]
|
||||
INC RDI
|
||||
CMP BL,'a'
|
||||
JB @@15
|
||||
CMP BL,'z'
|
||||
JA @@15
|
||||
ADD BL,'A'-'a'
|
||||
@@15: CMP AL,BL
|
||||
JE @@05
|
||||
JA @@25
|
||||
@@20: MOV RAX,1
|
||||
JMP @@35
|
||||
@@25: MOV RAX,-1
|
||||
JMP @@35
|
||||
@@30: MOV BL,U8 [RDI]
|
||||
TEST BL,BL
|
||||
JNE @@20
|
||||
XOR RAX,RAX
|
||||
@@35: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_STRNCMP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
@@05: TEST RCX,RCX
|
||||
JZ @@25
|
||||
DEC RCX
|
||||
LODSB
|
||||
TEST AL,AL
|
||||
JZ @@20
|
||||
SCASB
|
||||
JE @@05
|
||||
JA @@15
|
||||
@@10: MOV RAX,1
|
||||
JMP @@30
|
||||
@@15: MOV RAX,-1
|
||||
JMP @@30
|
||||
@@20: MOV BL,U8 [RDI]
|
||||
TEST BL,BL
|
||||
JNE @@10
|
||||
@@25: XOR RAX,RAX
|
||||
@@30: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_STRNICMP::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RCX,U64 SF_ARG3[RBP]
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
@@05: TEST RCX,RCX
|
||||
JZ @@35
|
||||
DEC RCX
|
||||
LODSB
|
||||
TEST AL,AL
|
||||
JZ @@30
|
||||
CMP AL,'a'
|
||||
JB @@10
|
||||
CMP AL,'z'
|
||||
JA @@10
|
||||
ADD AL,'A'-'a'
|
||||
@@10: MOV BL,U8 [RDI]
|
||||
INC RDI
|
||||
CMP BL,'a'
|
||||
JB @@15
|
||||
CMP BL,'z'
|
||||
JA @@15
|
||||
ADD BL,'A'-'a'
|
||||
@@15: CMP AL,BL
|
||||
JE @@05
|
||||
JA @@25
|
||||
@@20: MOV RAX,1
|
||||
JMP @@40
|
||||
@@25: MOV RAX,-1
|
||||
JMP @@40
|
||||
@@30: SCASB
|
||||
JNE @@20
|
||||
@@35: XOR RAX,RAX
|
||||
@@40: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 24
|
||||
_STRMATCH::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
TEST RSI,RSI
|
||||
JZ @@25
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
TEST RDI,RDI
|
||||
JZ @@25
|
||||
MOV DL,U8 [RDI]
|
||||
TEST DL,DL
|
||||
JZ @@20
|
||||
JMP @@10
|
||||
@@05: INC RSI
|
||||
@@10: LODSB
|
||||
TEST AL,AL
|
||||
JZ @@25
|
||||
CMP AL,DL
|
||||
JNE @@10
|
||||
DEC RSI
|
||||
MOV RCX,1
|
||||
@@15: MOV AL,U8 [RDI+RCX]
|
||||
TEST AL,AL
|
||||
JZ @@20
|
||||
CMP AL,U8 [RSI+RCX]
|
||||
JNE @@05
|
||||
INC RCX
|
||||
JMP @@15
|
||||
|
||||
DEC RSI
|
||||
@@20: MOV RAX,RSI
|
||||
JMP @@30
|
||||
@@25: XOR RAX,RAX
|
||||
@@30: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
_STRIMATCH::
|
||||
PUSH RBP
|
||||
MOV RBP,RSP
|
||||
PUSH RSI
|
||||
PUSH RDI
|
||||
MOV RSI,U64 SF_ARG2[RBP]
|
||||
TEST RSI,RSI
|
||||
JZ @@25
|
||||
MOV RDI,U64 SF_ARG1[RBP]
|
||||
TEST RDI,RDI
|
||||
JZ @@25
|
||||
MOV AL,U8 [RDI]
|
||||
CALL TO_UPPER
|
||||
MOV DL,AL
|
||||
TEST DL,DL
|
||||
JZ @@20
|
||||
JMP @@10
|
||||
@@05: INC RSI
|
||||
@@10: LODSB
|
||||
CALL TO_UPPER
|
||||
TEST AL,AL
|
||||
JZ @@25
|
||||
CMP AL,DL
|
||||
JNE @@10
|
||||
DEC RSI
|
||||
MOV RCX,1
|
||||
@@15: MOV AL,U8 [RDI+RCX]
|
||||
CALL TO_UPPER
|
||||
TEST AL,AL
|
||||
JZ @@20
|
||||
MOV BL,U8 [RSI+RCX]
|
||||
XCHG AL,BL
|
||||
CALL TO_UPPER
|
||||
CMP AL,BL
|
||||
JNE @@05
|
||||
INC RCX
|
||||
JMP @@15
|
||||
|
||||
DEC RSI
|
||||
@@20: MOV RAX,RSI
|
||||
JMP @@30
|
||||
@@25: XOR RAX,RAX
|
||||
@@30: POP RDI
|
||||
POP RSI
|
||||
POP RBP
|
||||
RET1 16
|
||||
}
|
||||
_extern _STRCMP I64 StrCmp(
|
||||
U8 *st1,U8 *st2); //Compare two strings.
|
||||
_extern _STRICMP I64 StrICmp(
|
||||
U8 *st1,U8 *st2); //Compare two strings, ignoring case.
|
||||
_extern _STRNCMP I64 StrNCmp(
|
||||
U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings.
|
||||
_extern _STRNICMP I64 StrNICmp(
|
||||
U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings, ignoring case.
|
||||
_extern _STRMATCH U8 *StrMatch(
|
||||
U8 *needle,U8 *haystack_str); //Scan for string in string.
|
||||
_extern _STRIMATCH U8 *StrIMatch(
|
||||
U8 *needle,U8 *haystack_str);//Scan for string in string, ignoring case.
|
||||
_extern _STRCPY U0 StrCpy(
|
||||
U8 *dst,U8 *src); //Copy string.
|
||||
|
||||
//These bitmaps go to 0-511 so that $LK,"Lex",A="MN:Lex"$() can use them with $LK,"Token Codes",A="MN:TK_EOF"$.
|
||||
U32
|
||||
char_bmp_alpha[16]=
|
||||
{0x0000000,0x00000000,0x87FFFFFF,0x07FFFFFE,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_alpha_numeric[16]=
|
||||
{0x0000000,0x03FF0000,0x87FFFFFF,0x07FFFFFE,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_alpha_numeric_no_at[16]=
|
||||
{0x0000000,0x03FF0000,0x87FFFFFE,0x07FFFFFE,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_word[16]=
|
||||
{0x0000000,0x03FF0080,0x87FFFFFE,0x07FFFFFE,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_filename[16]=
|
||||
{0x0000000,0x03FF73FB,0xEFFFFFFF,0x6FFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_dec_numeric[16]=
|
||||
{0x0000000,0x03FF0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_hex_numeric[16]=
|
||||
{0x0000000,0x03FF0000,0x7E,0x7E,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_white_space[16]=
|
||||
{0x80002600,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_non_eol_white_space[16]=
|
||||
{0x80000200,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_zero_cr_nl_cursor[16]=
|
||||
{0x00002421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_zero_tab_cr_nl_cursor[16]=
|
||||
{0x00002621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_zero_tab_cr_nl_cursor_dollar[16]=
|
||||
{0x00002621,0x10,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_macro[16]=
|
||||
{0x80002600,0xFFFFFFDF,0xFFFFFFFF,0x7FFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_printable[16]=
|
||||
{0x80002600,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_displayable[16]=
|
||||
{0x80000000,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},
|
||||
|
||||
char_bmp_safe_dollar[16]=
|
||||
{0x80000000,0xFFFFFFEF,0xFFFFFFFF,0x7FFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0,0,0,0,0,0,0,0},//same but no dollar sign
|
||||
|
||||
char_bmp_non_eol[16]=
|
||||
{0xFFFFDBFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
|
||||
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
|
||||
|
||||
U8 *LstSub(I64 sub, U8 *lst)
|
||||
{//Point to lst entry.
|
||||
//Not efficient. Use an array of U8 ptrs for efficiency.
|
||||
if (!lst) return NULL;
|
||||
while (*lst && sub>0) {
|
||||
while (*lst) //Advance to end of cur entry.
|
||||
lst++;
|
||||
lst++; //Skip trailing zero.
|
||||
if (*lst=='@') //Check for '@' alias lst entry.
|
||||
lst++;
|
||||
else
|
||||
sub--;
|
||||
}
|
||||
if (sub||!*lst)
|
||||
return NULL;
|
||||
else
|
||||
return lst;
|
||||
}
|
||||
|
||||
I64 LstMatch(U8 *needle, U8 *haystack_lst,I64 flags=0)
|
||||
{//-2 if Ambiguous
|
||||
// -1 if not found
|
||||
// Not efficient. Use hash tables for efficiency.
|
||||
I64 n,sub=0,res=-1;
|
||||
U8 *ptr;
|
||||
Bool exact_match=FALSE;
|
||||
if (!haystack_lst) return -1;
|
||||
n=StrLen(needle);
|
||||
while (*haystack_lst) {
|
||||
if (*haystack_lst=='@') { //Check for '@' alias haystack_lst entry
|
||||
sub--;
|
||||
haystack_lst++;
|
||||
}
|
||||
ptr=needle;
|
||||
if (flags & LMF_IGNORE_CASE)
|
||||
while (*ptr && ToUpper(*ptr)==ToUpper(*haystack_lst)) {
|
||||
ptr++;
|
||||
haystack_lst++;
|
||||
}
|
||||
else
|
||||
while (*ptr && *ptr==*haystack_lst) {
|
||||
ptr++;
|
||||
haystack_lst++;
|
||||
}
|
||||
if (!*ptr) { //Did we reach end of needle?
|
||||
if (!*haystack_lst) //Did we reach end of haystack_lst?
|
||||
return sub; //Found Exact match
|
||||
else {
|
||||
if (res!=-1) {
|
||||
if (!exact_match)
|
||||
res=-2; //Ambiguous unless later exact match.
|
||||
} else {
|
||||
if (!(flags & LMF_EXACT))
|
||||
res=sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (*haystack_lst) //Advance to end of cur entry.
|
||||
haystack_lst++;
|
||||
haystack_lst++; //Skip trailing zero
|
||||
sub++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 StrOcc(U8 *src, I64 ch)
|
||||
{//Count occurrences of a char.
|
||||
I64 i=0;
|
||||
if (!src) return 0;
|
||||
while (*src)
|
||||
if (*src++==ch)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
I64 Spaces2Tabs(U8 *dst,U8 *src)
|
||||
{//Src buf with spaces to dst buf without.
|
||||
U8 *src2;
|
||||
I64 chged=0,space_cnt,space_cnt2,col=0;
|
||||
if (*src)
|
||||
while (TRUE) {
|
||||
src2=src;
|
||||
while (*src2==CH_SPACE)
|
||||
src2++;
|
||||
space_cnt=src2-src;
|
||||
while (col+space_cnt>=8) {
|
||||
space_cnt2=8-col;
|
||||
if (space_cnt2==1)
|
||||
*dst++=CH_SPACE;
|
||||
else {
|
||||
*dst++='\t';
|
||||
chged+=space_cnt2-1;
|
||||
}
|
||||
space_cnt-=space_cnt2;
|
||||
col=0;
|
||||
}
|
||||
if (*src2=='\t') {
|
||||
if (space_cnt==1 && col==7)
|
||||
*dst++=CH_SPACE;
|
||||
else
|
||||
chged+=space_cnt;
|
||||
*dst++='\t';
|
||||
col=0;
|
||||
} else {
|
||||
while (space_cnt--) {
|
||||
*dst++=CH_SPACE;
|
||||
if (++col==8)
|
||||
col=0;
|
||||
}
|
||||
if (*src2) {
|
||||
*dst++=*src2;
|
||||
if (++col==8)
|
||||
col=0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
src=++src2;
|
||||
}
|
||||
*dst=0;
|
||||
return chged;
|
||||
}
|
||||
|
||||
U8 *StrUtil(U8 *_src,I64 flags)
|
||||
{//Modifies in place. See $LK,"flags",A="MN:SUF_REM_SPACES"$ for all the options.
|
||||
U8 *src=_src,*dst=_src;
|
||||
I64 ch;
|
||||
|
||||
if (flags & SUF_REM_LEADING)
|
||||
while (Bt(char_bmp_white_space,*src))
|
||||
src++;
|
||||
while (ch=*src++)
|
||||
if (Bt(char_bmp_white_space,ch)) {
|
||||
if (!(flags & SUF_REM_SPACES)) {
|
||||
if (flags & SUF_SINGLE_SPACE) {
|
||||
*dst++ = CH_SPACE;
|
||||
while ((ch=*src++) && Bt(char_bmp_white_space,ch));
|
||||
src--;
|
||||
} else
|
||||
*dst++ = ch;
|
||||
}
|
||||
} else if (!(flags & SUF_REM_CTRL_CHARS) || ch>=CH_SHIFT_SPACE)
|
||||
*dst++=ch;
|
||||
*dst=0;
|
||||
|
||||
if (flags & SUF_REM_TRAILING)
|
||||
while (dst!=_src && (!*dst || Bt(char_bmp_white_space,*dst)))
|
||||
*dst-- =0;
|
||||
if (flags & SUF_TO_UPPER)
|
||||
for (dst=_src;*dst;dst++) {
|
||||
ch=*dst;
|
||||
if ('a'<=ch<='z')
|
||||
*dst=ch-0x20;
|
||||
}
|
||||
if (flags & SUF_TO_LOWER)
|
||||
for (dst=_src;*dst;dst++) {
|
||||
ch=*dst;
|
||||
if ('A'<=ch<='Z')
|
||||
*dst=ch+0x20;
|
||||
}
|
||||
if (flags & SUF_SAFE_DOLLAR)
|
||||
for (dst=_src;*dst;dst++) {
|
||||
ch=*dst;
|
||||
if (!Bt(char_bmp_safe_dollar,*dst))
|
||||
*dst='.';
|
||||
}
|
||||
if (flags & SUF_S2T)
|
||||
Spaces2Tabs(_src,_src);
|
||||
return _src;
|
||||
}
|
||||
|
||||
U8 *StrFirstOcc(U8 *src,U8 *marker)
|
||||
{//Point to 1st occurrence of marker set in str.
|
||||
I64 ch;
|
||||
while ((ch=*src++) && !StrOcc(marker,ch));
|
||||
if (ch)
|
||||
return src-1;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL)
|
||||
{//Remove first str segment and place in dst buf or NULL.
|
||||
I64 ch;
|
||||
U8 *ptr=src,*res=dst;
|
||||
if (dst) {
|
||||
while ((ch=*ptr++) && !StrOcc(marker,ch))
|
||||
*dst++=ch;
|
||||
*dst=0;
|
||||
} else
|
||||
while ((ch=*ptr++) && !StrOcc(marker,ch));
|
||||
if (ch)
|
||||
StrCpy(src,ptr);
|
||||
else
|
||||
*src=0;
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *StrLastOcc(U8 *src,U8 *marker)
|
||||
{//Point to last occurrence of market set in str.
|
||||
I64 ch;
|
||||
U8 *res=NULL;
|
||||
while (ch=*src++)
|
||||
if (StrOcc(marker,ch))
|
||||
res=src-1;
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL)
|
||||
{//Remove last str segment and place in dst buf or NULL.
|
||||
U8 *ptr;
|
||||
if (ptr=StrLastOcc(src,marker)) {
|
||||
if (dst)
|
||||
StrCpy(dst,ptr+1);
|
||||
*ptr=0;
|
||||
} else {
|
||||
if (dst)
|
||||
StrCpy(dst,src);
|
||||
*src=0;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
U8 *StrFind(U8 *needle,U8 *haystack_str,I64 flags=0)
|
||||
{//Find needle_str in haystack_str with options.
|
||||
Bool cont;
|
||||
U8 *saved_haystack_str=haystack_str;
|
||||
I64 plen=StrLen(needle);
|
||||
do {
|
||||
cont=FALSE;
|
||||
if (flags & SFF_IGNORE_CASE)
|
||||
haystack_str=StrIMatch(needle,haystack_str);
|
||||
else
|
||||
haystack_str=StrMatch(needle,haystack_str);
|
||||
if (haystack_str && flags & SFF_WHOLE_LABELS_BEFORE &&
|
||||
haystack_str!=saved_haystack_str &&
|
||||
Bt(char_bmp_alpha_numeric,*(haystack_str-1))) {
|
||||
haystack_str++;
|
||||
if (*haystack_str)
|
||||
cont=TRUE;
|
||||
else
|
||||
haystack_str=NULL;
|
||||
}
|
||||
if (haystack_str && flags & SFF_WHOLE_LABELS_AFTER &&
|
||||
Bt(char_bmp_alpha_numeric,*(haystack_str+plen))) {
|
||||
haystack_str++;
|
||||
if (*haystack_str)
|
||||
cont=TRUE;
|
||||
else
|
||||
haystack_str=NULL;
|
||||
}
|
||||
} while (cont);
|
||||
return haystack_str;
|
||||
}
|
||||
|
||||
Bool WildMatch(U8 *test_str,U8 *wild_str)
|
||||
{//Wildcard match with '*' and '?'.
|
||||
I64 ch1,ch2;
|
||||
U8 *fall_back_src=NULL,*fall_back_wild=NULL;
|
||||
while (TRUE) {
|
||||
if (!(ch1=*test_str++)) {
|
||||
if (*wild_str && *wild_str!='*')
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
} else {
|
||||
if (!(ch2=*wild_str++))
|
||||
return FALSE;
|
||||
else {
|
||||
if (ch2=='*') {
|
||||
fall_back_wild=wild_str-1;
|
||||
fall_back_src=test_str;
|
||||
if (!(ch2=*wild_str++))
|
||||
return TRUE;
|
||||
while (ch2!=ch1)
|
||||
if (!(ch1=*test_str++))
|
||||
return FALSE;
|
||||
} else
|
||||
if (ch2!='?' && ch1!=ch2) {
|
||||
if (fall_back_wild) {
|
||||
wild_str=fall_back_wild;
|
||||
test_str=fall_back_src;
|
||||
fall_back_wild=NULL;
|
||||
fall_back_src=NULL;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
U8 *Tabs2Spaces(U8 *src)
|
||||
{//MAlloc str with tabs to spaces.
|
||||
I64 ch,i,j,l=StrLen(src)<<1+2,col=0;
|
||||
U8 *dst=MAlloc(l),*tmp;
|
||||
while (ch=*src++) {
|
||||
if (ch=='\t') {
|
||||
j=(col+8) & ~7;
|
||||
for (i=col;i<j;i++) {
|
||||
dst[i]=CH_SPACE;
|
||||
if (i>=l-2) {
|
||||
tmp=MAlloc(l<<1);
|
||||
MemCpy(tmp,dst,i+1);
|
||||
Free(dst);
|
||||
l<<=1;
|
||||
dst=tmp;
|
||||
}
|
||||
}
|
||||
col=j;
|
||||
} else {
|
||||
dst[col]=ch;
|
||||
if (col>=l-2) {
|
||||
tmp=MAlloc(l<<1);
|
||||
MemCpy(tmp,dst,col+1);
|
||||
Free(dst);
|
||||
l<<=1;
|
||||
dst=tmp;
|
||||
}
|
||||
col++;
|
||||
}
|
||||
}
|
||||
dst[col]=0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
U8 *ScaleIndent(U8 *src,F64 indent_scale_factor)
|
||||
{//MAlloced str. 8*0.25-->2 or 8*2.0-->16
|
||||
I64 ch,i,col=0;
|
||||
U8 *dst,*dst2;
|
||||
while (ch=*src++) {
|
||||
if (ch=='\t')
|
||||
col=(col+8) & -0x8;
|
||||
else if (ch==CH_SPACE)
|
||||
col++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
src--;
|
||||
col=Round(indent_scale_factor*col);
|
||||
dst=dst2=MAlloc(StrLen(src)+col/8+col&7+1);
|
||||
for (i=col/8;i>0;i--)
|
||||
*dst2++='\t';
|
||||
for (i=col&7;i>0;i--)
|
||||
*dst2++=CH_SPACE;
|
||||
StrCpy(dst2,src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
U8 *MStrUtil(U8 *src,I64 flags,F64 indent_scale_factor=0)
|
||||
{//MAlloc $LK,"StrUtil",A="MN:StrUtil"$().
|
||||
U8 *dst=StrNew(src),*dst2,*tmp;
|
||||
StrUtil(dst,flags);
|
||||
if (flags & SUF_T2S) {
|
||||
tmp=Tabs2Spaces(dst);
|
||||
Free(dst);
|
||||
dst=tmp;
|
||||
}
|
||||
if (flags & SUF_SCALE_INDENT)
|
||||
dst2=ScaleIndent(dst,indent_scale_factor);
|
||||
else
|
||||
dst2=StrNew(dst); //Shorten to just right size.
|
||||
Free(dst);
|
||||
return dst2;
|
||||
}
|
||||
|
||||
U0 GetOutOfDollar()
|
||||
{//If a $$ has been printed, print another $$ to exit mode.
|
||||
CDoc *doc;
|
||||
if (IsRaw) {
|
||||
if (text.raw_flags&RWF_IN_DOLLAR)
|
||||
'$$';
|
||||
} else {
|
||||
if (fp_doc_put && (doc=(*fp_doc_put)(Fs)) && doc->flags&DOCF_IN_DOLLAR)
|
||||
'$$';
|
||||
}
|
||||
}
|
||||
|
||||
Bool YorN()
|
||||
{//Wait for user to answer Y or N.
|
||||
I64 ch;
|
||||
"(y or n)? ";
|
||||
while (TRUE) {
|
||||
ch=ToUpper(GetChar(,FALSE));
|
||||
if (ch=='Y') {
|
||||
"$$PT$$YES$$FG$$\n";
|
||||
return TRUE;
|
||||
} else if (ch=='N') {
|
||||
"$$PT$$NO$$FG$$\n";
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I64 PressAKey()
|
||||
{//Print "Press a key" and wait for non-zero $LK,"ASCII",A="MN:CH_CTRLA"$ key.
|
||||
"$$BK,1$$PRESS A KEY$$BK,0$$\n";
|
||||
return GetChar(,FALSE);
|
||||
}
|
||||
|
||||
Bool AreYouSure()
|
||||
{//Print "Are you sure" and waits for Y or N.
|
||||
"ARE YOU SURE ";
|
||||
return YorN;
|
||||
}
|
||||
|
||||
U0 Help()
|
||||
{//Dbg help or master help index file.
|
||||
if (IsDbgMode)
|
||||
DbgHelp;
|
||||
else
|
||||
PopUp("Type(\"::/Doc/HelpIndex.DD\");DocTop;View;");
|
||||
}
|
||||
|
||||
U0 ScanFlags(U8 *_dst_flags,U8 *lst,U8 *src)
|
||||
{/*More than 64 flags. Flags passed by ref.
|
||||
|
||||
Examples:
|
||||
$LK,"ScanFlags",A="FF:::/Adam/Opt/Utils/Diff.HC,ScanFlags:2"$(&fuf_flags,Define("ST_FILE_UTIL_FLAGS"),fu_flags);
|
||||
|
||||
I64 flags=0;
|
||||
ScanFlags(&flags,"R\0L\0Dump\0Scan\0","+Dump-R"); //Sets Bit#2, Clears Bit#0.
|
||||
*/
|
||||
I64 i;
|
||||
U8 *buf,*ptr;
|
||||
if (src) {
|
||||
buf=MAlloc(StrLen(src)+1);
|
||||
while (*src) {
|
||||
while (*src && *src!='+' && *src!='-')
|
||||
src++;
|
||||
if (*src=='+') {
|
||||
src++;
|
||||
if (*src) {
|
||||
ptr=buf;
|
||||
while (*src && *src!='+' && *src!='-' &&
|
||||
*src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
|
||||
*ptr++=*src++;
|
||||
*ptr=0;
|
||||
i=LstMatch(buf,lst);
|
||||
if (i>=0)
|
||||
LBts(_dst_flags,i);
|
||||
else {
|
||||
Free(buf);
|
||||
throw('ScanFlag');
|
||||
}
|
||||
}
|
||||
} else if (*src=='-') {
|
||||
src++;
|
||||
if (*src) {
|
||||
ptr=buf;
|
||||
while (*src && *src!='+' && *src!='-' &&
|
||||
*src!=CH_SPACE && *src!=CH_SHIFT_SPACE)
|
||||
*ptr++=*src++;
|
||||
*ptr=0;
|
||||
i=LstMatch(buf,lst);
|
||||
if (i>=0)
|
||||
LBtr(_dst_flags,i);
|
||||
else {
|
||||
Free(buf);
|
||||
throw('ScanFlag');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
U8 *StrPrintFlags(U8 *dst,U8 *lst,I64 flags)
|
||||
{//Only 64 flags. Flags passed by value.
|
||||
I64 i;
|
||||
*dst=0;
|
||||
while (flags) {
|
||||
i=Bsf(flags);
|
||||
Btr(&flags,i);
|
||||
CatPrint(dst,"+%z",i,lst);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,920 @@
|
||||
U0 SPutChar(U8 **_dst,U8 ch,U8 **_buf)
|
||||
{
|
||||
I64 i;
|
||||
U8 *dst=*_dst,*buf;
|
||||
if (_buf) {
|
||||
buf=*_buf;
|
||||
i=dst-buf;
|
||||
if (i>=MSize(buf)) {
|
||||
buf=MAlloc(i<<1+1);
|
||||
MemCpy(buf,*_buf,i);
|
||||
Free(*_buf);
|
||||
dst=buf+i;
|
||||
*_buf=buf;
|
||||
}
|
||||
}
|
||||
*dst++=ch;
|
||||
*_dst=dst;
|
||||
}
|
||||
|
||||
U0 OutStr(U8 *ptr,U8 **_buf,U8 **_dst,I64 len,I64 flags)
|
||||
{
|
||||
I64 i,j;
|
||||
if (!ptr)
|
||||
i=0;
|
||||
else
|
||||
i=StrLen(ptr);
|
||||
if (flags&PRTF_TRUNCATE && i>len)
|
||||
i=len;
|
||||
if (flags&PRTF_LEFT_JUSTIFY) {
|
||||
for (j=0;j<i;j++)
|
||||
SPutChar(_dst,*ptr++,_buf);
|
||||
for (j=0;j<len-i;j++)
|
||||
SPutChar(_dst,CH_SPACE,_buf);
|
||||
} else {
|
||||
for (j=0;j<len-i;j++)
|
||||
SPutChar(_dst,CH_SPACE,_buf);
|
||||
for (j=len-i;j<len;j++)
|
||||
SPutChar(_dst,*ptr++,_buf);
|
||||
}
|
||||
}
|
||||
|
||||
U8 *MPrintTime(CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt+local_time_offset);
|
||||
return MStrPrint("%02d:%02d:%02d",ds.hour,ds.min,ds.sec);
|
||||
}
|
||||
|
||||
U8 *MPrintDate(CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt+local_time_offset);
|
||||
return MStrPrint("%02d/%02d/%02d",ds.mon,ds.day_of_mon,ds.year%100);
|
||||
}
|
||||
|
||||
U8 *MPrintQ(U8 *ptr,I64 flags)
|
||||
{
|
||||
U8 **_buf,*buf,**_dst,*dst,buf2[8],*ptr2;
|
||||
I64 ch;
|
||||
buf=MAlloc(STR_LEN);
|
||||
_buf=&buf;
|
||||
dst=buf;
|
||||
_dst=&dst;
|
||||
if (ptr)
|
||||
while (ch=*ptr++) {
|
||||
switch (ch) {
|
||||
case '$$':
|
||||
if (flags&PRTF_DOLLAR) {
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
SPutChar(_dst,'d',_buf);
|
||||
} else {
|
||||
SPutChar(_dst,ch,_buf);
|
||||
SPutChar(_dst,ch,_buf);
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
SPutChar(_dst,ch,_buf);
|
||||
if (flags&PRTF_SLASH)
|
||||
SPutChar(_dst,ch,_buf);
|
||||
break;
|
||||
case '\n':
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
SPutChar(_dst,'n',_buf);
|
||||
break;
|
||||
case '\r':
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
SPutChar(_dst,'r',_buf);
|
||||
break;
|
||||
case '\t':
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
SPutChar(_dst,'t',_buf);
|
||||
break;
|
||||
case '"':
|
||||
case '\\':
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
SPutChar(_dst,ch,_buf);
|
||||
break;
|
||||
default:
|
||||
if (ch>=CH_SHIFT_SPACE && ch!=0x7F)
|
||||
SPutChar(_dst,ch,_buf);
|
||||
else {
|
||||
StrPrint(buf2,"\\x%02X",ch);
|
||||
ptr2=buf2;
|
||||
while (*ptr2)
|
||||
SPutChar(_dst,*ptr2++,_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
SPutChar(_dst,0,_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U8 *MPrintq(U8 *ptr,I64 flags)
|
||||
{
|
||||
U8 **_buf,*buf,**_dst,*dst;
|
||||
I64 i,j,ch,ch1;
|
||||
buf=MAlloc(STR_LEN);
|
||||
_buf=&buf;
|
||||
dst=buf;
|
||||
_dst=&dst;
|
||||
if (ptr)
|
||||
while (ch=*ptr++) {
|
||||
ch1=*ptr;
|
||||
switch (ch) {
|
||||
case '\\':
|
||||
switch (ch1) {
|
||||
start:
|
||||
case '0':
|
||||
SPutChar(_dst,0,_buf);
|
||||
break;
|
||||
case '\'':
|
||||
SPutChar(_dst,'\'',_buf);
|
||||
break;
|
||||
case '\`':
|
||||
SPutChar(_dst,'\`',_buf);
|
||||
break;
|
||||
case '"':
|
||||
SPutChar(_dst,'"',_buf);
|
||||
break;
|
||||
case '\\':
|
||||
SPutChar(_dst,'\\',_buf);
|
||||
break;
|
||||
case 'd':
|
||||
SPutChar(_dst,'$$',_buf);
|
||||
break;
|
||||
case 'n':
|
||||
SPutChar(_dst,'\n',_buf);
|
||||
break;
|
||||
case 'r':
|
||||
SPutChar(_dst,'\r',_buf);
|
||||
break;
|
||||
case 't':
|
||||
SPutChar(_dst,'\t',_buf);
|
||||
break;
|
||||
end:
|
||||
ptr++;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
i=0;
|
||||
ptr++;
|
||||
for (j=0;j<2;j++) {
|
||||
ch1=ToUpper(*ptr++);
|
||||
if (Bt(char_bmp_hex_numeric,ch1)) {
|
||||
if (ch1<='9')
|
||||
i=i<<4+ch1-'0';
|
||||
else
|
||||
i=i<<4+ch1-'A'+10;
|
||||
} else {
|
||||
ptr--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SPutChar(_dst,i,_buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
SPutChar(_dst,ch,_buf);
|
||||
}
|
||||
break;
|
||||
case '$$':
|
||||
SPutChar(_dst,ch,_buf);
|
||||
if (ch1=='$$')
|
||||
ptr++;
|
||||
break;
|
||||
case '%':
|
||||
SPutChar(_dst,ch,_buf);
|
||||
if (flags&PRTF_SLASH && ch1=='%')
|
||||
ptr++;
|
||||
break;
|
||||
default:
|
||||
SPutChar(_dst,ch,_buf);
|
||||
}
|
||||
}
|
||||
SPutChar(_dst,0,_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U8 *sys_pos_pows_lets=" KMGTPEZY",
|
||||
*sys_neg_pows_lets=" mænpfazy",
|
||||
*sys_pos_pows_lst="kilo\0mega\0giga\0tera\0peta\0exa\0zetta\0yotta\0",
|
||||
*sys_neg_pows_lst="milli\0micro\0nano\0pico\0femto\0atto\0zepto\0yocto\0";
|
||||
|
||||
#define TMP_BUF_LEN 256
|
||||
#define SLOP 8
|
||||
|
||||
U8 *StrPrintJoin(U8 *dst,U8 *fmt,I64 argc,I64 *argv)
|
||||
{/*$LK,"Print(\"\") Fmt Strings",A="FI:::/Doc/Print.DD"$
|
||||
In float formatting, do not exceed 18-digits
|
||||
before or after the decimal point
|
||||
because the numbers before and after
|
||||
the decimal point are stored
|
||||
in 64-bits. Use exponentiated forms
|
||||
to avoid this.
|
||||
*/
|
||||
I64 i,j,l,ch,k,k0,n,n0,len,dec_len,flags,old_flags,
|
||||
aux_fmt_num,comma_cnt,comma_fmt_cnt,cur_arg=0;
|
||||
U64 m;
|
||||
F64 d,d1;
|
||||
CDoc *doc;
|
||||
U8 *ptr,**_buf,*buf,**_dst,tmp_buf[TMP_BUF_LEN],tmp_buf2[TMP_BUF_LEN*2];
|
||||
|
||||
if (!fmt)
|
||||
throw('StrPrint');
|
||||
if (dst) {
|
||||
_buf=NULL;
|
||||
buf=dst;
|
||||
} else {
|
||||
buf=MAlloc(STR_LEN);
|
||||
_buf=&buf;
|
||||
dst=buf;
|
||||
}
|
||||
_dst=&dst;
|
||||
|
||||
while (ch = *fmt++) {
|
||||
if (ch=='%') {
|
||||
flags=0;
|
||||
if (*fmt=='-') {
|
||||
flags|=PRTF_LEFT_JUSTIFY;
|
||||
fmt++;
|
||||
}
|
||||
if (*fmt=='0') {
|
||||
flags|=PRTF_PAD_ZERO;
|
||||
fmt++;
|
||||
}
|
||||
len=0;
|
||||
while ('0'<=*fmt<='9')
|
||||
len=len*10+ *fmt++ -'0';
|
||||
if (*fmt=='*') {
|
||||
fmt++;
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
len=argv[cur_arg++];
|
||||
}
|
||||
dec_len=0;
|
||||
if (*fmt=='.') {
|
||||
fmt++;
|
||||
while ('0'<=*fmt<='9')
|
||||
dec_len=dec_len*10+ *fmt++ -'0';
|
||||
if (*fmt=='*') {
|
||||
fmt++;
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
dec_len=argv[cur_arg++];
|
||||
}
|
||||
flags|=PRTF_DECIMAL;
|
||||
}
|
||||
|
||||
aux_fmt_num=0;
|
||||
while (TRUE) {
|
||||
switch (*fmt) {
|
||||
start:
|
||||
case '$$':
|
||||
flags|=PRTF_DOLLAR;
|
||||
break;
|
||||
case '/':
|
||||
flags|=PRTF_SLASH;
|
||||
break;
|
||||
case ',':
|
||||
flags|=PRTF_COMMA;
|
||||
break;
|
||||
case 't':
|
||||
flags|=PRTF_TRUNCATE;
|
||||
break;
|
||||
case 'l': //harmless
|
||||
break;
|
||||
end:
|
||||
fmt++;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
fmt++;
|
||||
flags|=PRTF_AUX_FMT_NUM;
|
||||
if (*fmt=='?') {
|
||||
fmt++;
|
||||
flags|=PRTF_QUESTION;
|
||||
} else {
|
||||
if (*fmt=='*') {
|
||||
fmt++;
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
aux_fmt_num=argv[cur_arg++];
|
||||
} else {
|
||||
if (*fmt=='-') {
|
||||
fmt++;
|
||||
flags|=PRTF_NEG_AUX_FMT_NUM;
|
||||
}
|
||||
while ('0'<=*fmt<='9')
|
||||
aux_fmt_num=aux_fmt_num*10+ *fmt++ -'0';
|
||||
if (flags&PRTF_NEG_AUX_FMT_NUM)
|
||||
aux_fmt_num=-aux_fmt_num;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto sp_arg;
|
||||
}
|
||||
}
|
||||
|
||||
sp_arg:
|
||||
k=0;
|
||||
switch (*fmt++) {
|
||||
start:
|
||||
case 'F':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
if (flags&PRTF_DOLLAR) {
|
||||
doc=argv[cur_arg++];
|
||||
old_flags=doc->flags;
|
||||
doc->flags|=DOCF_NO_CURSOR;
|
||||
ptr=DocSave(doc);
|
||||
doc->flags=old_flags;
|
||||
} else
|
||||
ptr=FileRead(argv[cur_arg++]);
|
||||
break;
|
||||
case 'Q':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=MPrintQ(argv[cur_arg++],flags);
|
||||
break;
|
||||
case 'q':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=MPrintq(argv[cur_arg++],flags);
|
||||
break;
|
||||
case 'D':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=MPrintDate(argv[cur_arg++]);
|
||||
break;
|
||||
case 'T':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=MPrintTime(argv[cur_arg++]);
|
||||
break;
|
||||
end:
|
||||
OutStr(ptr,_buf,_dst,len,flags);
|
||||
Free(ptr);
|
||||
break;
|
||||
|
||||
start:
|
||||
case 's':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=argv[cur_arg++];
|
||||
break;
|
||||
case 'S':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=Define(argv[cur_arg++]);
|
||||
break;
|
||||
case 'z':
|
||||
if (cur_arg+1>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=LstSub(argv[cur_arg],argv[cur_arg+1]);
|
||||
cur_arg=cur_arg+2;
|
||||
break;
|
||||
case 'Z':
|
||||
if (cur_arg+1>=argc)
|
||||
throw('StrPrint');
|
||||
ptr=DefineSub(argv[cur_arg],argv[cur_arg+1]);
|
||||
cur_arg=cur_arg+2;
|
||||
break;
|
||||
end:
|
||||
OutStr(ptr,_buf,_dst,len,flags);
|
||||
break;
|
||||
|
||||
start:
|
||||
case 'c':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
tmp_buf[0](I64)=argv[cur_arg++];
|
||||
tmp_buf[8]=0;
|
||||
break;
|
||||
case 'C':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
tmp_buf[0](I64)=argv[cur_arg++];
|
||||
tmp_buf[8]=0;
|
||||
ptr=tmp_buf;
|
||||
while (*ptr) {
|
||||
*ptr=ToUpper(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
break;
|
||||
end:
|
||||
if (!(flags&PRTF_AUX_FMT_NUM))
|
||||
aux_fmt_num=1;
|
||||
while (aux_fmt_num-->0)
|
||||
OutStr(tmp_buf,_buf,_dst,len,flags);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
StrPrintFunSeg(tmp_buf,argv[cur_arg++],len,flags);
|
||||
OutStr(tmp_buf,_buf,_dst,len,flags);
|
||||
break;
|
||||
case 'P':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
StrPrintFunSeg(tmp_buf,argv[cur_arg],len,flags);
|
||||
if (!IsRaw || !_buf) {
|
||||
StrPrint(tmp_buf2,"$$LK,\"%s\",A=\"AD:0x%X\"$$",
|
||||
tmp_buf,argv[cur_arg]);
|
||||
OutStr(tmp_buf2,_buf,_dst,len,flags);
|
||||
} else
|
||||
OutStr(tmp_buf,_buf,_dst,len,flags);
|
||||
cur_arg++;
|
||||
break;
|
||||
case 'd':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
m=argv[cur_arg++];
|
||||
if (m(I64)<0) {
|
||||
flags|=PRTF_NEG;
|
||||
m=-m;
|
||||
}
|
||||
sp_out_dec:
|
||||
if (flags&PRTF_AUX_FMT_NUM) {
|
||||
if (!len) len=12;
|
||||
d=m;
|
||||
goto sp_out_eng;
|
||||
}
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_fmt_cnt=comma_cnt=3;
|
||||
do {
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
if (!m) break;
|
||||
if (!--comma_cnt) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=3;
|
||||
}
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
sp_out_comma_num:
|
||||
if (flags&PRTF_NEG)
|
||||
i=1;
|
||||
else
|
||||
i=0;
|
||||
if (len<0)
|
||||
len=0;
|
||||
if (flags&PRTF_TRUNCATE && k+i>len)
|
||||
k=len-i;
|
||||
if (k<0)
|
||||
k=0;
|
||||
if (flags&PRTF_PAD_ZERO) {
|
||||
if (flags&PRTF_NEG)
|
||||
SPutChar(_dst,'-',_buf);
|
||||
comma_cnt=(len-k-i+comma_fmt_cnt-comma_cnt+1)
|
||||
%(comma_fmt_cnt+1)+1;
|
||||
for (;i<len-k;i++) {
|
||||
if (!--comma_cnt) {
|
||||
SPutChar(_dst,',',_buf);
|
||||
comma_cnt=comma_fmt_cnt;
|
||||
if (++i>=len-k)
|
||||
break;
|
||||
}
|
||||
SPutChar(_dst,'0',_buf);
|
||||
}
|
||||
} else {
|
||||
for (;i<len-k;i++)
|
||||
SPutChar(_dst,CH_SPACE,_buf);
|
||||
if (flags&PRTF_NEG)
|
||||
SPutChar(_dst,'-',_buf);
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
if (!m) break;
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
sp_out_num:
|
||||
if (flags&PRTF_NEG)
|
||||
i=1;
|
||||
else
|
||||
i=0;
|
||||
if (len<0)
|
||||
len=0;
|
||||
if (flags&PRTF_TRUNCATE && k+i>len)
|
||||
k=len-i;
|
||||
if (k<0)
|
||||
k=0;
|
||||
if (flags&PRTF_PAD_ZERO) {
|
||||
if (flags&PRTF_NEG)
|
||||
SPutChar(_dst,'-',_buf);
|
||||
for (;i<len-k;i++)
|
||||
SPutChar(_dst,'0',_buf);
|
||||
} else {
|
||||
for (;i<len-k;i++)
|
||||
SPutChar(_dst,CH_SPACE,_buf);
|
||||
if (flags&PRTF_NEG)
|
||||
SPutChar(_dst,'-',_buf);
|
||||
}
|
||||
}
|
||||
for (i=k-1;i>=0;i--)
|
||||
SPutChar(_dst,tmp_buf[i],_buf);
|
||||
break;
|
||||
case 'u':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
m=argv[cur_arg++];
|
||||
goto sp_out_dec;
|
||||
case 'f':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
d=argv[cur_arg++](F64);
|
||||
if (d<0) {
|
||||
flags|=PRTF_NEG;
|
||||
d=-d;
|
||||
}
|
||||
|
||||
if (d==ì) {
|
||||
sp_out_inf:
|
||||
if (flags&PRTF_NEG)
|
||||
i=1;
|
||||
else
|
||||
i=0;
|
||||
k=1;
|
||||
if (len<0)
|
||||
len=0;
|
||||
if (flags&PRTF_TRUNCATE && k+i>len)
|
||||
k=len-i;
|
||||
if (k<0)
|
||||
k=0;
|
||||
for (;i<len-k;i++)
|
||||
SPutChar(_dst,CH_SPACE,_buf);
|
||||
if (flags&PRTF_NEG)
|
||||
SPutChar(_dst,'-',_buf);
|
||||
for (i=0;i<k;i++)
|
||||
SPutChar(_dst,'ì',_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
sp_out_f:
|
||||
if (dec_len<0)
|
||||
dec_len=0;
|
||||
n=Log10(d);
|
||||
if (i=dec_len) {
|
||||
if (flags&PRTF_COMMA)
|
||||
i=i-i/4;
|
||||
if (n+i>17) {
|
||||
n+=i-17;
|
||||
d*=Pow10I64(i-n);
|
||||
} else {
|
||||
n=0;
|
||||
d*=Pow10I64(i);
|
||||
}
|
||||
i=dec_len;
|
||||
} else if (n>17) {
|
||||
n-=17;
|
||||
d*=Pow10I64(-n);
|
||||
} else
|
||||
n=0;
|
||||
|
||||
m=Round(d);
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_cnt=i&3;
|
||||
while (i-- && k<TMP_BUF_LEN-SLOP) {
|
||||
if (i>2 && !comma_cnt--) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=2;
|
||||
if (!--i) break;
|
||||
}
|
||||
if (n) {
|
||||
n--;
|
||||
tmp_buf[k++]='0';
|
||||
} else
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
if (!i) break;
|
||||
}
|
||||
} else {
|
||||
while (i-- && k<TMP_BUF_LEN-SLOP) {
|
||||
if (n) {
|
||||
n--;
|
||||
tmp_buf[k++]='0';
|
||||
} else
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
}
|
||||
}
|
||||
if (dec_len)
|
||||
tmp_buf[k++]='.';
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_cnt=3;
|
||||
do {
|
||||
if (n) {
|
||||
n--;
|
||||
tmp_buf[k++]='0';
|
||||
} else
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
if (!m) break;
|
||||
if (!--comma_cnt) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=3;
|
||||
}
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
} else {
|
||||
do {
|
||||
if (n) {
|
||||
n--;
|
||||
tmp_buf[k++]='0';
|
||||
} else
|
||||
tmp_buf[k++]=ModU64(&m,10)+'0';
|
||||
if (!m) break;
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
}
|
||||
goto sp_out_num;
|
||||
case 'e':
|
||||
if (!len) len=12;
|
||||
flags|=PRTF_TRUNCATE;
|
||||
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
d=argv[cur_arg++](F64);
|
||||
if (d<0) {
|
||||
flags|=PRTF_NEG;
|
||||
d=-d;
|
||||
}
|
||||
if (d==ì) goto sp_out_inf;
|
||||
|
||||
if (d)
|
||||
n=Floor(Log10(d));
|
||||
else
|
||||
n=0;
|
||||
sp_out_e:
|
||||
d/=Pow10I64(n);
|
||||
|
||||
k0=k;
|
||||
for (l=0;l<2;l++) {
|
||||
n0=n;
|
||||
if (n<0) {
|
||||
n=-n;
|
||||
flags|=PRTF_NEG_E;
|
||||
} else
|
||||
flags&=~PRTF_NEG_E;
|
||||
|
||||
i=3;
|
||||
do tmp_buf[k++]=ModU64(&n,10)+'0';
|
||||
while (n && i--);
|
||||
if (flags&PRTF_NEG_E)
|
||||
tmp_buf[k++]='-';
|
||||
tmp_buf[k++]='e';
|
||||
dec_len=len-k-2;
|
||||
if (flags&PRTF_NEG)
|
||||
dec_len--;
|
||||
|
||||
if (d) {
|
||||
d1=d+Pow10I64(-dec_len)/2;
|
||||
if (d1<1.0) {
|
||||
d*=10;
|
||||
n=n0-1;
|
||||
k=k0;
|
||||
} else if (d1>=10) {
|
||||
d/=10;
|
||||
n=n0+1;
|
||||
k=k0;
|
||||
} else
|
||||
break;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
goto sp_out_f;
|
||||
case 'g':
|
||||
if (!len) len=12;
|
||||
flags|=PRTF_TRUNCATE;
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
d=argv[cur_arg++](F64);
|
||||
if (d<0) {
|
||||
flags|=PRTF_NEG;
|
||||
d=-d;
|
||||
}
|
||||
if (d==ì) goto sp_out_inf;
|
||||
if (d)
|
||||
n=Floor(Log10(d));
|
||||
else
|
||||
n=0;
|
||||
if (n>=len-1-dec_len || n<-(dec_len-1))
|
||||
goto sp_out_e;
|
||||
else
|
||||
goto sp_out_f;
|
||||
case 'n':
|
||||
if (!len) len=12;
|
||||
flags|=PRTF_TRUNCATE;
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
d=argv[cur_arg++](F64);
|
||||
if (d<0) {
|
||||
flags|=PRTF_NEG;
|
||||
d=-d;
|
||||
}
|
||||
sp_out_eng: //Engineering notation
|
||||
if (d==ì) goto sp_out_inf;
|
||||
if (d)
|
||||
n=FloorI64(Floor(Log10(d)),3);
|
||||
else
|
||||
n=0;
|
||||
d/=Pow10I64(n);
|
||||
|
||||
if (n<0) {
|
||||
n=-n;
|
||||
flags|=PRTF_NEG_E;
|
||||
}
|
||||
if (flags&PRTF_AUX_FMT_NUM && -24<=n<=24) {
|
||||
if (flags&PRTF_QUESTION) {
|
||||
if (flags&PRTF_NEG_E)
|
||||
i=-n/3;
|
||||
else
|
||||
i=n/3;
|
||||
j=0;
|
||||
} else {
|
||||
if (flags&PRTF_NEG_E)
|
||||
j=-n-aux_fmt_num;
|
||||
else
|
||||
j=n-aux_fmt_num;
|
||||
d*=Pow10I64(j);
|
||||
i=aux_fmt_num/3;
|
||||
}
|
||||
if (i<0)
|
||||
tmp_buf[k++]=sys_neg_pows_lets[-i];
|
||||
else if (i>0)
|
||||
tmp_buf[k++]=sys_pos_pows_lets[i];
|
||||
else if (len!=0)
|
||||
tmp_buf[k++]=CH_SPACE;
|
||||
if (!(flags&PRTF_DECIMAL)) {
|
||||
dec_len=len-k-2;
|
||||
if (flags&PRTF_NEG)
|
||||
dec_len--;
|
||||
if (j>0) {
|
||||
if (flags&PRTF_COMMA)
|
||||
dec_len-=4*j/3;
|
||||
else
|
||||
dec_len-=j;
|
||||
}
|
||||
d1=d+Pow10I64(-dec_len+1)/2;
|
||||
if (d1>=10) {
|
||||
dec_len--;
|
||||
if (d1>=100)
|
||||
dec_len--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i=3;
|
||||
do tmp_buf[k++]=ModU64(&n,10)+'0';
|
||||
while (n && i--);
|
||||
if (flags&PRTF_NEG_E)
|
||||
tmp_buf[k++]='-';
|
||||
tmp_buf[k++]='e';
|
||||
if (!dec_len) {
|
||||
dec_len=len-k-2;
|
||||
if (flags&PRTF_NEG)
|
||||
dec_len--;
|
||||
d1=d+Pow10I64(-dec_len+1)/2;
|
||||
if (d1>=10) {
|
||||
dec_len--;
|
||||
if (d1>=100)
|
||||
dec_len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flags&PRTF_COMMA) {
|
||||
if (len && dec_len>0 && !(dec_len&3))
|
||||
tmp_buf[k++]=',';
|
||||
dec_len-=dec_len/4;
|
||||
}
|
||||
goto sp_out_f;
|
||||
case 'X':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
m=argv[cur_arg++];
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_fmt_cnt=comma_cnt=4;
|
||||
do {
|
||||
tmp_buf[k]= m&15 +'0';
|
||||
if (tmp_buf[k]>'9') tmp_buf[k]+='A'-0x3A;
|
||||
k++;
|
||||
m>>=4;
|
||||
if (!m) break;
|
||||
if (!--comma_cnt) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=4;
|
||||
}
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_comma_num;
|
||||
} else {
|
||||
do {
|
||||
tmp_buf[k]= m&15 +'0';
|
||||
if (tmp_buf[k]>'9') tmp_buf[k]+='A'-0x3A;
|
||||
k++;
|
||||
m>>=4;
|
||||
} while (m && k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_num;
|
||||
}
|
||||
case 'x':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
m=argv[cur_arg++];
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_fmt_cnt=comma_cnt=4;
|
||||
do {
|
||||
tmp_buf[k]= m&15 +'0';
|
||||
if (tmp_buf[k]>'9') tmp_buf[k]+='a'-0x3A;
|
||||
k++;
|
||||
m>>=4;
|
||||
if (!m) break;
|
||||
if (!--comma_cnt) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=4;
|
||||
}
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_comma_num;
|
||||
} else {
|
||||
do {
|
||||
tmp_buf[k]= m&15 +'0';
|
||||
if (tmp_buf[k]>'9') tmp_buf[k]+='a'-0x3A;
|
||||
k++;
|
||||
m>>=4;
|
||||
} while (m && k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_num;
|
||||
}
|
||||
case 'b':
|
||||
case 'B':
|
||||
if (cur_arg>=argc)
|
||||
throw('StrPrint');
|
||||
m=argv[cur_arg++];
|
||||
if (flags&PRTF_COMMA) {
|
||||
comma_fmt_cnt=comma_cnt=4;
|
||||
do {
|
||||
tmp_buf[k++]= m&1 +'0';
|
||||
m>>=1;
|
||||
if (!m) break;
|
||||
if (!--comma_cnt) {
|
||||
tmp_buf[k++]=',';
|
||||
comma_cnt=4;
|
||||
}
|
||||
} while (k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_comma_num;
|
||||
} else {
|
||||
do {
|
||||
tmp_buf[k++]= m&1 +'0';
|
||||
m>>=1;
|
||||
} while (m && k<TMP_BUF_LEN-SLOP);
|
||||
goto sp_out_num;
|
||||
}
|
||||
case '%':
|
||||
SPutChar(_dst,'%',_buf);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
SPutChar(_dst,ch,_buf);
|
||||
}
|
||||
SPutChar(_dst,0,_buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
U8 *StrPrint(U8 *dst,U8 *fmt,...)
|
||||
{//See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
|
||||
return StrPrintJoin(dst,fmt,argc,argv);
|
||||
}
|
||||
|
||||
U8 *CatPrint(U8 *_dst,U8 *fmt,...)
|
||||
{//StrCat(). See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
|
||||
U8 *dst=_dst;
|
||||
while (*dst)
|
||||
dst++;
|
||||
StrPrintJoin(dst,fmt,argc,argv);
|
||||
return _dst;
|
||||
}
|
||||
|
||||
U0 Print(U8 *fmt,...)
|
||||
{//$LK,"Print(\"\") Fmt Strings",A="FI:::/Doc/Print.DD"$. See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
|
||||
//Don't use this. $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
PutS(buf);//Don't use PutS(). $LK,"See Print() shortcut.",A="FF:::/Doc/HolyC.DD,DemoHolyC"$
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U8 *MStrPrint(U8 *fmt,...)
|
||||
{//MAlloc StrPrint. See $LK,"StrPrintJoin",A="MN:StrPrintJoin"$().
|
||||
U8 *res,*buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
res=StrNew(buf);
|
||||
Free(buf);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 PrintErr(U8 *fmt,...)
|
||||
{//Print "Err:" and msg in blinking red.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
GetOutOfDollar;
|
||||
ST_ERR_ST "%s",buf;
|
||||
Free(buf);
|
||||
}
|
||||
|
||||
U0 PrintWarn(U8 *fmt,...)
|
||||
{//Print "Warn:" and msg in blinking red.
|
||||
U8 *buf=StrPrintJoin(NULL,fmt,argc,argv);
|
||||
GetOutOfDollar;
|
||||
ST_WARN_ST "%s",buf;
|
||||
Free(buf);
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
I64 Str2I64(U8 *st,I64 radix=10,U8 **_end_ptr=NULL)
|
||||
{//String to I64. Similar to strtoul().
|
||||
//Allows radix change with "0x20" "0b1010" "0d123" "0o18".
|
||||
//Be careful of Str2I64("0b101",16)-->0xB101.
|
||||
Bool neg=FALSE;
|
||||
I64 ch,res=0;
|
||||
if (!st || !(2<=radix<=36)) {
|
||||
if (_end_ptr) *_end_ptr=st;
|
||||
return 0;
|
||||
}
|
||||
while (Bt(char_bmp_white_space,*st))
|
||||
st++;
|
||||
while (TRUE)
|
||||
switch (*st) {
|
||||
case '-':
|
||||
st++;
|
||||
neg=!neg;
|
||||
break;
|
||||
case '+':
|
||||
st++;
|
||||
break;
|
||||
case '0':
|
||||
st++;
|
||||
ch=ToUpper(*st);
|
||||
if (ch>='B' && (radix<=10 || ch>'A'+radix-11))
|
||||
switch (ch) {
|
||||
case 'B': radix=2; st++; break;
|
||||
case 'D': radix=10; st++; break;
|
||||
case 'X': radix=16; st++; break;
|
||||
}
|
||||
default:
|
||||
goto ai_cont;
|
||||
}
|
||||
ai_cont:
|
||||
while (ch=ToUpper(*st++)) {
|
||||
if (radix>10) {
|
||||
if ('0'<=ch<='9')
|
||||
res=res*radix+ch-'0';
|
||||
else if ('A'<=ch<='A'+radix-11)
|
||||
res=res*radix+ch-'A'+10;
|
||||
else
|
||||
break;
|
||||
} else if ('0'<=ch<='0'+radix-1)
|
||||
res=res*radix+ch-'0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (_end_ptr) *_end_ptr=st-1;
|
||||
if (neg)
|
||||
return -res;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
F64 Str2F64(U8 *src,U8 **_end_ptr=NULL)
|
||||
{/*String to F64.
|
||||
Does not allow more than 18-digits
|
||||
before or after the decimal point
|
||||
because the numbers before and after
|
||||
the decimal point are stored
|
||||
in 64-bits. Use exponentiated forms
|
||||
to avoid this.
|
||||
*/
|
||||
I64 i,j,k,ch;
|
||||
F64 d;
|
||||
Bool neg=FALSE,neg_e=FALSE;
|
||||
|
||||
ch=*src++;
|
||||
while (Bt(char_bmp_white_space,ch))
|
||||
ch=*src++;
|
||||
if (ch=='-') {
|
||||
neg=TRUE;
|
||||
ch=*src++;
|
||||
}
|
||||
if (!StrNCmp(src-1,"inf",3)) {
|
||||
d=ì;
|
||||
src+=3;
|
||||
goto a2f_end;
|
||||
}
|
||||
if (*src=='ì') {
|
||||
d=ì;
|
||||
src++;
|
||||
goto a2f_end;
|
||||
}
|
||||
i=0;
|
||||
while (TRUE) {
|
||||
if (Bt(char_bmp_dec_numeric,ch))
|
||||
i=i*10+ch-'0';
|
||||
else {
|
||||
if (ch=='.' || ch=='e' || ch=='E')
|
||||
break;
|
||||
d=i;
|
||||
goto a2f_end;
|
||||
}
|
||||
ch=*src++;
|
||||
}
|
||||
if (ch=='.')
|
||||
ch=*src++;
|
||||
k=0;
|
||||
while (TRUE) {
|
||||
if (Bt(char_bmp_dec_numeric,ch)) {
|
||||
i=i*10+ch-'0';
|
||||
k++;
|
||||
} else {
|
||||
if (ch=='e' || ch=='E')
|
||||
break;
|
||||
d=i*Pow10I64(-k);
|
||||
goto a2f_end;
|
||||
}
|
||||
ch=*src++;
|
||||
}
|
||||
ch=*src++;
|
||||
if (ch=='-') {
|
||||
neg_e=TRUE;
|
||||
ch=*src++;
|
||||
}
|
||||
j=0;
|
||||
while (TRUE) {
|
||||
if (Bt(char_bmp_dec_numeric,ch))
|
||||
j=j*10+ch-'0';
|
||||
else {
|
||||
if (neg_e)
|
||||
d=i*Pow10I64(-j-k);
|
||||
else
|
||||
d=i*Pow10I64(j-k);
|
||||
goto a2f_end;
|
||||
}
|
||||
ch=*src++;
|
||||
}
|
||||
a2f_end:
|
||||
if (_end_ptr) *_end_ptr=src-1;
|
||||
if (neg)
|
||||
return -d;
|
||||
else
|
||||
return d;
|
||||
}
|
||||
|
||||
CDate Str2Date(U8 *_src)
|
||||
{/*"*+nnnn", "*-nnnn", "mm/dd", "mm/dd/yy"
|
||||
It also supports some funs
|
||||
SM() start of mon
|
||||
EM() end of mon
|
||||
SY() start of year
|
||||
EY() end of year
|
||||
Full expressions are not implimented
|
||||
but you can do stuff like SM(*-7)+3
|
||||
and it will return the 3rd day after
|
||||
the start of mon for seven days before
|
||||
today.
|
||||
*/
|
||||
CDate res=0;
|
||||
CDateStruct ds,ds_now;
|
||||
U8 *src=MStrUtil(_src,SUF_REM_SPACES|SUF_TO_UPPER),
|
||||
*v=StrNew(src),
|
||||
*ptr=src;
|
||||
Bool start_mon=FALSE,end_mon=FALSE,
|
||||
start_year=FALSE,end_year=FALSE;
|
||||
|
||||
MemSet(&ds,0,sizeof(CDateStruct));
|
||||
if (!StrNCmp(ptr,"SM(",3)) {
|
||||
ptr+=3;
|
||||
start_mon=TRUE;
|
||||
} else if (!StrNCmp(ptr,"EM(",3)) {
|
||||
ptr+=3;
|
||||
end_mon=TRUE;
|
||||
} else if (!StrNCmp(ptr,"SY(",3)) {
|
||||
ptr+=3;
|
||||
start_year=TRUE;
|
||||
} else if (!StrNCmp(ptr,"EY(",3)) {
|
||||
ptr+=3;
|
||||
end_year=TRUE;
|
||||
}
|
||||
if (*ptr=='*') {
|
||||
ptr++;
|
||||
if (*ptr=='+' || *ptr=='-')
|
||||
res.date=Str2I64(ptr,,&ptr);
|
||||
res+=Now+local_time_offset;
|
||||
} else {
|
||||
StrFirstRem(ptr,"/",v); //Put mon into v
|
||||
ds.mon=Str2I64(v);
|
||||
if (StrOcc(ptr,'/')) {
|
||||
StrFirstRem(ptr,"/",v); //Put day into v leaving year in ptr
|
||||
ds.day_of_mon=Str2I64(v);
|
||||
ds.year=Str2I64(ptr,,&ptr);
|
||||
if (ds.year<100) //if not 4 digit year
|
||||
ds.year+=2000;
|
||||
} else {
|
||||
ds.day_of_mon=Str2I64(ptr,,&ptr);
|
||||
Date2Struct(&ds_now,Now+local_time_offset);
|
||||
ds.year=ds_now.year;
|
||||
}
|
||||
res=Struct2Date(&ds);
|
||||
}
|
||||
if (*ptr==')') ptr++;
|
||||
|
||||
if (start_mon)
|
||||
res.date=FirstDayOfMon(res.date);
|
||||
else if (end_mon)
|
||||
res.date=LastDayOfMon(res.date);
|
||||
else if (start_year)
|
||||
res.date=FirstDayOfYear(res.date);
|
||||
else if (end_year)
|
||||
res.date=LastDayOfYear(res.date);
|
||||
|
||||
if (*ptr=='+' || *ptr=='-')
|
||||
res.date+=Str2I64(ptr);
|
||||
Free(src);
|
||||
Free(v);
|
||||
return res-local_time_offset;
|
||||
}
|
||||
|
||||
U8 *StrScan(U8 *src,U8 *fmt,...)
|
||||
{/*Opposite of sprintf(). Pass ptrs to data to be scanned-in.
|
||||
For "%s", pass ptr to ptr (be careful because addr
|
||||
of array is the same as array--create ptr to array
|
||||
and take addr.
|
||||
*/
|
||||
U8 *buf,*ptr,**pptr;
|
||||
Bool left_justify=FALSE;
|
||||
I64 ch,cur_arg=0,i,len,*i_ptr,dec_len;
|
||||
F64 *d_ptr;
|
||||
if (!fmt)
|
||||
throw('Scan');
|
||||
while (ch = *fmt++) {
|
||||
if (ch=='%') {
|
||||
if (*fmt=='%') {
|
||||
src++;
|
||||
fmt++;
|
||||
} else {
|
||||
if (*fmt=='-') {
|
||||
left_justify=TRUE;
|
||||
fmt++;
|
||||
} else
|
||||
left_justify=FALSE;
|
||||
len=0;
|
||||
while ('0'<=*fmt<='9')
|
||||
len=len*10+ (*fmt++ -'0');
|
||||
if (*fmt=='*') {
|
||||
fmt++;
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
len=argv[cur_arg++];
|
||||
}
|
||||
ch=*fmt++;
|
||||
if (ch && !len) {
|
||||
ptr=src;
|
||||
while (*ptr && *ptr!=*fmt)
|
||||
ptr++;
|
||||
len=ptr-src;
|
||||
} else {
|
||||
if (ch=='.') {
|
||||
dec_len=0;
|
||||
while ('0'<=*fmt<='9')
|
||||
dec_len=dec_len*10+ (*fmt++-'0');
|
||||
if (*fmt=='*') {
|
||||
fmt++;
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
dec_len=argv[cur_arg++];
|
||||
}
|
||||
ch=*fmt++;
|
||||
}
|
||||
}
|
||||
buf=MAlloc(len+1);
|
||||
for (i=0;i<len;i++)
|
||||
buf[i]=*src++;
|
||||
buf[i]=0;
|
||||
switch (ch) {
|
||||
case 's':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
pptr=argv[cur_arg++];
|
||||
StrCpy(*pptr,buf);
|
||||
break;
|
||||
case 'c':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
ptr=argv[cur_arg++];
|
||||
*ptr=*buf;
|
||||
break;
|
||||
case 'C':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
ptr=argv[cur_arg++];
|
||||
*ptr=ToUpper(*buf);
|
||||
break;
|
||||
case 'z':
|
||||
if (cur_arg+1>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=LstMatch(buf,argv[cur_arg++]);
|
||||
break;
|
||||
case 'Z':
|
||||
if (cur_arg+1>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=DefineMatch(buf,argv[cur_arg++]);
|
||||
break;
|
||||
case 'd':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=Str2I64(buf);
|
||||
break;
|
||||
case 'X':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=Str2I64(buf,16);
|
||||
break;
|
||||
case 'b':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=Str2I64(buf,2);
|
||||
break;
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'n':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
d_ptr=argv[cur_arg++];
|
||||
*d_ptr=Str2F64(buf);
|
||||
break;
|
||||
case 'D':
|
||||
if (cur_arg>=argc)
|
||||
throw('Scan');
|
||||
i_ptr=argv[cur_arg++];
|
||||
*i_ptr=Str2Date(buf);
|
||||
break;
|
||||
}
|
||||
Free(buf);
|
||||
}
|
||||
} else
|
||||
src++;
|
||||
}
|
||||
return src;
|
||||
}
|
||||
Reference in new issue
Block a user