Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM II/MPM II SOURCE/UTIL6/PIP.PLM
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1812 lines
54 KiB
Plaintext
Raw 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.

PIPMOD:
DO;
/* P E R I P H E R A L I N T E R C H A N G E P R O G R A M
COPYRIGHT (C) 1976, 1977, 1978, 1979, 1980, 1981
DIGITAL RESEARCH
BOX 579
PACIFIC GROVE, CA
93950
Revised:
17 Jan 80 by Thomas Rolander
14 Sept 81 by Ray Pedrizetti
*/
DECLARE
VERSION LITERALLY '0130H'; /* REQUIRED FOR OPERATION */
DECLARE
MAXB ADDRESS EXTERNAL, /* ADDR FIELD OF JMP BDOS */
FCB (33) BYTE EXTERNAL, /* DEFAULT FILE CONTROL BLOCK */
BUFF(128)BYTE EXTERNAL; /* DEFAULT BUFFER */
DECLARE
ENDFILE LITERALLY '1AH', /* END OF FILE MARK */
JMP LITERALLY '0C3H'; /* 8080 JUMP INSTRUCTION */
DECLARE JUMP BYTE DATA(JMP); /* JMP INSTRUCTION TO */
/* JMP .PIPENTRY-3 WHERE THE LXI SP,STACK ACTUALLY OCCURS */
DECLARE JADR ADDRESS DATA(.PIPENTRY-3); /* START OF PIP */
/* NOTE: PAGE 1 AT 100H CONTAINS THE FOLLOWING
100H: JMP PIPENTRY ;TO START THE PIP PROGRAM */
DECLARE COPYRIGHT(*) BYTE DATA (
' COPYRIGHT (C) 1980, DIGITAL RESEARCH,',
' (09/11/81) MP/M-II PIP VERS 2.0');
/* LITERAL DECLARATIONS */
DECLARE
LIT LITERALLY 'LITERALLY',
LPP LIT '60', /* LINES PER PAGE */
TAB LIT '09H', /* HORIZONTAL TAB */
FF LIT '0CH', /* FORM FEED */
LA LIT '05FH', /* LEFT ARROW */
LB LIT '05BH', /* LEFT BRACKET */
RB LIT '05DH', /* RIGHT BRACKET */
XOFF LIT '13H', /* TRANSMIT BUFFER FUNCTION */
RDR LIT '5',
LST LIT '10',
PUNP LIT '15', /* POSITION OF 'PUN' + 1 */
CONP LIT '19', /* CONSOLE */
NULP LIT '19', /* NUL: BEFORE INCREMENT */
EOFP LIT '20', /* EOF: BEFORE INCREMENT */
HSRDR LIT 'RDR', /* READER DEVICES */
PRNT LIT '10', /* PRINTER */
FSIZE LIT '33',
FRSIZE LIT '36', /* SIZE OF RANDOM FCB */
NSIZE LIT '8',
FNSIZE LIT '11',
FEXT LIT '9',
FEXTL LIT '3',
HBUFS LIT '80', /* "HEX" BUFFER SIZE */
/* scanner return type code */
ERR LIT '0',
SPECL LIT '1',
FILE LIT '2',
PERIPH LIT '3',
DISKNAME LIT '4';
DECLARE
SEARFCB LITERALLY 'FCB', /* SEARCH FCB IN MULTI COPY */
MEMSIZE LITERALLY 'MAXB'; /* MEMORY SIZE */
DECLARE
TRUE LITERALLY '1',
FALSE LITERALLY '0',
FOREVER LITERALLY 'WHILE TRUE',
CR LITERALLY '13',
LF LITERALLY '10',
WHAT LITERALLY '63';
DECLARE
COLUMN BYTE, /* COLUMN COUNT FOR PRINTER TABS */
LINENO BYTE, /* LINE WITHIN PAGE */
AMBIG BYTE, /* SET FOR AMBIGUOUS FILE REFS */
FEEDBASE BYTE, /* USED TO FEED SEARCH CHARACTERS */
FEEDLEN BYTE, /* LENGTH OF FEED STRING */
MATCHLEN BYTE, /* USED IN MATCHING STRINGS */
QUITLEN BYTE, /* USED TO TERMINATE QUIT COMMAND */
NBUF BYTE, /* NUM BUFFERS-1 IN SBUFF AND DBUFF */
CDISK BYTE, /* CURRENT DISK */
SBLEN ADDRESS, /* SOURCE BUFFER LENGTH */
DBLEN ADDRESS, /* DEST BUFFER LENGTH */
tblen address, /* temp buffer length */
SBASE ADDRESS, /* SOURCE BUFFER BASE */
/* THE VECTORS DBUFF AND SBUFF ARE DECLARED WITH DIMENSION
1024, BUT ACTUALLY VARY WITH THE FREE MEMORY SIZE */
DBUFF(1024) BYTE AT (.MEMORY), /* DESTINATION BUFFER */
SBUFF BASED SBASE (1024) BYTE, /* SOURCE BUFFER */
(SCOM, DHEX) BYTE, /* SOURCE IS 'COM' FILE IF TRUE */
/* DEST IS 'HEX' FILE IF TRUE */
/* source fcb, password and password mode */
source structure (
fcb(frsize) byte,
pwnam(nsize) byte,
pwmode byte,
user byte ),
/* temporary destination fcb, password and password mode */
dest structure (
fcb(frsize) byte,
pwnam(nsize) byte,
pwmode byte,
user byte ),
/* original destination fcb, password and password mode */
odest structure (
fcb(frsize) byte,
pwnam(nsize) byte,
pwmode byte,
user byte ),
HSOURCE BYTE, /* NEXT HEX SOURCE CHARACTER */
HBUFF(HBUFS) BYTE, /* HEX FILE BUFFER */
dxfcb(fsize) byte, /* destination xfcb */
DESTR ADDRESS AT(.DEST.FCB(33)), /* RANDOM RECORD POSITION */
DESTO BYTE AT(.DEST.FCB(35)), /* RANDOM OVERFLOW BYTE */
bufsize address, /* multsect buffer size */
NSOURCE ADDRESS, /* NEXT SOURCE CHARACTER */
HARDEOF ADDRESS, /* SET TO NSOURCE ON REAL EOF */
NDEST ADDRESS; /* NEXT DESTINATION CHARACTER */
DECLARE
PDEST BYTE, /* DESTINATION DEVICE */
PSOURCE BYTE; /* CURRENT SOURCE DEVICE */
DECLARE
getpw byte, /* false if password in dest file name */
fastcopy byte, /* true if copy directly to dbuf */
MULTCOM BYTE, /* FALSE IF PROCESSING ONE LINE */
PUTNUM BYTE, /* SET WHEN READY FOR NEXT LINE NUM */
CONCNT BYTE, /* COUNTER FOR CONSOLE READY CHECK */
CHAR BYTE, /* LAST CHARACTER SCANNED */
TYPE BYTE, /* TYPE OF CHARACTER SCANNED */
FLEN BYTE; /* FILE NAME LENGTH */
declare
f1 byte, /* f1 user attribute flag */
f2 byte, /* f2 user attribute flag */
f3 byte, /* f3 user attribute flag */
f4 byte, /* f4 user attribute flag */
ro byte, /* read only attribute flag */
sys byte, /* system attribute flag */
dcnt byte, /* error code or directory code */
exten byte, /* extention error code */
odcnt byte, /* saves dcnt for open dest file */
eretry byte; /* error return flag */
declare
subflgadr address,
submflg based subflgadr byte;
retcodes: procedure(a);
declare a address;
dcnt = low(a);
exten = high(a);
end retcodes;
MON1: PROCEDURE(F,A) EXTERNAL;
DECLARE F BYTE,
A ADDRESS;
END MON1;
MON2: PROCEDURE(F,A) BYTE EXTERNAL;
DECLARE F BYTE,
A ADDRESS;
END MON2;
MON3: PROCEDURE(F,A) ADDRESS EXTERNAL;
DECLARE F BYTE,
A ADDRESS;
END MON3;
BOOT: PROCEDURE EXTERNAL;
/* SYSTEM REBOOT */
END BOOT;
RDCHAR: PROCEDURE BYTE;
/* READ CONSOLE CHARACTER */
RETURN MON2(1,0);
END RDCHAR;
PRINTCHAR: PROCEDURE(CHAR);
DECLARE CHAR BYTE;
CALL MON1(2,CHAR AND 7FH);
END PRINTCHAR;
CRLF: PROCEDURE;
CALL PRINTCHAR(CR);
CALL PRINTCHAR(LF);
END CRLF;
printx: procedure(a);
declare a address;
call mon1(9,a);
end printx;
PRINT: PROCEDURE(A);
DECLARE A ADDRESS;
/* PRINT THE STRING STARTING AT ADDRESS A UNTIL THE
NEXT DOLLAR SIGN IS ENCOUNTERED */
CALL CRLF;
CALL printx(A);
END PRINT;
DECLARE CBUFF(130) BYTE, /* COMMAND BUFFER */
MAXLEN BYTE AT (.CBUFF(0)), /* MAX BUFFER LENGTH */
COMLEN BYTE AT (.CBUFF(1)), /* CURRENT LENGTH */
COMBUFF(128) BYTE AT (.CBUFF(2)); /* COMMAND BUFFER CONTENTS */
DECLARE
CBP BYTE; /* COMMAND BUFFER POINTER */
RDCOM: PROCEDURE;
/* READ INTO COMMAND BUFFER */
MAXLEN = 128;
CALL MON1(10,.MAXLEN);
END RDCOM;
CONBRK: PROCEDURE BYTE;
/* CHECK CONSOLE CHARACTER READY */
RETURN MON2(11,0);
END CONBRK;
CVERSION: PROCEDURE ADDRESS;
RETURN MON3(12,0); /* VERSION NUMBER */
END CVERSION;
SETDMA: PROCEDURE(A);
DECLARE A ADDRESS;
CALL MON1(26,A);
END SETDMA;
setpw: procedure(fcba);
declare fcba address;
declare fcbs based fcba structure (
fcb(frsize) byte,
pwnam(nsize) byte );
call setdma(.fcbs.pwnam(0));
end setpw;
OPEN: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL SETPW(FCB);
call retcodes(mon3(15,FCB));
END OPEN;
CLOSE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
call retcodes(MON3(16,FCB));
END CLOSE;
DECLARE
CUSER BYTE; /* CURRENT USER NUMBER */
declare (anything,last$user) byte;
ck$user: procedure;
do forever;
if anything then return;
if dcnt = 0ffh then return;
if last$user = buff(ror (dcnt,3) and 110$0000b)
then return;
call retcodes(mon3(18,0));
end;
end ck$user;
SEARCH: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
declare fcb0 based fcb byte;
anything = (fcb0 = '?');
call retcodes(MON3(17,FCB));
call ck$user;
END SEARCH;
SEARCHN: PROCEDURE;
call retcodes(MON3(18,0));
call ck$user;
END SEARCHN;
DELETE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL SETPW(FCB);
call retcodes(MON3(19,FCB));
END DELETE;
DISKRD: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
call retcodes(MON3(20,FCB));
END DISKRD;
DISKWRITE: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
call retcodes(MON3(21,FCB));
END DISKWRITE;
MAKE: procedure(fcba);
declare fcba address;
declare fcbs based fcba structure (
fcb(frsize) byte,
pwnam(nsize) byte );
if fcbs.pwnam(0) = 0 then /* zero if no password */
fcbs.fcb(6) = fcbs.fcb(6) and 7fh; /* reset password attribute */
else do;
fcbs.fcb(6) = fcbs.fcb(6) or 80h; /* set password attribute */
call setdma(.fcbs.pwnam(0)); /* set password dma */
end;
call retcodes(mon3(22,fcba));
END MAKE;
RENAME: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
CALL SETPW(FCB);
call retcodes(MON3(23,FCB)) ;
END RENAME;
getdisk: procedure byte;
return mon2(25,0);
end getdisk;
SETIND: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
call retcodes(MON3(30,FCB));
END SETIND;
GETUSER: PROCEDURE BYTE;
RETURN MON2(32,0FFH);
END GETUSER;
SETUSER: PROCEDURE(USER);
DECLARE USER BYTE;
CALL MON1(32,(last$user:=USER));
END SETUSER;
SETCUSER: PROCEDURE;
CALL SETUSER(CUSER);
END SETCUSER;
setduser: procedure;
call setuser(odest.user);
end setduser;
SETSUSER: PROCEDURE;
CALL SETUSER(source.user);
END SETSUSER;
RD$RANDOM: PROCEDURE(FCB) BYTE;
DECLARE FCB ADDRESS;
RETURN MON2(33,FCB);
END RD$RANDOM;
SET$RANDOM: PROCEDURE(FCB);
DECLARE FCB ADDRESS;
/* SET RANDOM RECORD POSITION */
CALL MON1(36,FCB);
END SET$RANDOM;
multsect: procedure(a);
declare a address;
call mon1(44,a);
end multsect;
errmode: procedure(a);
declare a address;
call mon1(45,a);
end errmode;
rdxfcb: procedure(xfcb);
declare xfcb address;
call retcodes(mon3(102,xfcb));
end rdxfcb;
who$con: procedure byte;
return mon2(153,0);
end who$con;
sysdatadr: procedure address;
return mon3(154,0);
end sysdatadr;
conatlst: procedure byte;
return mon2(161,0);
end conatlst;
DECLARE /* CONTROL TOGGLE VECTOR */
CONT(26) BYTE, /* ONE FOR EACH ALPHABETIC */
/* 00 01 02 03 04 05 06 07 08 09 10 11 12 13
A B C D E F G H I J K L M N
14 15 16 17 18 19 20 21 22 23 24 25
O P Q R S T U V W X Y Z */
archiv byte at(.cont(0)), /* file archive */
BLOCK BYTE AT(.CONT(1)), /* BLOCK MODE TRANSFER */
DELET BYTE AT(.CONT(3)), /* DELETE CHARACTERS */
ECHO BYTE AT(.CONT(4)), /* ECHO CONSOLE CHARACTERS */
FORMF BYTE AT(.CONT(5)), /* FORM FILTER */
GETU BYTE AT(.CONT(6)), /* GET FILE, USER # */
HEXT BYTE AT(.CONT(7)), /* HEX FILE TRANSFER */
IGNOR BYTE AT(.CONT(8)), /* IGNORE :00 RECORD ON FILE */
kilds byte at(.cont(10)), /* kill filename display */
LOWER BYTE AT(.CONT(11)), /* TRANSLATE TO LOWER CASE */
NUMB BYTE AT(.CONT(13)), /* NUMBER OUTPUT LINES */
OBJ BYTE AT(.CONT(14)), /* OBJECT FILE TRANSFER */
PAGCNT BYTE AT(.CONT(15)), /* PAGE LENGTH */
QUITS BYTE AT(.CONT(16)), /* QUIT COPY */
RSYS BYTE AT(.CONT(17)), /* READ SYSTEM FILES */
STARTS BYTE AT(.CONT(18)), /* START COPY */
TABS BYTE AT(.CONT(19)), /* TAB SET */
UPPER BYTE AT(.CONT(20)), /* UPPER CASE TRANSLATE */
VERIF BYTE AT(.CONT(21)), /* VERIFY EQUAL FILES ONLY */
WRROF BYTE AT(.CONT(22)), /* WRITE TO R/O FILE */
ZEROP BYTE AT(.CONT(25)); /* ZERO PARITY ON INPUT */
DECLARE ZEROSUP BYTE, /* ZERO SUPPRESSION */
(C3,C2,C1) BYTE; /* LINE COUNT ON PRINTER */
MOVE: PROCEDURE(S,D,N);
DECLARE (S,D) ADDRESS, N BYTE;
DECLARE A BASED S BYTE, B BASED D BYTE;
DO WHILE (N:=N-1) <> 255;
B = A; S = S+1; D = D+1;
END;
END MOVE;
MOVEXT: PROCEDURE(A);
DECLARE A ADDRESS;
/* MOVE THREE CHARACTER EXTENT INTO DEST FCB */
CALL MOVE(A,.DEST.FCB(FEXT),FEXTL);
END MOVEXT;
ERROR: PROCEDURE(errtype,extention,retflag,fileadr);
DECLARE I BYTE,
temp byte,
errtype byte,
extention byte,
retflag byte,
fileadr address,
fcb based fileadr (fsize) byte;
/* errtype error messages */
declare er00(*) byte data ('DISK READ$');
declare er01(*) byte data ('DISK WRITE$');
declare er02(*) byte data ('VERIFY$');
declare er03(*) byte data ('INVALID DESTINATION$');
declare er04(*) byte data ('INVALID SOURCE$');
declare er05(*) byte data ('USER ABORTED$');
declare er06(*) byte data ('BAD PARAMETER$');
declare er07(*) byte data ('INVALID USER NUMBER$');
declare er08(*) byte data ('INVALID FORMAT$');
declare er09(*) byte data ('MAKE FILE$');
declare er10(*) byte data ('FILE NOT FOUND$');
declare er11(*) byte data ('START NOT FOUND$');
declare er12(*) byte data ('QUIT NOT FOUND$');
declare er13(*) byte data ('OPEN FILE$');
declare er14(*) byte data ('CLOSE FILE$');
declare er15(*) byte data ('PRINTER BUSY$');
declare er16(*) byte data ('INVALID SEPARATOR$');
declare er17(*) byte data ('NO DIRECTORY SPACE$');
declare er18(*) byte data ('CAN''T DELETE TEMP FILE$');
declare errmsg(*) address data(
.er00,.er01,.er02,.er03,.er04,
.er05,.er06,.er07,.er08,.er09,
.er10,.er11,.er12,.er13,.er14,
.er15,.er16,.er17,.er18);
/* extended error messages */
declare ex00(*) byte data ('$'); /* NO MESSAGE */
declare ex01(*) byte data ('NONRECOVERABLE$');
declare ex02(*) byte data ('R/O DISK$');
declare ex03(*) byte data ('R/O FILE$');
declare ex04(*) byte data ('INVALID DISK SELECT$');
declare ex05(*) byte data ('INCOMPATIBLE MODE$');
declare ex06(*) byte data ('FCB CHECKSUM$');
declare ex07(*) byte data ('INVALID PASSWORD$');
declare ex08(*) byte data ('ALREADY EXISTS$');
declare ex09(*) byte data ('INVALID FILENAME$');
declare ex10(*) byte data ('LIMIT EXCEEDED$');
declare ex11(*) byte data ('INTERNAL LOCK LIMIT EXCEEDED$');
declare nummsgs lit '12'; /* number of extended messages */
declare extmsg(nummsgs) address data(
.ex00,.ex01,.ex02,.ex03,.ex04,
.ex05,.ex06,.ex07,.ex08,.ex09,
.ex10,.ex11);
eretry = retflag; /* error retry = retry flag */
call multsect(1);
call setduser;
call close(.dest);
call delete(.dest); /* delete destination scratch file */
call close(.odest); /* try to close original destination */
CALL SETCUSER;
/* print out error message */
call print(.('ERROR - $'));
call printx(errmsg(errtype));
if (extention := extention and 0fh) <= nummsgs then
do; call printchar(' ');
call printx(extmsg(extention));
end;
call printx(.(' - $'));
if fileadr <> 0 then
do; call printchar('A' + fcb(0) - 1);
call printchar(':');
do i = 1 to fnsize;
if (temp := fcb(i) and 07fh) <> ' ' then
do; if i = fext then call printchar('.');
call printchar(temp);
end;
end;
end;
/* ZERO THE COMLEN IN CASE THIS IS A SINGLE COMMAND */
COMLEN = 0;
/* DELETE ANY $$$.SUB FILES IN CASE BATCH PROCESSING */
subflgadr = sysdatadr + 128 + who$con;
submflg = 0;
CALL CRLF;
GO TO RETRY;
END ERROR;
FORMERR: PROCEDURE;
call error(8,0,0,0); /* invalid format */
END FORMERR;
FILLSOURCE: PROCEDURE;
/* FILL THE SOURCE BUFFERS */
DECLARE (I,n) BYTE;
NSOURCE = 0;
CALL SETSUSER; /* SOURCE USER NUMBER SET */
if fastcopy then
do; n = shr(nbuf,3) - 1;
bufsize = 1024;
call multsect(8);
end;
else do;
bufsize = 128;
call multsect(1);
n = nbuf;
end;
DO I = 0 TO N;
/* SET DMA ADDRESS TO NEXT BUFFER POSIITION */
CALL SETDMA(.SBUFF(NSOURCE));
call diskrd(.source);
IF dcnt <> 0 THEN
DO; IF dcnt <> 1 THEN
call error(0,exten,0,.source); /* DISK READ ERROR */
/* END - OF - FILE */
if fastcopy then /* add no. sectors copied */
nsource = nsource + (128 * shr(exten,4));
HARDEOF = NSOURCE; /* SET HARD END-OF-FILE */
SBUFF(NSOURCE) = ENDFILE; I = N;
END;
ELSE
NSOURCE = NSOURCE + bufsize;
END;
tblen = nsource;
NSOURCE = 0;
CALL SETCUSER; /* BACK TO CURRENT USER NUMBER */
END FILLSOURCE;
WRITEDEST: PROCEDURE;
/* WRITE OUTPUT BUFFERS UP TO BUT NOT INCLUDING POSITION
NDEST - THE LOW ORDER 7 BITS OF NDEST ARE ZERO */
DECLARE (I, J, N) BYTE,
DATAOK BYTE;
IF (N := LOW(SHR(NDEST,7)) - 1) = 255 THEN RETURN ;
if fastcopy then
do; bufsize = 1024;
call multsect(8);
end;
else
do; bufsize = 128;
call multsect(1);
end;
NDEST = 0;
call setduser; /* destination user */
CALL SETRANDOM(.DEST); /* SET BASE RECORD FOR VERIFY */
DO I = 0 TO N;
if fastcopy then
do; if (n - i < 7) then
do; bufsize = 128;
call multsect(1);
end;
else i = i + 7;
end;
/* SET DMA ADDRESS TO NEXT BUFFER */
CALL SETDMA(.dbuff(ndest));
call diskwrite(.dest);
IF dcnt <> 0 THEN
call error(1,exten,0,.dest); /* DISK WRITE ERROR */
NDEST = NDEST + bufsize;
END;
call multsect(1);
IF VERIF THEN /* VERIFY DATA WRITTEN OK */
DO;
NDEST = 0;
CALL SETDMA(.BUFF); /* FOR COMPARE */
DO I = 0 TO N;
DATAOK = RDRANDOM(.DEST) = 0;
DESTR = DESTR + 1; /* NEXT RANDOM READ */
J = 0;
/* PERFORM COMPARISON */
DO WHILE DATAOK AND J < 80H;
DATAOK = BUFF(J) = DBUFF(NDEST+J);
J = J + 1;
END;
NDEST = NDEST + 128;
IF NOT DATAOK THEN
call error(2,0,0,.dest); /* VERIFY ERROR */
END;
call diskwrite(.dest);
DATAOK = dcnt;
/* NOW READY TO CONTINUE THE WRITE OPERATION */
END;
NDEST = 0;
call setcuser; /* back to current user */
END WRITEDEST;
PUTDCHAR: PROCEDURE(B);
DECLARE B BYTE;
/* WRITE BYTE B TO THE DESTINATION DEVICE GIVEN BY PDEST */
IF B >= ' ' THEN
DO; COLUMN = COLUMN + 1;
IF DELET > 0 THEN /* MAY BE PAST RIGHT SIDE */
DO; IF COLUMN > DELET THEN RETURN;
END;
END;
DO CASE PDEST;
/* CASE 0 IS THE DESTINATION FILE */
DO;
IF NDEST >= DBLEN THEN CALL WRITEDEST;
DBUFF(NDEST) = B;
NDEST = NDEST+1;
END;
/* CASE 1 IS ARD (ADDMASTER) */
GO TO NOTDEST;
/* CASE 2 IS IRD (INTEL/ICOM) */
GO TO NOTDEST;
/* CASE 3 IS PTR */
GO TO NOTDEST;
/* CASE 4 IS UR1 */
GO TO NOTDEST;
/* CASE 5 IS UR2 */
GO TO NOTDEST;
/* CASE 6 IS RDR */
NOTDEST:
call error(3,0,0,0); /* invalid destination */
/* CASE 7 IS OUT */
go to notdest;
/* CASE 8 IS LPT */
go to notdest;
/* CASE 9 IS UL1 */
GO TO NOTDEST;
/* CASE 10 IS PRN (TABS EXPANDED, LINES LISTED, CHANGED TO LST) */
GO TO LSTL;
/* CASE 11 IS LST */
LSTL:
CALL MON1(5,B);
/* CASE 12 IS PTP */
GO TO NOTDEST;
/* CASE 13 IS UP1 */
GO TO NOTDEST;
/* CASE 14 IS UP2 */
GO TO NOTDEST;
/* CASE 15 IS PUN */
GO TO NOTDEST;
/* CASE 16 IS TTY */
go to notdest;
/* CASE 17 IS CRT */
go to notdest;
/* CASE 18 IS UC1 */
go to notdest;
/* CASE 19 IS CON */
CONL:
CALL MON1(2,B);
END; /* of case */
END PUTDCHAR;
PUTDESTC: PROCEDURE(B);
DECLARE (B,I) BYTE;
/* WRITE DESTINATION CHARACTER, TAB EXPANSION */
IF B <> TAB THEN CALL PUTDCHAR(B);
ELSE IF TABS = 0 THEN CALL PUTDCHAR(B);
ELSE /* B IS TAB CHAR, TABS > 0 */
DO; I = COLUMN;
DO WHILE I >= TABS;
I = I - TABS;
END;
I = TABS - I;
DO WHILE I > 0;
I = I - 1;
CALL PUTDCHAR(' ');
END;
END;
IF B = CR THEN COLUMN = 0;
END PUTDESTC;
PRINT1: PROCEDURE(B);
DECLARE B BYTE;
IF (ZEROSUP := ZEROSUP AND B = 0) THEN
CALL PUTDESTC(' ');
ELSE
CALL PUTDESTC('0'+B);
END PRINT1;
PRINTDIG: PROCEDURE(D);
DECLARE D BYTE;
CALL PRINT1(SHR(D,4)); CALL PRINT1(D AND 1111B);
END PRINTDIG;
NEWLINE: PROCEDURE;
DECLARE ONE BYTE;
ONE = 1;
ZEROSUP = NUMB = 1;
C1 = DEC(C1+ONE); C2 = DEC(C2 PLUS 0); C3 = DEC(C3 PLUS 0);
CALL PRINTDIG(C3); CALL PRINTDIG(C2); CALL PRINTDIG(C1);
IF NUMB = 1 THEN /* USUALLY PRINTER OUTPUT */
DO; CALL PUTDESTC(':'); CALL PUTDESTC(' ');
END;
ELSE
CALL PUTDESTC(TAB);
END NEWLINE;
CLEARBUFF: PROCEDURE;
/* CLEAR OUTPUT BUFFER IN BLOCK MODE TRANSMISION */
DECLARE NA ADDRESS;
DECLARE I BYTE;
I = LOW(NDEST) AND 7FH; /* REMAINING PARTIAL BUFFER LENGTH */
NA = NDEST AND 0FF80H; /* START OF SEGMENT NOT WRITTEN */
CALL WRITEDEST; /* CLEARS BUFFERS */
CALL MOVE(.DBUFF(NA),.DBUFF,I);
/* DATA MOVED TO BEGINNING OF BUFFER */
NDEST = I;
END CLEARBUFF;
PUTDEST: PROCEDURE(B);
DECLARE (I,B) BYTE;
/* WRITE DESTINATION CHARACTER, CHECK TABS AND LINES */
IF FORMF THEN /* SKIP FORM FEEDS */
DO; IF B = FF THEN RETURN;
END;
IF PUTNUM THEN /* END OF LINE OR START OF FILE */
DO;
IF B <> FF THEN /* NOT FORM FEED */
DO;
IF (I:=PAGCNT) <> 0 THEN /* PAGE EJECT */
DO; IF I=1 THEN I=LPP;
IF (LINENO := LINENO + 1) >= I THEN
DO; LINENO = 0; /* NEW PAGE */
CALL PUTDESTC(FF);
END;
END;
IF NUMB > 0 THEN
CALL NEWLINE;
PUTNUM = FALSE;
END;
END;
IF BLOCK THEN /* BLOCK MODE TRANSFER */
DO;
IF B = XOFF AND PDEST = 0 THEN
DO; CALL CLEARBUFF; /* BUFFERS WRITTEN */
RETURN; /* DON'T PASS THE X-OFF */
END;
END;
IF B = FF THEN LINENO = 0;
CALL PUTDESTC(B);
IF B = LF THEN PUTNUM = TRUE;
END PUTDEST;
UTRAN: PROCEDURE(B) BYTE;
DECLARE B BYTE;
/* TRANSLATE ALPHA TO UPPER CASE */
IF B >= 110$0001B AND B <= 111$1010B THEN /* LOWER CASE */
B = B AND 101$1111B; /* TO UPPER CASE */
RETURN B;
END UTRAN;
LTRAN: PROCEDURE(B) BYTE;
DECLARE B BYTE;
/* TRANSLATE TO LOWER CASE ALPHA */
IF B >= 'A' AND B <= 'Z' THEN
B = B OR 10$0000B; /* TO LOWER */
RETURN B;
END LTRAN;
GETSOURCEC: PROCEDURE BYTE;
/* READ NEXT SOURCE CHARACTER */
DECLARE (TEMP,B,CONCHK) BYTE;
IF PSOURCE - 1 <= RDR THEN /* 1 ... RDR+1 */
DO; IF (BLOCK OR HEXT) AND CONBRK THEN
DO;
IF RDCHAR = ENDFILE THEN RETURN ENDFILE;
CALL PRINT(.('READER STOPPING',CR,LF,'$'));
RETURN XOFF;
END;
END;
CONCHK = TRUE; /* CONSOLE STATUS CHECK BELOW */
DO CASE PSOURCE;
/* CASE 0 IS SOURCE FILE */
DO; IF NSOURCE >= SBLEN THEN CALL FILLSOURCE;
B = SBUFF(NSOURCE);
NSOURCE = NSOURCE + 1;
END;
/* CASE 1 IS INP */
go to notsource;
/* CASE 2 IS IRD (INTEL/ICOM) */
GO TO NOTSOURCE;
/* CASE 3 IS PTR */
GO TO NOTSOURCE;
/* CASE 4 IS UR1 */
GO TO NOTSOURCE;
/* CASE 5 IS UR2 */
GO TO NOTSOURCE;
/* CASE 6 IS RDR */
GO TO NOTSOURCE;
/* CASE 7 IS OUT */
GO TO NOTSOURCE;
/* CASE 8 IS LPT */
GO TO NOTSOURCE;
/* CASE 9 IS UL1 */
GO TO NOTSOURCE;
/* CASE 10 IS PRN */
GO TO NOTSOURCE;
/* CASE 11 IS LST */
GO TO NOTSOURCE;
/* CASE 12 IS PTP */
GO TO NOTSOURCE;
/* CASE 13 IS UP1 */
GO TO NOTSOURCE;
/* CASE 14 IS UP2 */
GO TO NOTSOURCE;
/* CASE 15 IS PUN */
NOTSOURCE:
DO; call error(4,0,0,0); /* invalid source */
END;
/* CASE 16 IS TTY */
go to notsource;
/* CASE 17 IS CRT */
go to notsource;
/* CASE 18 IS UC1 */
go to notsource;
/* CASE 19 IS CON */
CONL:
DO; CONCHK = FALSE; /* DON'T CHECK CONSOLE STATUS */
B = MON2(1,0);
END;
END; /* OF CASES */
IF ECHO THEN /* COPY TO CONSOLE DEVICE */
DO; TEMP = PDEST; PDEST = CONP; CALL PUTDEST(B);
PDEST = TEMP;
END;
IF CONCHK THEN /* TEST FOR CONSOLE CHAR READY */
DO;
IF SCOM THEN /* SOURCE IS A COM FILE */
CONCHK = (CONCNT := CONCNT + 1) = 0;
ELSE /* ASCII */
CONCHK = B = LF;
IF CONCHK THEN
DO; IF CONBRK THEN
DO;
IF RDCHAR = ENDFILE THEN RETURN ENDFILE;
call error(5,0,0,0); /* USER ABORTED */
END;
END;
END;
IF ZEROP THEN B = B AND 7FH;
IF UPPER THEN RETURN UTRAN(B);
IF LOWER THEN RETURN LTRAN(B);
RETURN B;
END GETSOURCEC;
GETSOURCE: PROCEDURE BYTE;
/* GET NEXT SOURCE CHARACTER */
DECLARE CHAR BYTE;
MATCH: PROCEDURE(B) BYTE;
/* MATCH START AND QUIT STRINGS */
DECLARE (B,C) BYTE;
IF (C:=COMBUFF(B:=(B+MATCHLEN))) = ENDFILE THEN /* END MATCH */
DO; COMBUFF(B) = CHAR; /* SAVE CURRENT CHARACTER */
RETURN TRUE;
END;
IF C = CHAR THEN MATCHLEN = MATCHLEN + 1;
ELSE
MATCHLEN = 0; /* NO MATCH */
RETURN FALSE;
END MATCH;
IF QUITLEN > 0 THEN
DO; IF (QUITLEN := QUITLEN - 1) = 1 THEN RETURN LF;
RETURN ENDFILE; /* TERMINATED WITH CR,LF,ENDFILE */
END;
DO FOREVER; /* LOOKING FOR START */
IF FEEDLEN > 0 THEN /* GET SEARCH CHARACTERS */
DO; FEEDLEN = FEEDLEN - 1;
CHAR = COMBUFF(FEEDBASE);
FEEDBASE = FEEDBASE + 1;
RETURN CHAR;
END;
IF (CHAR := GETSOURCEC) = ENDFILE THEN RETURN ENDFILE;
IF STARTS > 0 THEN /* LOOKING FOR START STRING */
DO; IF MATCH(STARTS) THEN
DO; FEEDBASE = STARTS; STARTS = 0;
FEEDLEN = MATCHLEN + 1;
matchlen = 0;
END; /* OTHERWISE NO MATCH, SKIP CHARACTER */
END;
ELSE IF QUITS > 0 THEN /* PASS CHARACTERS TIL MATCH */
DO; IF MATCH(QUITS) THEN
DO; QUITS = 0; QUITLEN = 2;
/* SUBSEQUENTLY RETURN CR, LF, ENDFILE */
RETURN CR;
END;
RETURN CHAR;
END;
ELSE
RETURN CHAR;
END; /* OF DO FOREVER */
END GETSOURCE;
GNC: PROCEDURE BYTE;
IF (CBP := CBP + 1) >= COMLEN THEN RETURN CR;
RETURN UTRAN(COMBUFF(CBP));
END GNC;
DEBLANK: PROCEDURE;
DO WHILE (CHAR := GNC) = ' ';
END;
END DEBLANK;
SCAN: PROCEDURE(FCBA);
DECLARE FCBA ADDRESS, /* ADDRESS OF FCB TO FILL */
fcbs based fcba structure ( /* FCB, PASSWORD AND MODE STRUCTURE */
fcb(frsize) byte,
pwnam(nsize) byte,
pwmode byte,
user byte );
DECLARE (I,K) BYTE; /* TEMP COUNTERS */
/* SCAN LOOKS FOR THE NEXT DELIMITER, DEVICE NAME, OR FILE NAME.
THE VALUE OF CBP MUST BE 255 UPON ENTRY THE FIRST TIME */
DELIMITER: PROCEDURE(C) BYTE;
DECLARE (I,C) BYTE;
DECLARE DEL(*) BYTE DATA
(' =.:;,<>',CR,LA,LB,RB);
DO I = 0 TO LAST(DEL);
IF C = DEL(I) THEN RETURN TRUE;
END;
RETURN FALSE;
END DELIMITER;
PUTCHAR: PROCEDURE;
FCBS.FCB(FLEN:=FLEN+1) = CHAR;
IF CHAR = WHAT THEN AMBIG = TRUE; /* CONTAINS AMBIGUOUS REF */
END PUTCHAR;
FILLQ: PROCEDURE(LEN);
/* FILL CURRENT NAME OR TYPE WITH QUESTION MARKS */
DECLARE LEN BYTE;
CHAR = WHAT; /* QUESTION MARK */
DO WHILE FLEN < LEN;
CALL PUTCHAR;
END;
END FILLQ;
SCANPAR: PROCEDURE;
DECLARE (I,J) BYTE;
/* SCAN OPTIONAL PARAMETERS */
CHAR = GNC; /* SCAN PAST BRACKET */
DO WHILE NOT(CHAR = CR OR CHAR = RB);
IF (I := CHAR - 'A') > 25 THEN /* NOT ALPHA */
DO; IF CHAR = ' ' THEN
CHAR = GNC;
ELSE
call error(6,0,0,0); /* BAD PARAMETER */
END;
ELSE
DO; /* SCAN PARAMETER VALUE */
IF CHAR = 'S' OR CHAR = 'Q' THEN
DO; /* START OR QUIT COMMAND */
J = CBP + 1; /* START OF STRING */
DO WHILE NOT ((CHAR := GNC) = ENDFILE OR CHAR = CR);
END;
CHAR=GNC;
END;
ELSE IF (J := (CHAR := GNC) - '0') > 9 THEN
J = 1;
ELSE
DO WHILE (K := (CHAR := GNC) - '0') <= 9;
J = J * 10 + K;
END;
CONT(I) = J;
IF I = 6 THEN /* SET SOURCE USER */
DO;
IF J > 31 THEN
call error(7,0,0,0); /* INVALID USER NUMBER */
fcbs.user = J;
END;
END;
END;
CHAR = GNC;
END SCANPAR;
CHKSET: PROCEDURE;
IF CHAR = LA THEN CHAR = '=';
END CHKSET;
/* scan procedure entry point */
/* INITIALIZE FILE CONTROL BLOCK TO EMPTY */
AMBIG = FALSE; TYPE = ERR; CHAR = ' '; FLEN = 0;
DO WHILE FLEN < FRSIZE + NSIZE;
IF FLEN = FNSIZE THEN CHAR = 0;
ELSE IF FLEN = FRSIZE THEN CHAR = ' ';
FCBS.FCB(FLEN := FLEN + 1) = CHAR;
END;
fcbs.pwmode = 1;
/* DEBLANK COMMAND BUFFER */
CALL DEBLANK;
/* MAY BE A SEPARATOR */
IF DELIMITER(CHAR) THEN
DO; CALL CHKSET;
TYPE = SPECL; RETURN;
END;
/* CHECK PERIPHERALS AND DISK FILES */
fcbs.fcb(0) = cdisk +1; /* initialize to current disk */
fcbs.user = cuser; /* and current user */
/* CLEAR PARAMETERS */
DO I = 0 TO 25; CONT(I) = 0;
END;
FEEDLEN,MATCHLEN,QUITLEN = 0;
/* SCAN NEXT NAME */
DO FOREVER;
FLEN = 0;
DO WHILE NOT DELIMITER(CHAR);
IF FLEN >= NSIZE THEN /* ERROR, FILE NAME TOO LONG */
RETURN;
IF CHAR = '*' THEN CALL FILLQ(NSIZE);
ELSE CALL PUTCHAR;
CHAR = GNC;
END;
/* CHECK FOR DISK NAME OR DEVICE NAME */
IF CHAR = ':' THEN
DO; IF FLEN = 1 THEN
/* MAY BE DISK NAME A ... P */
DO;
IF (fcbs.fcb(0) := fcbs.fcb(1) - 'A' + 1) > 17 THEN
RETURN; /* ERROR, INVALID DISK NAME */
CALL DEBLANK; /* MAY BE DISK NAME ONLY */
IF DELIMITER(CHAR) THEN
DO; IF CHAR = LB THEN
CALL SCANPAR;
CBP = CBP - 1;
TYPE = DISKNAME;
RETURN;
END;
END;
ELSE
/* MAY BE A THREE CHARACTER DEVICE NAME */
IF FLEN <> 3 THEN /* ERROR, CANNOT BE DEVICE NAME */
RETURN;
ELSE
/* LOOK FOR DEVICE NAME */
DO; DECLARE (I,J,K) BYTE, M LITERALLY '20',
IO(*) BYTE DATA
('INPIRDPTRUR1UR2RDROUTLPTUL1PRNLST',
'PTPUP1UP2PUNTTYCRTUC1CONNULEOF',0);
/* NOTE THAT ALL READER-LIKE DEVICES MUST BE
PLACED BEFORE 'RDR', AND ALL LISTING-LIKE DEVICES
MUST APPEAR BELOW LST, BUT ABOVE RDR. THE LITERAL
DECLARATIONS FOR RDR, LST, AND PUNP MUST INDICATE
THE POSITIONS OF THESE DEVICES IN THE LIST */
J = 255;
DO K = 0 TO M;
I = 0;
DO WHILE ((I:=I+1) <= 3) AND
IO(J+I) = fcbs.fcb(I);
END;
IF I = 4 THEN /* COMPLETE MATCH */
DO; TYPE = PERIPH;
/* SCAN PARAMETERS */
IF GNC = LB THEN CALL SCANPAR;
CBP = CBP - 1; CHAR = K;
RETURN;
END;
/* OTHERWISE TRY NEXT DEVICE */ J = J + 3;
END;
/* ERROR, NO DEVICE NAME MATCH */ RETURN;
END;
IF CHAR = LB THEN /* PARAMETERS FOLLOW */
CALL SCANPAR;
END;
ELSE
/* CHAR IS NOT ':', SO FILE NAME IS SET. SCAN REMAINDER */
DO; IF FLEN = 0 THEN /* ERROR, NO PRIMARY NAME */
RETURN;
FLEN = NSIZE;
IF CHAR = '.' THEN /* SCAN FILE TYPE */
DO WHILE NOT DELIMITER(CHAR := GNC);
IF FLEN >= FNSIZE THEN
/* ERROR, TYPE FIELD TOO LONG */ RETURN;
IF CHAR = '*' THEN CALL FILLQ(FNSIZE);
ELSE CALL PUTCHAR;
END;
FLEN = 0;
IF CHAR = ';' THEN /* SCAN PASSWORD */
DO WHILE NOT DELIMITER(CHAR := GNC);
IF FLEN >= NSIZE THEN
/* ERROR, PW TOO LONG */ RETURN;
ELSE /* SAVE PASSWORD */
FCBS.PWNAM(FLEN) = CHAR;
FLEN = FLEN + 1;
END;
if (.fcbs = .odest) then /* use dest password */
getpw = false;
IF CHAR = LB THEN
CALL SCANPAR;
/* RESCAN DELIMITER NEXT TIME AROUND */
CBP = CBP - 1;
TYPE = FILE;
FCBS.FCB(32) = 0;
RETURN;
END;
END;
END SCAN;
NULLS: PROCEDURE;
/* SEND 40 NULLS TO OUTPUT DEVICE */
DECLARE I BYTE;
DO I = 0 TO 39; CALL PUTDEST(0);
END;
END NULLS;
DECLARE COPYING BYTE; /* TRUE WHILE COPYING TO DEST FILE */
EQUAL: PROCEDURE(A,B) BYTE;
/* COMPARE THE STRINGS AT A AND B UNTIL EITHER A MISMATCH OR
A '$' IS ENCOUNTERED IN STRING B */
DECLARE (A,B) ADDRESS,
(SA BASED A, SB BASED B) BYTE;
DO WHILE SB <> '$';
IF (SB AND 7FH) <> (SA AND 7FH) THEN RETURN FALSE;
A = A + 1; B = B + 1;
END;
RETURN TRUE;
END EQUAL;
RD$EOF: PROCEDURE BYTE;
/* RETURN TRUE IF END OF FILE */
CHAR = GETSOURCE;
IF SCOM THEN RETURN HARDEOF < NSOURCE;
RETURN CHAR = ENDFILE;
END RD$EOF;
HEXRECORD: PROCEDURE BYTE;
/* READ ONE RECORD INTO SBUFF AND CHECK FOR PROPER FORM
RETURNS 0 IF RECORD OK
RETURNS 1 IF END OF TAPE (:00000)
RETURNS 2 IF ERROR IN RECORD */
DECLARE XOFFSET BYTE; /* TRUE IF XOFF RECVD */
DECLARE NOERRS BYTE; /* TRUE IF NO ERRORS IN THIS RECORD */
PRINTERR: PROCEDURE(A);
/* PRINT ERROR MESSAGE IF NOERRS TRUE */
DECLARE A ADDRESS;
IF NOERRS THEN
DO; NOERRS = FALSE;
CALL PRINT(A);
END;
END PRINTERR;
CKXOFF: PROCEDURE;
IF XOFFSET THEN
DO; XOFFSET = FALSE;
CALL CLEARBUFF;
END;
END CKXOFF;
SAVECHAR: PROCEDURE BYTE;
/* READ CHARACTER AND SAVE IN BUFFER */
DECLARE I BYTE;
IF NOERRS THEN
DO;
DO WHILE (I := GETSOURCE) = XOFF; XOFFSET = TRUE;
END;
HBUFF(HSOURCE) = I;
IF (HSOURCE := HSOURCE + 1) >= LAST(HBUFF) THEN
CALL PRINTERR(.('RECORD TOO LONG$'));
RETURN I;
END;
RETURN ENDFILE; /* ON ERROR FLAG */
END SAVECHAR;
DECLARE (M, RL, CS, RT) BYTE,
LDA ADDRESS; /* LOAD ADDRESS WHICH FOLLOWS : */
RDHEX: PROCEDURE BYTE;
DECLARE H BYTE;
IF (H := SAVECHAR) - '0' <= 9 THEN
RETURN H-'0';
IF H - 'A' > 5 THEN
CALL PRINTERR(.('INVALID DIGIT$'));
RETURN H - 'A' + 10;
END RDHEX;
RDBYTE: PROCEDURE BYTE;
/* READ TWO HEX DIGITS */
RETURN SHL(RDHEX,4) OR RDHEX;
END RDBYTE;
RDCS: PROCEDURE BYTE;
/* READ BYTE WITH CHECKSUM */
RETURN CS := CS + RDBYTE;
END RDCS;
RDADDR: PROCEDURE ADDRESS;
/* READ DOUBLE BYTE WITH CHECKSUM */
RETURN SHL(DOUBLE(RDCS),8) OR RDCS;
END RDADDR;
NOERRS = TRUE; /* NO ERRORS DETECTED IN THIS RECORD */
/* READ NEXT RECORD */
/* SCAN FOR THE ':' */
HSOURCE = 0;
DO WHILE (CS := SAVECHAR) <> ':';
HSOURCE = 0;
IF CS = ENDFILE THEN
DO; CALL PRINT(.('END OF FILE, CTL-Z',WHAT,'$'));
IF RDCHAR = ENDFILE THEN RETURN 1;
ELSE HSOURCE = 0;
END;
CALL CKXOFF;
END;
/* ':' FOUND */
CS = 0;
IF (RL := RDCS) = 0 THEN /* END OF TAPE */
DO; DO WHILE (RL := SAVECHAR) <> ENDFILE;
CALL CKXOFF;
END;
IF NOERRS THEN RETURN 1;
RETURN 2;
END;
/* RECORD LENGTH IS NOT ZERO */
LDA = RDADDR; /* LOAD ADDRESS */
/* READ WORDS UNTIL RECORD LENGTH EXHAUSTED */
RT = RDCS; /* RECORD TYPE */
DO WHILE RL <> 0 AND NOERRS; RL = RL - 1;
M = RDCS;
/* INCREMENT LA HERE FOR EXACT ADDRESS */
END;
/* CHECK SUM */
IF CS + RDBYTE <> 0 THEN
CALL PRINTERR(.('CHECKSUM ERROR$'));
CALL CKXOFF;
IF NOERRS THEN RETURN 0;
RETURN 2;
END HEXRECORD;
RDTAPE: PROCEDURE;
/* READ HEX FILE FROM HIGH SPEED READER TO 'HEX' FILE,
CHECK EACH RECORD FOR VALID DIGITS, AND PROPER CHECKSUM */
DECLARE (I,A) BYTE;
DO FOREVER;
DO WHILE (I := HEXRECORD) <= 1;
IF NOT (I = 1 AND IGNOR) THEN
DO A = 1 TO HSOURCE;
CALL PUTDEST(HBUFF(A-1));
END;
CALL PUTDEST(CR); CALL PUTDEST(LF);
IF I = 1 THEN /* END OF TAPE ENCOUNTERED */
RETURN;
END;
CALL CRLF; HBUFF(HSOURCE) = '$';
CALL PRINT(.HBUFF);
CALL PRINT(.('CORRECT ERROR, TYPE RETURN OR CTL-Z$'));
CALL CRLF;
IF RDCHAR = ENDFILE THEN RETURN;
END;
END RDTAPE;
setpswd: procedure;
declare (i,j) byte;
j = 23;
do i = 0 to 7;
dest.pwnam(i) = dxfcb(j) xor dxfcb(13);
j = j - 1;
end;
dest.pwmode = dxfcb(12);
end setpswd;
SETUPDEST: PROCEDURE;
call setduser; /* destination user */
call move(.odest,.dest,(frsize + nsize + 1)); /* save original dest */
DHEX = EQUAL(.odest.fcb(fext),.('HEX$'));
CALL MOVEXT(.('$$$'));
odest.fcb(6) = odest.fcb(6) or 80h;
call open(.odest); /* try to open destination file */
if dcnt <> 255 and rol(odest.fcb(8),1) then
do; odcnt = 255;
call close(.odest);
end;
else
odcnt = dcnt; /* and save error code */
if (odcnt = 255) and ((exten and 0fh) <> 0) then /* file exists */
call error(13,exten,1,.odest); /* but cant open - error */
if getpw then /* setup destination password */
do; call setsuser;
call move(.source,.dxfcb,fsize);
call rdxfcb(.dxfcb);
if dcnt = 255 then dest.pwnam(0) = 0;
else call setpswd;
call setduser;
end;
CALL DELETE(.DEST); /* REMOVE OLD $$$ FILE */
if dcnt = 255 and exten <> 0 then
/* cant delete temp file */
call error(18,exten,1,.dest);
CALL MAKE(.DEST); /* CREATE A NEW ONE */
IF DCNT = 255 THEN
if (exten and 0fh) = 0 then
call error(17,0,1,.dest); /* no directory space */
else call error(9,exten,1,.dest); /* make file error */
call setcuser; /* back to current user */
DEST.FCB(32),NDEST = 0;
END SETUPDEST;
SETUPSOURCE: PROCEDURE;
HARDEOF = 0FFFFH;
f1,f2,f3,f4,ro,sys = 0;
CALL SETSUSER; /* SOURCE USER */
source.fcb(6) = source.fcb(6) or 80h;
CALL OPEN(.SOURCE); /* open source in r/o mode */
if rol(source.fcb(1),1) then f1 = 80h;
if rol(source.fcb(2),1) then f2 = 80h;
if rol(source.fcb(3),1) then f3 = 80h;
if rol(source.fcb(4),1) then f4 = 80h;
if rol(source.fcb(9),1) then ro = 80h;
if rol(source.fcb(10),1) then sys = 80h;
CALL SETCUSER; /* BACK TO CURRENT USER */
IF (NOT RSYS) AND ROL(SOURCE.FCB(10),1) THEN
/* skip system file */
DCNT = 255;
IF DCNT = 255 THEN
if (exten and 0fh) = 0 then
call error(10,0,0,.source); /* file not found */
else call error(13,exten,1,.source); /* open file error */
SOURCE.FCB(32) = 0;
/* CAUSE IMMEDIATE READ */
SCOM = EQUAL(.SOURCE.FCB(FEXT),.('COM$'));
NSOURCE = SBLEN;
END SETUPSOURCE;
CK$STRINGS: PROCEDURE;
IF STARTS > 0 THEN
call error(11,0,0,0); /* START NOT FOUND */
IF QUITS > 0 THEN
call error(12,0,0,0); /* QUIT NOT FOUND */
END CK$STRINGS;
CLOSEDEST: PROCEDURE;
DO WHILE (LOW(NDEST) AND 7FH) <> 0;
CALL PUTDEST(ENDFILE);
END;
CALL CK$STRINGS;
CALL WRITEDEST;
call setduser; /* destination user */
CALL CLOSE(.DEST);
IF DCNT = 255 THEN
call error(14,exten,1,.dest); /* CLOSE FILE */
IF odcnt <> 255 THEN /* FILE EXISTS */
DO;
call close(.odest);
IF ROL(odest.fcb(9),1) THEN /* READ ONLY */
DO;
IF NOT WRROF THEN
DO;
CALL PRINT (.('DESTINATION IS R/O, DELETE (Y/N)?$'));
IF UTRAN(RDCHAR) <> 'Y' THEN
DO; CALL PRINT(.('**NOT DELETED**$'));
CALL CRLF;
CALL DELETE(.DEST);
call setcuser; /* back to current user */
RETURN;
END;
CALL CRLF;
END;
END;
/* reset r/o and sys attributes */
odest.fcb(9) = odest.fcb(9) and 7fh;
odest.fcb(10) = odest.fcb(10) AND 7FH;
CALL SETIND(.odest);
CALL DELETE(.odest);
END;
CALL MOVE(.odest.fcb,.dest.fcb(16),16); /* READY FOR RENAME */
CALL RENAME(.DEST);
/* set destination attributes same as source */
odest.fcb(1) = (odest.fcb(1) and 07fh) or f1;
odest.fcb(2) = (odest.fcb(2) and 07fh) or f2;
odest.fcb(3) = (odest.fcb(3) and 07fh) or f3;
odest.fcb(4) = (odest.fcb(4) and 07fh) or f4;
odest.fcb(8) = (odest.fcb(8) and 07fh);
odest.fcb(9) = (odest.fcb(9) and 07fh) or ro;
odest.fcb(10) = (odest.fcb(10) and 07fh) or sys;
odest.fcb(11) = (odest.fcb(11) and 07fh);
call setind(.odest);
if archiv then /* set archive bit */
do; call setsuser;
source.fcb(11) = source.fcb(11) or 080h;
source.fcb(12) = 0;
call setind(.source);
end;
call setcuser; /* back to current user */
END CLOSEDEST;
SIZE$NBUF: PROCEDURE;
/* COMPUTE NUMBER OF BUFFERS - 1 FROM DBLEN */
NBUF = (SHR(DBLEN,7) AND 0FFH) - 1;
/* COMPUTED AS DBLEN/128-1, WHERE DBLEN <= 32K (AND THUS
NBUF RESULTS IN A VALUE <= 2**15/2**7-1 = 2**8-1 = 255) */
END SIZE$NBUF;
SET$DBLEN: PROCEDURE;
/* ABSORB THE SOURCE BUFFER INTO THE DEST BUFFER */
SBASE = .MEMORY;
IF DBLEN >= 4000H THEN DBLEN = 7F80H;
ELSE DBLEN = DBLEN + SBLEN;
CALL SIZE$NBUF;
END SET$DBLEN;
SIZE$MEMORY: PROCEDURE;
/* SET UP SOURCE AND DESTINATION BUFFERS */
SBASE = .MEMORY + SHR(MEMSIZE - .MEMORY,1);
SBLEN, DBLEN = SHR((MEMSIZE - .MEMORY) AND 0FF00H,1);
CALL SIZE$NBUF;
END SIZE$MEMORY;
COPYCHAR: PROCEDURE;
/* PERFORM THE ACTUAL COPY FUNCTION */
DECLARE RESIZED BYTE; /* TRUE IF SBUFF AND DBUFF COMBINED */
IF (RESIZED := (BLOCK AND PSOURCE <> 0)) THEN /* BLOCK MODE */
CALL SET$DBLEN; /* ABSORB SOURCE BUFFER */
IF HEXT OR IGNOR THEN /* HEX FILE */
CALL RDTAPE;
ELSE
DO WHILE NOT RD$EOF;
CALL PUTDEST(CHAR);
END;
IF RESIZED THEN
DO; CALL CLEARBUFF;
CALL SIZE$MEMORY;
END;
END COPYCHAR;
SIMPLECOPY: PROCEDURE;
DECLARE I BYTE;
REAL$EOF: PROCEDURE BYTE;
RETURN HARDEOF <> 0FFFFH;
END REALEOF;
CALL SIZE$MEMORY;
CALL SETUPDEST;
CALL SETUPSOURCE;
/* FILES READY FOR DIRECT COPY */
FASTCOPY = TRUE;
/* LOOK FOR PARAMETERS */
DO I = 0 TO 25;
IF CONT(I) <> 0 THEN
DO;
IF NOT(I=6 OR I=10 OR I=14 OR I=17 OR I=21 OR I=22) THEN
/* NOT OBJ OR VERIFY */
FASTCOPY = FALSE;
END;
END;
IF FASTCOPY THEN /* COPY DIRECTLY TO DBUFF */
DO; CALL SET$DBLEN; /* EXTEND DBUFF */
DO WHILE NOT REAL$EOF;
CALL FILLSOURCE;
IF REAL$EOF THEN NDEST = HARDEOF;
ELSE NDEST = tblen;
CALL WRITEDEST;
END;
CALL SIZE$MEMORY; /* RESET TO TWO BUFFERS */
END;
ELSE
CALL COPYCHAR;
call setsuser;
CALL CLOSE(.SOURCE);
call setcuser;
CALL CLOSEDEST;
END SIMPLECOPY;
MULTCOPY: PROCEDURE;
DECLARE (NEXTDIR, NDCNT, NCOPIED) ADDRESS;
PRNAME: PROCEDURE;
/* PRINT CURRENT FILE NAME */
DECLARE (I,C) BYTE;
CALL CRLF;
DO I = 1 TO FNSIZE;
IF (C := odest.fcb(I)) <> ' ' THEN
DO; IF I = FEXT THEN CALL PRINTCHAR('.');
CALL PRINTCHAR(C);
END;
END;
END PRNAME;
archck: procedure byte;
/* check if archive bit is set in any extent of source file */
call setsuser;
source.fcb(12) = what;
call search(.source);
do while dcnt <> 255;
call move(.buff+shl(dcnt and 11b,5)+1,.source.fcb(1),15);
if not rol(source.fcb(11),1) then
do; source.fcb(12) = 0;
call setcuser;
return 1;
end;
call searchn;
end;
call setcuser;
return 0;
end archck;
/* initialize counters if not error retry */
if eretry = 0 then NEXTDIR, NCOPIED = 0;
DO FOREVER;
/* FIND A MATCHING ENTRY */
CALL SETSUSER; /* SOURCE USER */
CALL SETDMA(.BUFF);
searfcb(12) = 0;
CALL SEARCH(.SEARFCB);
NDCNT = 0;
DO WHILE (DCNT <> 255) AND NDCNT < NEXTDIR;
NDCNT = NDCNT + 1;
CALL SEARCHN;
END;
CALL SETCUSER;
/* FILE CONTROL BLOCK IN BUFFER */
IF DCNT = 255 THEN
DO; IF NCOPIED = 0 THEN
call error(10,0,0,.searfcb); /* file not found */
CALL CRLF;
RETURN;
END;
NEXTDIR = NDCNT + 1;
/* GET THE FILE CONTROL BLOCK NAME TO DEST */
CALL MOVE(.BUFF + SHL(DCNT AND 11B,5)+1,.odest.fcb(1),15);
CALL MOVE(.odest.fcb(1),.SOURCE.FCB(1),15); /* FILL BOTH FCB'S */
if not archiv or archck then
do; odest.fcb(12) = 0;
IF RSYS OR NOT ROL(odest.fcb(10),1) THEN /* OK TO READ */
DO; if not kilds then /* kill display option */
do; IF NCOPIED = 0 THEN
CALL PRINT(.('COPYING -$'));
CALL PRNAME;
end;
ncopied = ncopied + 1;
CALL SIMPLECOPY;
END;
end;
END;
END MULTCOPY;
CK$DISK: PROCEDURE;
/* error if same user and same disk */
IF (odest.user = source.user) and (odest.fcb(0) = source.fcb(0)) THEN
CALL FORMERR;
END CK$DISK;
CK$EOL: PROCEDURE;
CALL DEBLANK;
IF CHAR <> CR THEN CALL FORMERR;
END CK$EOL;
SCANDEST: PROCEDURE(COPYFCB);
DECLARE COPYFCB ADDRESS;
CALL CK$EOL;
CALL MOVE(.source.fcb(1),COPYFCB,35);
CALL CK$DISK;
END SCANDEST;
SCANEQL: PROCEDURE;
CALL SCAN(.SOURCE);
IF NOT (TYPE = SPECL AND CHAR = '=') THEN CALL FORMERR;
END SCANEQL;
PIPENTRY:
/* BUFFER AT 80H CONTAINS REMAINDER OF LINE TYPED
FOLLOWING THE COMMAND 'PIP' - IF ZERO THEN PROMPT TIL CR */
CALL MOVE(.BUFF,.COMLEN,80H);
MULTCOM = COMLEN = 0;
if multcom then
do; call printx(.('MP/M II PIP VERSION 2.0$'));
call crlf;
end;
/* GET CURRENT CP/M VERSION */
IF CVERSION < VERSION THEN
DO;
CALL PRINT(.('REQUIRES MP/M II$'));
CALL BOOT;
END;
CUSER = GETUSER; /* GET CURRENT USER */
CDISK = getdisk; /* GET CURRENT DISK */
call errmode(255); /* set return error mode */
eretry = 0;
RETRY:
/* ENTER HERE ON ERROR EXIT FROM THE PROCEDURE 'ERROR' */
if eretry <> 0 then
do; call multcopy;
comlen = multcom;
end;
CALL SIZE$MEMORY;
/* MAIN PROCESSING LOOP. PROCESS UNTIL CR ONLY */
DO FOREVER;
C1, C2, C3 = 0; /* LINE COUNT = 000000 */
PUTNUM = TRUE; /* ACTS LIKE LF OCCURRED ON ASCII FILE */
CONCNT,COLUMN = 0; /* PRINTER TABS */
LINENO = 254; /* INCREMENTED TO 255 > PAGCNT */
/* READ FROM CONSOLE IF NOT A ONELINER */
IF MULTCOM THEN
DO; CALL PRINTCHAR('*'); CALL RDCOM;
CALL CRLF;
END;
CBP = 255;
IF COMLEN = 0 THEN /* SINGLE CARRIAGE RETURN */
CALL BOOT; /* normal exit from pip here */
/* LOOK FOR SPECIAL CASES FIRST */
PSOURCE,PDEST = 0;
fastcopy = false;
getpw = true;
CALL SCAN(.odest);
IF TYPE = PERIPH THEN GO TO SIMPLECOM;
IF TYPE = DISKNAME THEN
DO;
CALL SCANEQL;
CALL SCAN(.SOURCE);
/* MAY BE MULTI COPY */
IF TYPE <> FILE THEN CALL FORMERR;
IF AMBIG THEN /* FORM IS A:=B:AFN */
DO; searfcb(0) = source.fcb(0);
CALL SCANDEST(.searfcb(1));
CALL MULTCOPY;
END;
ELSE
DO; CALL SCANDEST(.odest.fcb(1));
/* FORM IS A:=B:UFN */
CALL SIMPLECOPY;
END;
GO TO ENDCOM;
END;
IF TYPE <> FILE OR AMBIG THEN CALL FORMERR;
CALL SCANEQL;
CALL SCAN(.SOURCE);
IF TYPE = DISKNAME THEN
DO;
CALL CK$DISK;
call move(.odest.fcb(1),.source.fcb(1),(frsize + nsize));
CALL CK$EOL;
CALL SIMPLECOPY;
GO TO ENDCOM;
END;
/* MAY BE POSSIBLE TO DO A FAST DISK COPY */
IF TYPE = FILE THEN /* FILE TO FILE */
DO; CALL DEBLANK;
IF CHAR <> CR THEN GO TO SIMPLECOM;
/* FILE TO FILE */
CALL SIMPLECOPY;
GO TO ENDCOM;
END;
SIMPLECOM:
CBP = 255; /* READY FOR RESCAN */
/* OTHERWISE PROCESS SIMPLE REQUEST */
CALL SCAN(.odest);
IF (TYPE < FILE) OR AMBIG THEN /* DELIMITER OR ERROR */
call error(3,0,0,0); /* invalid destination */
DHEX = FALSE;
IF TYPE = FILE THEN
DO; /* DESTINATION IS A FILE, SAVE EXTENT NAME */
CALL SETUPDEST;
CHAR = 255;
END;
ELSE /* PERIPHERAL NAME */
IF CHAR >= NULP OR CHAR <= RDR THEN
call error(3,0,0,0); /* invalid destination */
IF (PDEST := CHAR + 1) = PUNP THEN
CALL NULLS;
/* NOW SCAN THE DELIMITER */
CALL SCAN(.SOURCE);
IF TYPE <> SPECL OR CHAR <> '=' THEN
call formerr; /* invalid format */
/* OTHERWISE SCAN AND COPY UNTIL CR */
COPYING = TRUE;
DO WHILE COPYING;
CALL SCAN(.SOURCE);
SCOM = FALSE;
IF TYPE = FILE AND NOT AMBIG THEN /* A SOURCE FILE */
DO;
CALL SETUPSOURCE;
CHAR = 255;
END;
ELSE IF TYPE <> PERIPH OR (CHAR <= LST AND CHAR > RDR) THEN
call error(4,0,0,0); /* invalid source */
SCOM = SCOM OR OBJ; /* MAY BE ABSOLUTE COPY */
PSOURCE = CHAR + 1;
IF CHAR = NULP THEN CALL NULLS;
ELSE IF CHAR = EOFP THEN
CALL PUTDEST(ENDFILE);
ELSE
DO; /* DISK COPY */
IF (CHAR < HSRDR AND DHEX) THEN HEXT = 1;
/* HEX FILE SET IF SOURCE IS RDR AND DEST IS HEX FILE */
if (pdest = 10 or pdest = 11) then /* periph = prn or lst */
do;
if conatlst = 255 then
call error(15,0,0,0); /* printer busy */
IF PDEST = PRNT THEN
DO; NUMB = 1;
IF TABS = 0 THEN TABS = 8;
IF PAGCNT = 0 THEN PAGCNT = 1;
END;
end;
CALL COPYCHAR;
END;
CALL CK$STRINGS;
/* READ ENDFILE, GO TO NEXT SOURCE */
if type = file then
do;
call setsuser;
call close(.source);
call setcuser;
end;
CALL SCAN(.SOURCE);
IF TYPE <> SPECL OR (CHAR <> ',' AND CHAR <> CR) THEN
call error(16,0,0,0); /* invalid separator */
COPYING = CHAR <> CR;
END;
/* IF NECESSARY, CLOSE FILE OR PUNCH TRAILER */
IF PDEST = PUNP THEN
DO; CALL PUTDEST(ENDFILE); CALL NULLS;
END;
IF PDEST = 0 THEN /* FILE HAS TO BE CLOSED AND RENAMED */
CALL CLOSEDEST;
/* COMLEN SET TO 0 IF NOT PROCESSING MULTIPLE COMMANDS */
ENDCOM:
COMLEN = MULTCOM;
END; /* DO FOREVER */
END;