Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

385 lines
9.4 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

$title('File Concatenation')
concat:
do;
$include (copyrt.lit)
declare true literally '0FFFFH';
declare false literally '0';
declare forever literally 'while true';
declare boolean literally 'byte';
declare start label;
declare jmp$to$start structure (
jmp$instr byte,
jmp$location address ) data (
0C3H,
.start-3);
mon1:
procedure (func,info) external;
declare func byte;
declare info address;
end mon1;
mon2:
procedure (func,info) byte external;
declare func byte;
declare info address;
end mon2;
declare fcb (1) byte external;
declare fcb16 (1) byte external;
declare tbuff (1) byte external;
/**************************************
* *
* B D O S Externals *
* *
**************************************/
system$reset:
procedure;
call mon1 (0,0);
end system$reset;
read$console:
procedure byte;
return mon2 (1,0);
end read$console;
write$console:
procedure (char);
declare char byte;
call mon1 (2,char);
end write$console;
print$console$buffer:
procedure (buffer$address);
declare buffer$address address;
call mon1 (9,buffer$address);
end print$console$buffer;
open$file:
procedure (fcb$address) byte;
declare fcb$address address;
return mon2 (15,fcb$address);
end open$file;
close$file:
procedure (fcb$address) byte;
declare fcb$address address;
return mon2 (16,fcb$address);
end close$file;
delete$file:
procedure (fcb$address);
declare fcb$address address;
call mon1 (19,fcb$address);
end delete$file;
read$record:
procedure (fcb$address) byte;
declare fcb$address address;
return mon2 (20,fcb$address);
end read$record;
write$record:
procedure (fcb$address) byte;
declare fcb$address address;
return mon2 (21,fcb$address);
end write$record;
create$file:
procedure (fcb$address) byte;
declare fcb$address address;
return mon2 (22,fcb$address);
end create$file;
set$DMA$address:
procedure (DMA$address);
declare DMA$address address;
call mon1 (26,DMA$address);
end set$DMA$address;
crlf:
procedure;
call write$console (0dh);
call write$console (0ah);
end crlf;
parse:
procedure (pcb$adr) address;
declare pcb$adr address;
declare pcb based pcb$adr structure (
filename$adr address,
fcb$adr address );
declare pcb$filename$adr address;
declare pcb$fcb$adr address;
declare filename based pcb$filename$adr (1) byte;
declare fcb based pcb$fcb$adr (1) byte;
declare
/* return conditions */
endline literally '00000H',
badfile literally '0FFFFH',
/* useful literals */
disk literally 'fcb(0)',
fcbname literally '8', /* end of name */
fcbtype literally '11', /* end of type field */
fcbsize literally '16'; /* partial size of fcb */
declare char byte; /* global temp for current char */
declare fnp byte; /* index into file name buffer */
declare fnlen byte;
gnctran:
procedure(b) byte;
declare b byte;
if b < ' ' then return 0dh; /* all non-graphics */
/* translate alpha to upper case */
if b >= 'a' and b <= 'z' then
b = b and 101$1111b; /* upper case */
return b;
end gnctran;
gnc:
procedure;
char = gnctran(filename(fnp := fnp + 1));
end gnc;
delimiter:
procedure byte;
declare i byte;
declare del(*) byte data
(0dh,' =.:<>_[],');
do i = 0 to last(del);
if char = del(i) then return true;
end;
return false;
end delimiter;
putchar:
procedure;
fcb(fnlen:=fnlen+1) = char;
/* can check here for ambig ref's "char = '?'" */
end putchar;
fillq:
procedure(len);
/* fill current name or type with question marks */
declare len byte;
char = '?'; /* question mark */
do while fnlen < len;
call putchar;
end;
end fillq;
/* initialize local bases */
pcb$filename$adr = pcb.filename$adr;
pcb$fcb$adr = pcb.fcb$adr;
/* initialize file control block to empty */
char = ' ';
fnlen = 0;
fnp = -1;
do while fnlen < fcbsize-1;
if fnlen = fcbtype then char = 0;
call putchar;
end;
disk = 0;
/* scan next name */
do forever;
/* deblank command buffer */
call gnc;
do while char = ' ';
call gnc;
end;
if delimiter then return badfile;
fnlen = 0;
do while not delimiter;
if fnlen >= fcbname then /* error, file name too long */
return badfile;
if char = '*' then call fillq(fcbname); else call putchar;
call gnc;
end;
/* check for disk name */
if char = ':' then
do;
if not (disk = 0 and fnlen = 1) then
return badfile;
/* must be a disk name */
if (disk := fcb(1) - 'A' + 1) > 26
/* invalid disk name */
then return badfile;
/* valid disk name replace space in name */
else fcb(fnlen) = ' ';
end;
else
do;
/* char is not ':', so file name is set. scan remainder */
/* at least one char scanned */
fnlen = fcbname;
if char = '.' then /* scan file type */
do;
call gnc;
do while not delimiter;
if fnlen >= fcbtype then
/* error, type field too long */
return badfile;
if char = '*'
then call fillq(fcbtype);
else call putchar;
call gnc;
end;
end;
if char = 0dh
then return endline;
else return .filename(fnp);
end;
end; /* of forever */
end parse;
declare pcb structure (
filename$adr address,
fcb$adr address );
declare nxt$chr$adr address;
declare old$nxt$chr$adr address at (.pcb.filename$adr);
declare char byte;
declare ret byte at (.char);
declare delim based nxt$chr$adr byte;
declare fcbin (33) byte;
declare fcbout (33) byte initial (
0,' ',' ',0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0);
declare default$fcb (33) byte data (
0,' ',' ',0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0);
declare nmb$sect literally '32';
declare buffer (nmb$sect) structure (
record (128) byte);
setup$output$file:
procedure;
pcb.filename$adr = .tbuff(1);
pcb.fcb$adr = .fcbout;
nxt$chr$adr = parse (.pcb);
if delim <> '=' then
do;
if nxt$chr$adr = 0 then
do;
call print$console$buffer (.(
'No input files specified','$'));
go to error;
end;
if nxt$chr$adr = 0ffffh then
do;
call print$console$buffer (.(
'Bad output file name','$'));
go to error;
end;
call print$console$buffer (.(
'A ''='' delimeter expected after output file name','$'));
go to error;
end;
call set$DMA$address (.buffer);
if open$file (.fcbout) <> 255 then
do;
call print$console$buffer (.(
'Destination file exists, delete (Y/N) ? ','$'));
char = read$console;
if (char <> 'y') and (char <> 'Y')
then call system$reset;
call crlf;
call delete$file (.fcbout);
end;
if create$file (.fcbout) = 255 then
do;
call print$console$buffer (.(
'Directory full','$'));
call system$reset;
end;
end setup$output$file;
setup$input$file:
procedure;
pcb.filename$adr = nxt$chr$adr + 1;
pcb.fcb$adr = .fcbin;
call move (33,.default$fcb,.fcbin);
if (nxt$chr$adr := parse (.pcb)) = 0ffffh then
do;
call print$console$buffer (.(
'Bad input file name','$'));
go to error;
end;
call set$DMA$address (.buffer);
if open$file (.fcbin) = 255 then
do;
call print$console$buffer (.(
'No such input file','$'));
go to error;
end;
end setup$input$file;
copy$file:
procedure;
declare (i,cnt) byte;
declare (ok,more$input) boolean;
more$input = true;
do while more$input;
cnt = 0;
ok = true;
do while ok;
call set$DMA$address (.buffer((cnt := cnt+1)-1));
ok = (read$record (.fcbin) = 0) and
(cnt <> nmb$sect);
end;
if (more$input := (cnt = nmb$sect))
then cnt = cnt - 1;
else cnt = cnt - 2;
do i = 0 to cnt;
call set$DMA$address (.buffer(i));
if write$record (.fcbout) <> 0 then
do;
call print$console$buffer (.(
'Disk write error','$'));
call system$reset;
end;
end;
end;
end copy$file;
/*
F i l e C o n c a t e n a t i o n
*/
start:
call setup$output$file;
do forever;
call setup$input$file;
call copy$file;
if nxt$chr$adr = 0 then
do;
ret = close$file (.fcbout);
call system$reset;
end;
end;
error:
call crlf;
tbuff(tbuff(0)+1) = '$';
call print$console$buffer (old$nxt$chr$adr);
call system$reset;
end concat;