;EDITS ;232 ADD COMPLETION DATE TO OUTPUT PATH-CHARACTER COMMAND ;233 CHANGE OUTPUT SCHEDULE TO ONLY INCLUDE INCOMPLETE TASKS ;234 MAKE SET SCHEDULE-DATE ANSWER PART OF DATABASE ;235 OUTPUT A WARNING IF SCHEDULE PASS NEEDED ;236 MARK CRITICAL PATHS CORRECTLY EVEN IF WEEKENDS COME BETWEEN TASKS ;237 [TEMP] DO NOT ROUND START DATES TO WORK DAYS (BREAKS CP ; ANALYSIS) ;240 IF A PROJECT HAS ALREADY STARTED (HAS ACTUAL START DATE) AND ; THERE IS A TIME-TO-DATE AND NO DEVELOPER, THE END DATE IS WRONG. ;241 STORE TSKLST INDEX IN TASK BLOCK. USE THE STORED VALUE TO SPEED ; UP LPCHK,CKAV1A,FNDTKI ;242 PANTT DIES A HORRIBLE DEATH IF ANY STRING IS TOO LONG. ADD SOME ; CODE TO DEFEND PANTT FROM LONG STRINGS. ;243 FIX PERT CHART BUG CAUSED BY EDIT 241 ;244 PLOTTER SOFTWARE HAS A LIMIT OF 15 BITS WORTH OF X,Y DATA (BECAUSE ; PDP-11 STORE X,Y AS SIGNED NUMBERS IN 16 BITS). OUTPUT WARNING IF ; DATA WILL OVERFLOW. ;245 SPEED UP SCHEDULER BY REMEMBERING THAT THERE ARE NO LOOPS. ;246 ALLOW READING DATABASE IF WRITE ACCESS IS NOT ALLOWED. ;247 "?" TO NAME OF DATABASE FAILS ;250 START WORK ON ATTRIBUTES ;251 COMPLETE ATTRIBUTE CODE ;252 MAKE SURE THAT ATTRIBUTE CODE TESTS FOR VERSION 2 TASK BLOCKS VMAJOR==4 ;MAJOR VERSION NUMBER VMINOR==3 ;MINOR VEDIT==252 ;EDIT NUMBER VWHO==0 ;CUSTOMER EDIT TITLE PANTT - PROGRAM TO PRODUCE PERT AND GANTT CHARTS SUBTTL PETER M. HURLEY, NOVEMBER 1,1977 SEARCH MONSYM,MACSYM,PARUNV EXTERNAL PARSE .REQUIRE PARSE .REQUIRE SYS:MACREL SALL VPANTT==B2+B11+B17+VEDIT T1=1 T2=2 T3=3 T4=4 Q1=5 Q2=6 Q3=7 P1=10 P2=11 P3=12 P4=13 P5=14 P6=15 CX=16 P=17 ;RANDOM VARIABLES MAXLEN==^D79 ;MAXIMUM STRING LENGTH MAXLNW==MAXLEN/5+^D10 ;NUMBER OF WORDS TO STORE MAX LENGTH STRING ; PLUS A LARGE FUDGE FACTOR BOXLEN==^D10 ;NUMBER OF LINES PER BOX GW==4 ;WIDTH OF GANTT TASK NGROW==6*GW ;NUMBER OF TASKS BETWEEN DATE LINES NOSLAK==400000,,0 ;NO SLACK VALUE SET IN TKSLK DEFINE ERRMES (TEXT) < JSP [ HRROI T1,[ASCIZ\? TEXT\] PSOUT HALTF JRST PANTT]> DEFINE WARN (INST,TEXT) < JSP CX,[HRROI T1,[ASCIZ\ % TEXT \] PSOUT IFNB ,< INST> JRST .+1]> DEFINE TYPE (AC,TEXT) < CALL [ MOVE CX,[[ASCIZ\TEXT\],,AC] CALLRET TYPRTN]> DEFINE CHKTYP (TYP) < CAIE T1,.CM'TYP ERRMES ()> DEFINE RETBAD (A,B) < IFB ,< IFB ,< RET> IFNB ,< JRST [ MOVEI T1,A RET]>> IFNB ,< JRST [ B RETBAD (A)]>> DEFINE PION < CALL PION.> DEFINE PIOFF < CALL PIOFF.> DEFINE LOCK (A) <> ;LOCK MACRO IS A NOP DEFINE UNLOCK (A) <> DEFINE SAVEQ < JSP CX,SAVQ> DEFINE SAVEPQ < JSP CX,SAVPQ> DEFINE SAVET < JSP CX,SAVT> DEFINE SAVEP < JSP CX,SAVP> ;MACRO TO CHECK TO SEE IF A STRING IS TOO LONG. IF IT IS TOO LONG IT IS ; TRUNCATED. DEFINE TRUNC(LEN,MAX,TYPE,RTN,LNG,%A),< MOVE CX,LEN ;GET CURRENT LENGTH XLIST CAIG CX,MAX ;TOO LONG? JRST %A ;NO--LEAVE IT ALONE PUSH P,T1 ;SAVE A JSYS AC TMSG < % TYPE STRING TOO LONG AT RTN > POP P,T1 ;RESTORE AC MOVEI CX,MAX ;TRUNCATE THE STRING MOVEM CX,LEN ; .. IFNB ,< JRST LNG ;DO SOMETHING SPECIAL > %A:! LIST > ;MACRO TO CHECK VERSION OF A BLOCK DEFINE CHKVER(VERSION,PTR,TO),< XLIST LOAD CX,BLKVER,PTR ;GET VERSION CAIGE CX,VERSION ;GOOD ENOUGH? JRST TO ;NO--GO AWAY LIST > ;DATA STRUCTURES USED IN PANTT.DATA-BASE DEFSTR (BLKTYP,-1,8,9) ;TYPE OF BLOCK DEFSTR (BLKVER,-1,17,9) ;VERSION NUMBER OF FORMAT OF BLOCK DEFSTR (BLKLEN,-1,35,18) ;LENGTH OF BLOCK .BLKLN==1 ;LENGTH OF THE HEADER BLOCK DEFSTR (PJNAM,0,35,36) ;PROJECT NAME DEFSTR (PJDSC,1,35,36) ;PROJECT DESCRIPTION DEFSTR (PJTKT,2,35,36) ;POINTER TO TASK TABLE DEFSTR (PJDVL,3,35,36) ;POINTER TO DEVELOPER LIST DEFSTR (PJFLG,4,35,36) ;PROJECT FLAGS DEFSTR (PJPRF,5,35,36) ;PROJECT PREFERENCE CODE .PJLEN==10 ;LENGTH OF A PROJECT BLOCK DEFSTR (TKNAM,0,35,36) ;TASK NAME DEFSTR (TKDSC,1,35,36) ;TASK DESCRIPTION DEFSTR (TKPRJ,2,35,36) ;POINTER TO PROJECT BLOCK DEFSTR (TKASD,3,35,36) ;ACTUAL STARTING DATE DEFSTR (TKAFD,4,35,36) ;ACTUAL FINISH DATE DEFSTR (TKESD,5,35,36) ;EARLIEST STARTING DATE DEFSTR (TKEFD,6,35,36) ;EARLIEST FINISH DATE DEFSTR (TKLSD,7,35,36) ;LATEST START DATE DEFSTR (TKLFD,10,35,36) ;LATEST FINISH DATE DEFSTR (TKELN,11,35,36) ;ESTIMATED TASK LENGTH DEFSTR (TKALN,12,35,36) ;ACTUAL TASK LENGTH DEFSTR (TKTTD,13,35,36) ;TIME SPENT ON TASK TO DATE DEFSTR (TKTAD,14,35,36) ;DATE WHEN TIME-TO-DATE WAS SET DEFSTR (TKDLP,15,35,36) ;BLOCKING TASK LIST POINTER DEFSTR (TKBLP,16,35,36) ;BLOCKED TASK LIST POINTER DEFSTR (TKDVL,17,35,36) ;POINTER TO DEVELOPER LIST DEFSTR (TKFLG,20,35,36) ;TASK FLAGS TK%BKG==1B0 ;BACKGROUND TASK TK%MIL==1B1 ;MILESTONE TK%CP==1B2 ;CRITICAL PATH TK%ADR==1B3 ;ADD DEVELOPERS REQUIRED MSKSTR (TKBKG,20,TK%BKG) MSKSTR (TKMIL,20,TK%MIL) MSKSTR (TKCP,20,TK%CP) MSKSTR (TKADR,20,TK%ADR) DEFSTR (TKPTC,20,35,7) ;PATH CHARACTER DEFSTR (TKMSD,21,35,36) ;MINIMUM START DATE DEFSTR (TKXCD,22,35,36) ;EXPECTED COMPLETION DATE DEFSTR (TKXSD,23,35,36) ;EXPECTED STARTING DATE DEFSTR (TKPRF,24,35,36) ;TASK PREFERENCE VALUE DEFSTR (TKPL,25,35,36) ;PATH LIST DEFSTR (TKSLK,26,35,36) ;SLACK DEFSTR (TKRCD,27,35,36) ;REMEMBERED COMPLETION DATE DEFSTR (TKRSD,30,35,36) ;REMEMBERED START DATE DEFSTR (TKTKI,31,17,18) ;TASK LIST INDEX DEFSTR (TKATR,32,35,36) ;POINTER TO ATTRIBUTE LIST .TKLEN==40 ;LENGTH OF TASK BLOCK DEFSTR (DVNAM,0,35,36) ;DEVELOPER'S NAME STRING DEFSTR (DVRAT,1,35,36) ;RATE OF WORK ON THIS TASK DEFSTR (DVHCR,2,35,36) ;HANDICAP RATING DEFSTR (DVBKP,3,35,36) ;POINTER BACK TO TASK/PROJECT BLOCK DEFSTR (DVLNK,4,35,36) ;POINTER TO NEXT DEVELOPER ON LIST .DVLEN==5 ;LENGTH OF EACH DEVELOPER ENTRY DEFSTR (DPTKP,0,35,36) ;POINTER TO BLOCKED TASK DEFSTR (DPBTK,1,35,36) ;POINTER TO BLOCKING TASK DEFSTR (DPDLP,2,35,36) ;BLOCKING TASK LIST POINTER DEFSTR (DPBLP,3,35,36) ;BLOCKED LIST POINTER .DPLEN==4 DEFSTR (HOLSIZ,0,17,18) ;SIZE OF HOLTAB DEFSTR (HOLUSE,0,35,18) ;NUMBER OF ENTRIES USED .HOLLN==^D100 ;SIZE OF HOLTAB .PTHLN==<^D36+1+4>/5*5 ;ROOM ENOUGH FOR ALL ALPHA-NUMERIC CHARS ;ATTRIBUTE BLOCKS DEFSTR (ATRLK,0,35,36) ;POINTER TO NEXT ATTRIBUTE BLOCK DEFSTR (ATRFL,1,35,36) ;FLAG WORD AT%LNG==1B0 ;DESCRIPTION IS LONG MSKSTR (ATRLG,1,AT%LNG) ;DESCRIPTION IS LONG DEFSTR (ATRNM,2,35,36) ;POINTER TO NAME OF ATTRIBUTE DEFSTR (ATRVL,3,35,36) ;POINTER TO VALUE OF ATTRIBUTE .ATRLN=4 ;TYPE CODES FOR BLOCKS IN THE DATABASE .TYPJT==501 ;TYPE CODE FOR PROJECT TABLE .TYTKT==502 ;TYPE CODE FOR TASK TABLE .TYDSC==503 ;TYPE CODE FOR A DESCRIPTION BLOCK .TYDEV==504 ;TYPE CODE FOR A DELELOPER BLOCK .TYNAM==505 ;TYPE CODE FOR A NAME BLOCK .TYTSK==506 ;TYPE CODE FOR A TASK BLOCK .TYPRJ==507 ;TYPE CODE FOR A PROJECT BLOCK .TYDEP==510 ;TYPE CODE OF DEPENDENCY BLOCK .TYHOL==511 ;TYPE CODE FOR HOLTAB .TYPTH==512 ;TYPE CODE FOR PATH LIST .TYATR==513 ;TYPE CODE FOR ATTRIBUTE LIST .VNPJT==1 ;VERSION NUMBER FOR PROJECT TABLE .VNTKT==1 ;VERSION NUMBER FOR TASK TABLE .VNDSC==1 ;VERSION NUMBER FOR A DESCRIPTION BLOCK .VNDEV==1 ;VERSION NUMBER FOR A DELELOPER BLOCK .VNNAM==1 ;VERSION NUMBER FOR A NAME BLOCK .VNTSK==2 ;VERSION NUMBER FOR A TASK BLOCK .VNPRJ==1 ;VERSION NUMBER FOR A PROJECT BLOCK .VNDEP==1 ;VERSION NUMBER OF DEPENDENCY BLOCK .VNHOL==1 ;VERSION NUMBER OF HOLTAB .VNPTH==1 ;VERSION NUMBER OF PATH LIST .VNATR==1 ;VERSION NUMBER OF ATRIBUTE BLOCK TABINC==20 ;EACH EXPANSION OF A TABLE GROWS THIS AMOUNT ;SCHEDULER BLOCKS ;THESE BLOCKS ARE USED TO SCHEDULE TASKS AND GENERATE GANTT CHARTS. THEY ARE ; POINTED TO BY DEVTAB. SCHEDULER BLOCKS ARE NOT PART OF THE DATABASE. DEFSTR (SCHTK,0,35,36) ;TASK ADR DEFSTR (SCHSD,1,35,36) ;START DATE DEFSTR (SCHFD,2,35,36) ;FINISH DATE DEFSTR (SCHRT,3,35,36) ;RATE DEFSTR (SCHLN,4,35,36) ;LINK TO NEXT BLOCK .SCHLN==5 ;STORAGE ;DATA BASE FILE DEFINITIONS NDBPAG==200 ;NUMBER OF PAGES IN DATA BASE DBPAG==100 ;PAGE 0 OF DATA BASE ;PAGE 0 OF THE DATA BASE FILE DBORG=DBPAG*1000 ;ORIGIN OF WHERE TO MAP THIS FILE DBSIZ=DBORG+1 ;NUMBER OF PAGES TO BE MAPPED FRSHDR=DBSIZ+1 ;FREE STORAGE HEADER PRJTBL=FRSHDR+6 ;POINTER TO THE PROJECT TABLE DEVTBP=PRJTBL+1 ;POINTER TO DEVELOPER TABLE HOLTAB=DEVTBP+1 ;POINTER TO HOLIDAY TABLE SKDITD=HOLTAB+1 ;SCHEDULER DATE AND TIME NOLOOP=SKDITD+1 ;-1 IF NO LOOPS IN DATA BASE ;FREE SPACE POOL WITHIN DATA BASE FILE FSP==DBPAG+1 ;FIRST FREE SPACE PAGE NFSP==NDBPAG-1 ;SIZE OF FREE SPACE POOL FSADR=FSP*1000 ;FREE SPACE ADR FSLEN==NFSP*1000 ;LENGTH OF FREE SPACE POOL ;LOCAL PROGRAM STORAGE ASSIGNMENTS MAXTSK==2000 ;MAXIMUM NUMBER OF TASKS MAXDEV==200 ;MAXIMUM NUMBER OF DEVELOPERS DEFINE ASG (NAM,LEN) < NAM=ASGVAL ASGVAL==ASGVAL+LEN> ASGVAL==*1000 PDLEN==1000+5*MAXTSK ASG PDL,PDLEN ;PUSH DOWN LIST ZERBEG==ASGVAL ;START ZEROING HERE ON INITIALIZATION ASG TSKTBL,1 ;POINTER TO THE CURRENT TASK TABLE ASG DBJFN,1 ;DATA BASE JFN ASG TLJFN,1 ;TRANSACTION LOG JFN ASG TRAFLG,1 ;FLAG FOR THE FIRST TRANSACTION WRITE ASG RONLY,1 ;0: NORMAL -1: READ ONLY ASG PERTPA,1 ;PERT PLACEMENT ALGORITHM ;0: DEFAULT ;1: ADVANCED ASG SLOB,1 ;IF NON-ZERO INHIBIT LOGGING ASG LINCNT,1 ;LINE COUNTER FOR USE DURING REPORTS ASG COLUMN,1 ;COLUMN COUNTER FOR TYPE OUT GTJBLN==16 ASG GTJBLK,GTJBLN ;BLOCK FOR LONG FORM GTJFN STRNGL==2000 ;STRING TO HOLD DESCRIPTIONS STRNGC==STRNGL*5-1 ;NUMBER OF CHARACTERS IN STRING ASG STRING,STRNGL ANSWRL==200 ASG ANSWER,ANSWRL ;BLOCK TO RECEIVE PARSED COMMANDS ASG CMDBUF,STRNGL+^D200*ANSWRL ;BLOCK TO HOLD THE COMMAND TEXT ASG CMDPTR,1 ;POINTER TO WHERE TO STORE THE COMMAND ASG GANTSD,1 ;START DATE OF GANTT CHART ASG GNTRMX,1 ;MAXIMUM GANTT ROW ASG GNTCMX,1 ;MAXIMUM GANNT COL ZEREND==ASGVAL ;END OF AREA TO BE ZEROED NPW==^D15 ;MAX WITDH IN PAGES OF GANTT CHART NCOL==^D132*NPW ;GANTT CHART SIZE NROW==^D200 NROW==*NGROW ;MODULO DATE LINES ROWLEN==/6 ROWSTL==NROW*ROWLEN ASG ROWOFS,1 ;OFFSET ROW NUMBER ASG ROWSTG,ROWSTL DEFINE BLDGST(A) < ASG GST'A,</5>> ZZ==0 REPEAT GW, NLVL==^D200 ;MAX NUMBER OF LEVELS IN A PERT CHART SPCTBL==/^D36 ;LENGTH OF A LINE IN THE SPACE TABLE SPCTBS==NLVL*SPCTBL ASG SPCTAB,SPCTBS ;TABLE TO KEEP TRACK OF SPACE BTEWEEN BOXES ;STORAGE FOR PERT SELECTION FEATURE ASG SELFLG,1 ;-1 IF SELECTING PERT BOXES ;0 IF NOT ASG SELCNT,1 ;NUMBER OF THINGS SELECTED MAXSEL==MAXTSK/8 ;FIELDS WITHIN SELTAB DEFSTR(SLTTYP,SELTAB,17,9) ;TYPE OF THING SELECTED DEFSTR(SLTDAT,SELTAB,35,18) ;DATA FOR SELECTION ASG SELTAB,MAXSEL ;TABLE OF THINGS SELECTED ;SCHEDULER STORAGE SKDTBL==ASGVAL ASG TSKLST,MAXTSK ;LIST OF TASKS ;LH: USUALLY ZERO, -1 IN THE MIDDLE OF ; SCHEDULE PASS AND THIS TASK NOT PROCESSED ;RH: ADDRESS OF TASK BLOCK ASG TSKSDL,MAXTSK ;START DATES OF EACH TASK ASG TSKFDL,MAXTSK ;FINISH DATE OF EACH TASK ;THE NEXT 5 TABLES ARE USED DURING PERT GENERATION ASG TSKPOS,MAXTSK ;POSITION OF TASK BOX ON CHART ;COL # OF LEFT END OF BOX, SET BY SETPOS ; OFFSET BY FIXPOS ASG TSKSVP,MAXTSK ;BEST VALUE OF TSKPOS (USED BY HDPLC) ASG TSKSKD,MAXTSK ;LEVEL # ,, COL # ;LH: C(LH) * IS TOP OF BOX ; SET BY PERT0 ;RH: SEEMS UNUSED ASG TSKWID,MAXTSK ;WIDTH OF TASK BOX ;SET BY SETWID CALLING BOXWID ASG TSKINV,MAXTSK ;INVISABLE TASK ;0 MEANS PERT, -1 MEANS DON'T PERT ASG AVLSST,MAXTSK ;SORTED SUM TABLE FOR PERT ;FLOATING POINT AVERAGE POSITION OF ALL ; THE BOXES CONNECTED TO THIS BOX. THIS ; TABLE IS PARALLEL TO AVLTSK NOT TSKLST ;THE NEXT 5 TABLES ARE TEMP STORAGE FOR THE SCHEDULER AND THE PERT/GANTT ; ROUTINES. THEY DO NOT HOLD GLOBAL DATA FROM ONE FUNCTION TO THE NEXT ASG AVLTSK,MAXTSK ;LIST OF AVAILABLE TASKS ;THIS LIST HOLDS C(AVLCNT) TASKS. DURING ; PERT IT HOLDS ONE ROW OF THE PERT CHART. ;LH: SOMETIMES FLAGS BUT USUALLY ZERO ;RH: TSKLST INDEX ASG AVLSDL,MAXTSK ;START DATES OF AVAILABLE TASKS ASG SKDLST,MAXTSK ;LIST OF TASKS IN SCHEDULER ORDER ASG LVLTAB,MAXTSK ;LEVEL TABLE ASG LVLCNT,MAXTSK ;COUNT OF CONFLICTS PER LEVEL BESTN==^D25 ;MAX NUMBER OF PERT PLACEMENT CONFLICTS TO FIX ASG BEST,BESTN ;BEST PLACEMENT ;DEVTAB IS A LIST OF DEVELOPERS IN TBLUK FORMAT. ; DEVTAB/ NUMBER OF DEVELOPERS,,NUMBER OF DEVELOPERS ; DEVTAB+N/ ADDRESS OF ASCIZ DEVELOPER NAME,,POINTER TO FIRST SCHEDULER BLOCK ASG DEVTAB,MAXDEV ;DEVELOPER TABLE SKDFRL==.SCHLN*6*MAXTSK ASG SKDFRE,SKDFRL ;SCHEDULER FREE POOL SKDVAR==ASGVAL ASG SKDFRP,1 ;POINTER TO NEXT BLOCK IN SKDFRE POOL ASG SKDFLG,1 ;SCHEDULER FLAG, 0=NEED TO SCHEDULE ASG SKDTAD,1 ;TODAY'S DATE ASG LSTSKT,1 ;LAST SCHEDULED TASK ASG SKTLST,1 ;POINTER TO SCHEDULED TASK LIST ASG TSKCNT,1 ;COUNT OF TASKS IN TSKLST ASG TSKPTR,1 ;AOBJN POINTER TO TSKLST ASG LVLPTR,1 ;AOBJN POINTER TO LVLTAB ASG SKDCNT,1 ;COUNT OF SCHEDULED TASKS ASG AVLCNT,1 ;COUNT OF AVAILABLE TASKS ASG OAVCNT,1 ;OPTIMIZED AVAILABLE TASK COUNT ASG BESTFD,1 ;BEST FINISH DATE SO FAR ASG BESTSK,1 ;BEST LEVEL 0 TASK ASG LVL0TK,1 ;LEVEL 0 TASK ADR ASG LVL0CT,1 ;SKDCNT AT LEVEL 0 ASG NCNFLC,1 ;NUMBER OF CONFLICTS SEEN ASG MAXCFL,1 ;MAX CONFLICTING LEVEL ASG PASCNT,1 ;COUNT OF THE NUMBER OF PASSES ASG PAS0CT,1 ;INITIAL VALUE OF PASCNT ASG LEVEL,1 ;CURRENT CONFLICT LEVEL NDEPTH==3 ;DEPTH = 3*LEVEL ASG DEPTH,1 ;MAX SEARCH DEPTH ASG COLMAX,1 ;MAXIMUM COLUMN REACHED IN GANTT CHART ASG AVWID,1 ;AVERAGE WIDTH OF A LINE ON THE PERT CHART SKDVRE==ASGVAL-1 ;END OF SCHEDULER VARIABLES SKDEND==ASGVAL-1 ;LAST LOC ZEROED AT SCHED STARTUP IFLE <770000-ASGVAL>, RELOC ;ENTRY VECTOR ENTVEC: JRST PANTT ;START ADR JRST REENT ;REENTER VPANTT ;VERSION NUMBER ;MAIN ROUTINE PANTT: MOVE P,[IOWD PDLEN,PDL] ;INIT THE PUSH DOWN STACK POINTER CALL UNMAP RESET ;RESET THE WORLD MOVE T1,[ZERBEG,,ZERBEG+1] SETZM ZERBEG ;ZERO THE FREE SPACE BLT T1,ZEREND-1 MOVE T1,[SKDVAR,,SKDVAR+1] SETZM SKDVAR BLT T1,SKDVRE-1 ;OPEN THE DATA BASE FILE HRROI T1,[ASCIZ/NAME OF DATA BASE FILE: /] CALL OPNFIL ;OPEN THE DATA BASE FILE JSP ERROR ;FAILED MOVEM T1,DBJFN ;SAVE THE JFN OF TE DATA BASE FILE MOVEM T2,TLJFN ;SAVE THE JFN OF THE TRANSACTION LOG MOVEI T2,DBPAG ;NOW MAP THE FILE MOVEI T3,NDBPAG CALL MAPFIL ;MAP IT ERRMES MOVE T1,DBJFN ;NOW GO LOCK THE DATA BASE CALL ENQJFN ;LEAVE IT LOCKED TILL EXIT JRST LEVEL0 ;REENTER ADR REENT: MOVE P,[IOWD PDLEN,PDL] JRST LEVEL0 ;ENTRY POINT TO UPDATE THE TRANSACTION LOG AND THE DATA BASE LOGLV0: CALL UPDDB ;GO UPDATE THE DATA BASE JRST LEVEL0 ;PARSE THE LEVEL 0 COMMAND LEVEL0: CALL INITRA ;INIT TRANSACTION AREA HRROI T1,[ASCIZ/ /] CALL COPCMD ;INITIALIZE EACH LINE WITH A CRLF HRROI T1,[ASCIZ/PANTT> /] MOVEI T2,LEV0CT ;GET ADR OF LEVEL 0 COMMAND TABLE MOVEI T3,ANSWER ;GET ADR OF ANSWER BLOCK CALL PARSE ;GO PARSE THIS COMMAND ERRMES CALL COPCMD ;COPY THIS COMMAND TO THE BUFFER MOVEI P1,ANSWER ;SET UP A POINTER TO THE PARSED COMMAND HLRZ T1,(P1) ;GET THE FIRST FUNCTION CODE CAIE T1,.CMKEY ;MUST BE A KEY WORD ERRMES HRRZ T1,(P1) ;GET DISPATCH ADR AOJA P1,(T1) ;DISPATCH ;SET COMMAND SET: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET THE ADR OF THE ROUTINE TO GO TO AOJA P1,(T1) ;DISPATCH ;SET SCHEDULE-DATE COMMAND SETDAT: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (TAD) HRRZ T1,(P1) ;GET ADR OF DATE MOVE T1,ANSWER(T1) ;GET THE DATE CALL GETDAY ;CONVERT IT TO DAY,,0 MOVEM T1,SKDITD ;SAVE THE INITIAL SCHEDULER TIME AND DATE JRST LEVEL0 ;DELETE SCHEDULE-DATE COMMAND DELDAT: SETZM SKDITD ;CLEAR THE FLAG JRST LEVEL0 ;THAT IS ALL ;SET PERT-PLACEMENT-ALGORITHM SETPPA: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (KEY) ;MUST BE A KEYWORD HRRZ T1,(P1) ;GET INDEX MOVEM T1,PERTPA ;SAVE PLACEMENT ALGORITHM JRST LEVEL0 ;ALL DONE ;SET SLOPPY/SAFE SETSAF: TDZA T1,T1 ;CLEAR FLAG SETSLB: SETO T1, ;SET FLAG MOVEM T1,SLOB ;STORE JUMPE T1,LEVEL0 ;DONE IF SAVE TMSG < %%WARNING: A system crash may destroy the database > JRST LEVEL0 ;ALL DONE ;SET HOLIDAY COMMNAD SETHOL: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (TAD) MOVE T1,HOLTAB ;GET TABLE ADR JUMPN T1,SETHO1 ;ONE THERE? CALL BLDHOL ;NO, BUILD ONE WARN (,) MOVEM T1,HOLTAB ;STORE THE ADR SETHO1: HRRZ T1,(P1) ;GET THE DATE MOVE T1,ANSWER(T1) CALL GETDAY ;GET DAY,,0 MOVE T3,T1 MOVE T1,HOLTAB ;GET TABLE ADR LOAD T2,HOLUSE,(T1) ;GET NUMBER OF ENTRIES JUMPE T2,SETHO3 ;IF NONE, GO ADD THIS ONE MOVNS T2 ;SET UP AOBJN COUNTER HRLZS T2 HRRI T2,1(T1) ;SKIP OVE HEADER WORD SETHO2: CAMN T3,(T2) ;FOUND THIS DATE? JRST SETHO4 ;YES, DO NOT MAKE ANOTHER ENTRY AOBJN T2,SETHO2 ;LOOP BACK LOOKING AT EACH ENTRY SETHO3: LOAD T2,HOLUSE,(T1) ;GET POINTER TO THE END LOAD T4,HOLSIZ,(T1) ;IS THERE ANY MORE ROOM? ADDI T2,1 ;COUNT UP USE COUNT CAML T2,T4 ;CHECK FOR ROOM WARN (,) STOR T2,HOLUSE,(T1) ;SAVE NEW COUNT ADD T2,T1 ;GET POINTER TO NEW ENTRY MOVEM T3,(T2) ;STORE THE DATE INTO THE TABLE SETHO4: JRST LOGLV0 ;GO LOG THIS COMMAND SETHO5: JRST LEVEL0 ;FAILED, DO NOT LOG COMMAND ;ROUTINE TO BUILD A HOLIDAY TABLE BLDHOL: MOVEI T1,.HOLLN ;GET SIZE OF TABLE MOVEI T2,.TYHOL ;GET TYPE CODE MOVEI T3,.VNHOL ;AND VERSION NUMBER CALL ASGFRE ;GET ROOM RET ;NONE SETZRO HOLUSE,(T1) ;INIT THE BLOCK MOVEI T2,.HOLLN STOR T2,HOLSIZ,(T1) ;SAVE LENGTH RETSKP ;RETURN WITH ADR IN T1 ;REMEMBER (EXPECTED DATES FOR COMPARISON) REMDAT: CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED MOVE T4,TSKPTR ;GET POINTER TO TSKLST REMDT1: HRRZ T3,TSKLST(T4) ;GET ADDRESS OF TASK BLOCK LOAD T1,BLKVER,(T3) ;GET VERSION CAIG T1,1 ;MUST BE BIG BLOCK JRST VERERR ;NO--BITCH LOAD T1,TKEFD,(T3) ;COPY DATES LOAD T2,TKESD,(T3) ; .. STOR T1,TKRCD,(T3) ; .. STOR T2,TKRSD,(T3) ; .. AOBJN T4,REMDT1 ;LOOP OVER ALL TASKS JRST LEVEL0 ;ALL DONE ;HERE IF DATABASE HAS AN OLD BLOCK TYPE IN IT VERERR: HRROI T1,[ASCIZ " % PANTT's internal database format does not support the % function you have requested. You need to rebuild the % database with the following procedure: % PANTT>OUTPUT CONTROL-FILE foo.ctl % PANTT>EXIT % @SUBMIT foo.ctl "] PSOUT JRST REENT ;RESET STACK AND PROMPT ;EXIT COMMAND EXIT: CALL UNMAP ;UNMAP THE DATA BASE FILE HRRZ T1,DBJFN ;NOW DEQ THE DATA BASE FILE CALL DEQJFN HRRZ T1,DBJFN ;NOW CLOSE THE DATA BASE FILE CLOSF JSP ERROR HRRZ T1,TLJFN ;AND RELEASE THE TRANSACTION LOG JFN RLJFN JFCL HALTF ;DONE JRST PANTT ;CONTINUE = START OVER AGAIN ;SCHEDULE COMMAND SKDCMD: CALL UPDEST ;GO UPDATE THE ESTIMATED DATES JRST LEVEL0 ;DONE ;OUTPUT COMMAND OUTPUT: HLRZ T1,(P1) ;GET FUNCTION CODE CAIE T1,.CMKEY ;MUST BE ANOTHER KEYWORD ERRMES HRRZ T1,(P1) ;GET DISPATCH ADDRESS AOJA P1,(T1) ;DISPATCH ;ROUTINE TO OUTPUT A CONTROL FILE DUMP: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (OFI) HRRZ T1,(P1) ;GET THE JFN MOVE T1,ANSWER(T1) HRRZS Q1,T1 ;RH ONLY MOVE T2,[070000,,OF%WR] ;OPEN IT FOR WRITE OPENF WARN (,) CALL OUTCTL ;OUTPUT THE CONTROL FILE MOVE T1,Q1 ;GET THE JFN CLOSF ;CLOSE IT WARN (,) JRST LEVEL0 ;DONE ;PLOT COMMAND PLOT: HLRZ T1,(P1) ;GET FUNCTION CODE CAIE T1,.CMKEY ;MUST BE ANOTHER KEYWORD ERRMES HRRZ T1,(P1) ;GET DISPATCH ADDRESS AOJA P1,(T1) ;DISPATCH ;LIST OVERALL DEVELOPERS LSTDEV: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (OFI) HRRZ T1,(P1) ;GET THE JFN MOVE T1,ANSWER(T1) MOVE T2,[070000,,OF%WR] ;OPEN IT FOR WRITE OPENF JSP ERROR MOVE Q1,T1 ;SAVE THE JFN MOVE T2,DEVTBP ;GET THE POINTER TO THE DEV LIST CALL TYPDEV ;GO TYPE OUT THE DEVELOPERS MOVE T1,Q1 TYPE T1,<&> HRRZ T1,Q1 ;GET THE JFN CLOSF ;CLOSE IT JFCL JRST LEVEL0 ;DONE ;THE LIST COMMAND LSTCMD: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET ADR AOJA P1,(T1) ;LIST PROJECT LISTP: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ P2,(P1) ;SET UP PROJECT ADR HLRZ T1,1(P1) ;GET NEXT TYPE CODE CAIN T1,.CMCFM ;CONFIRM? JRST LISTP1 ;YES, GO LIST THE WHOLE PROJECT CHKTYP (KEY) ;MUST BE A TASK HRRZ P3,1(P1) ;GET THE TASK BLOCK ADR CALL SCHWRN ;OUTPUT POSSIBLE WARNING MOVEI T1,.PRIOU ;GET OUTPUT JFN MOVE T2,P3 ;GET TASK BLOCK ADR CALL TYPTSK ;TYPE THE TASK JRST LEVEL0 LISTP1: CALL SCHWRN ;OUTPUT POSSIBLE WARNING MOVEI T1,.PRIOU ;OUTPUT TO THE TTY MOVE T2,P2 ;GET PROJECT BLOCK ADR CALL TYPPRJ ;TYPE OUT THE PROJECT JRST LEVEL0 ;PERT CHART GENERATOR PERT: TDZA T1,T1 ;FLAG NORMAL PERT SPERT: SETOM T1 ;FLAGE SELECTED PERT MOVEM T1,SELFLG ;SAVE THE FLAG HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (OFI) HRRZ T1,(P1) ;GET THE JFN MOVE Q1,ANSWER(T1) MOVE T1,Q1 ;OPEN THE JFN MOVE T2,[070000,,OF%WR] ;7 BIT BYTES OPENF JSP ERROR SKIPE SELFLG ;WANT TO SELECT? CALL SELECT ;YES CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/ PERT CHART - /] SETZ T3, SOUT SETO T2, ;GET TODAYS DATE ODTIM HRROI T2,[ASCIZ/ /] SOUT CALL INISPC ;INIT SPACE TABLE SETZ Q2, ;INIT ROW OFFSET LPERT1: MOVEI T1,0 ;LPT MOVE T2,Q2 ;GET THE ROW OFFSET CALL PERT0 ;GO BUILD THE PERT MOVE Q3,T1 ;SAVE THE ROW HRL Q3,T2 ;AND THE COL MOVE T3,T2 ;GET MAX COL HRRZ T2,Q3 ;GET THE ROW SUBI T2,(Q2) ;MINUS THE OFFSET MOVE T1,Q1 ;GET JFN HLRZ T4,Q2 ;GET THE COL OFFSET CALL PRISTO ;PRINT ANSWER ADDI Q2,NROW ;STEP TO THE NEXT SECTION HRRZ T1,Q3 ;GET MAX ROW SUBI T1,(Q2) ;GET NUMBER OF ROWS LEFT JUMPG T1,LPERT1 ;IF MORE ROWS, GO DO THEM HLRZ T1,Q2 ;GET COL OFFSET ADDI T1,^D132 ;STEP TO NEXT PAGE HRLZM T1,Q2 ;START AT THIS COL AND ROW 0 HLRZ T2,Q3 ;GET MAX COL CAML T1,T2 ;DONE? JRST LPERT2 ;YES MOVE T1,Q1 ;GET JFN HRROI T2,[ASCIZ/ . /] SETZ T3, SOUT MOVEI T2,14 ;FORM FEED BOUT HRROI T2,[ASCIZ/ /] SOUT JRST LPERT1 ;LOOP BACK FOR REST OF COLUMNS LPERT2: HLRZ T1,Q3 ;GET COL MAX CAILE T1,NCOL ;WAS THERE TRUNCATION? WARN (,<% CAUTION: MAXIMUM WIDTH EXCEEDED, TRUNCATION OCCURED>) HRRZ T1,Q1 ;DONE, NOW CLOSE THE JFN CLOSF JFCL JRST LEVEL0 ;DONE ;PERT CHART PLOTTER PPLOT: TDZA T1,T1 ;FLAG NORMAL PERT SPPLOT: SETOM T1 ;FLAG SELECTED PERT MOVEM T1,SELFLG ;SAVE FLAG HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (OFI) HRRZ T1,(P1) ;GET THE JFN MOVE Q1,ANSWER(T1) MOVE T1,Q1 ;OPEN THE JFN MOVE T2,[070000,,OF%WR] ;7 BIT BYTES OPENF JSP ERROR SKIPE SELFLG CALL SELECT CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED CALL INISPC ;INIT THE SPACE TABLE SETZ Q2, ;INIT THE ROW OFFSET PPLOT1: MOVEI T1,1 ;PLOTTER MOVE T2,Q2 ;GET THE ROW OFFSET CALL PERT0 ;GO BUILD THE PERT MOVE Q3,T1 ;SAVE THE MAX ROW HRL Q3,T2 ;AND THE MAX COL MOVE T3,T2 ;GET MAX COL HRRZ T2,Q3 ;GET THE ROW SUB T2,Q2 ;MINUS THE OFFSET MOVE T1,Q1 ;GET JFN CALL PRIPLT ;OUTPUT THE TEXT TO THE PLOTTER FILE ADDI Q2,NROW ;STEP THE ROW OFFSET HRRZ T1,Q3 ;GET THE MAX ROW SUB T1,Q2 ;SEE IF THERE ARE ANY ROWS LEFT TO DO JUMPG T1,PPLOT1 ;IF YES, GO DO THEM HLRZ T1,Q3 ;GET COL MAX CAILE T1,NCOL ;WAS THERE TRUNCATION? WARN (,<% CAUTION: MAXIMUM WIDTH EXCEEDED, TRUNCATION OCCURED>) HRRZ T1,Q1 ;GET THE JFN MOVE T2,SKDTAD ;GET DATE CALL DBOX ;DRAW THE BOXES HRRZ T1,Q1 ;GET THE JFN CALL CBOX ;GO CONNECT THE BOXES HRRZ T1,Q1 ;COPY JFN SKIPE SELFLG ;PLOTTING ONLY SOME STUFF CALL TICKS ;YES--PUT IN TICK MARKS HRRZ T1,Q1 ;DONE, NOW CLOSE THE JFN CLOSF JFCL JRST LEVEL0 ;DONE ;ROUTINE TO PERT THE TASKS ;ACCEPTS IN T1/ 0 = LPT, 1 = PLOTTER ; T2/ COL OFFSET,,ROW OFFSET ;RETURNS +1: T1/ MAX ROW ; T2/ MAX COL PERT0: SAVEQ MOVE Q3,T1 ;SAVE THE OUTPUT TYPE MOVE Q1,T2 ;SAVE FLAG HRRZ T1,T2 ;GET THE ROW OFFSET CALL INISTO ;INITIALIZE THE STORAGE AREA JUMPN Q1,PERT5B ;SKIP PLACEMENT IF NOT FIRST CALL MOVE Q1,TSKPTR ;INIT THE TABLES PERT1: HRROS TSKLST(Q1) ;-1 IN LH MEANS NOT SCHEDULED SETZM TSKPOS(Q1) SETZM TSKWID(Q1) SETZM TSKSKD(Q1) SETZM TSKINV(Q1) ;MARK TASK AS VISIBLE MOVE T1,TSKLST(Q1) CALL PRTTSK ;WANT THIS TASK IN PERT? SETOM TSKINV(Q1) ;NO AOBJN Q1,PERT1 MOVEI Q1,0 ;START AT LEVEL 0 PERT2: SUBI Q1,1 ;COUNT DOWN THE LEVEL NUMBER MOVEI T1,1 ;DO A REVERSE SCAN OF THE AVAILABLE LIST CALL BLDPAV ;SET UP AVLTSK LIST JRST PERT4 ;NO MORE TO DO MOVN T1,AVLCNT ;SET UP LEVEL NUMBER FOR THESE TASKS HRLZS T1 PERT3: HRRZ T2,AVLTSK(T1) ;GET TASK INDEX HRLZM Q1,TSKSKD(T2) ;SAVE THE LEVEL NUMBER HRRZS TSKLST(T2) ;MARK THIS TASK AS SCHEDULED AOBJN T1,PERT3 JRST PERT2 ;GO BACK TIL ALL TASKS ARE PLACED PERT4: MOVNS Q1 ;NOW SHIFT THE LEVEL NUMBERS SUBI Q1,1 ;SO THEY START AT 0 MOVE T1,TSKPTR PERT5: SKIPE TSKINV(T1) JRST PERT5A HLRE T2,TSKSKD(T1) ;GET THE LEVEL NUMBER ADD T2,Q1 ;TRANSPOSE IT HRLM T2,TSKSKD(T1) ;STORE IT BACK AGAIN PERT5A: AOBJN T1,PERT5 MOVE T1,Q3 ;GET THE OUTPUT DEVICE CALL SETWID ;SETUP TSKWID MOVE T1,PERTPA ;GET ALGROITHM XCT [CALL PLACE ;STANDARD PLACER CALL HDPLC](T1) ;HIGH DENSITY PLACER JUMPE Q3,PERT5B ;OK. IF LPT CALL PLTOFL ;CHECK FOR OVERFLOW PERT5B: MOVE T1,Q3 ;GET THE TYPE OF OUTPUT DEVICE CALL STOPRT ;GO STORE THE PERT BOXES RET ;DONE ;CHECK TO SEE IF PERT CHART WILL FIT IN PDP-11 ; CALL PLTOFL ; RETURN HERE (WARNING TYPED IF NEEDED) ; PLTOFL: MOVE T1,TSKPTR ;GET POINTER TO LIST PLTOF1: HLRZ T2,TSKSKD(T1) ;GET LEVEL # SKIPN TSKINV(T1) ;IGNORE IF NOT IN PERT CAIG T2,^D36 ;TOO BIG? AOBJN T1,PLTOF1 ;NO--KEEP LOOKING JUMPG T1,PLTOF2 ;ANYTHING FOUND? TMSG < ? Plot is too tall for PDP-11 plotting software! > PLTOF2: MOVE T1,TSKPTR ;GET POINTER TO LIST PLTOF3: MOVE T2,TSKPOS(T1) ;GET POSITION ADD T2,TSKWID(T1) ;GET MAX SKIPN TSKINV(T1) ;IGNORE IF NOT IN PERT CAIG T2,^D800 ;OVER 13 FEET WIDE? AOBJN T1,PLTOF3 ;NO KEEP LOOKING JUMPG T1,R ;RETURN IF NOTHING FOUND TMSG < ? Plot is too wide for PDP-11 plotting software. > RET ;ROUTINE TO STORE THE PERT BOXES ;ACCEPTS IN T1/ 0 = LPT, 1 = PLOTTER ;RETURNS +1: T1/ MAX ROW ; T2/ MAX COL STOPRT: SAVEPQ MOVE P2,T1 ;SAVE THE OUTPUT DEVICE SETZB Q2,Q3 ;INIT ROW AND COL MAXIMUMS MOVE Q1,TSKPTR ;SET UP TO STORE ALL TASK BOXES STOPR7: SKIPE TSKINV(Q1) JRST STOPR8 HRRZ T1,Q1 ;GET TASK INDEX MOVE T2,TSKPOS(T1) ;GET COL POSITION HLRZ T3,TSKSKD(T1) ;GET LEVEL # IMULI T3, ;GET ROW NUMBER (BOX LENGTH + BLANKS) MOVE T4,SKDTAD ;GET THE DATE XCT [ CALL STOBOX ;STORE THE BOX CALL PSTOBX](P2) CAMLE T1,Q3 ;NEW MAX COL? MOVE Q3,T1 ;YES CAMLE T2,Q2 ;NEW MAX ROW? MOVE Q2,T2 ;YES HLRZ T1,TSKSKD(Q1) ;GET THE LEVEL NUMBER HLRZ T2,TSKSKD(Q1) IMULI T2, ;GET THE ROW NUMBER ADDI T2,1 ;GET TO THE FIRST FULL ROW CALL SETSPC ;GO MARK THE SPACE TABLE STOPR8: AOBJN Q1,STOPR7 ;LOOP BACK FOR ALL BOXES DMOVE T1,Q2 ;GET MAX ROW AND COL RET ;ROUTINE TO FIX UP TSKPOS TABLE TO ELIMINATE WHITE SPACE FIXPOS: SETZ T1, ;INIT COUNTER FIXPS1: HRLOI T2,377777 ;START AT MAX POSITION MOVE T4,TSKPTR ;SET UP AOBJN POINTER FIXPS2: SKIPE TSKINV(T4) JRST FIXPS3 MOVE T3,TSKPOS(T4) ;GET POSITION ADD T3,TSKWID(T4) ;GET OTHER END OF THE BOX CAML T1,T3 ;PAST THIS BOX? JRST FIXPS3 ;YES, SKIP IT CAML T1,TSKPOS(T4) ;PAST THE START OF THE BOX? JRST [ MOVE T1,T3 ;YES, SOMETHING IS WRONG JRST FIXPS1] CAMG T2,TSKPOS(T4) ;NEW LOW? JRST FIXPS3 ;NO MOVE T2,TSKPOS(T4) ;YES, REMEMBER IT FIXPS3: AOBJN T4,FIXPS2 ;LOOP BACK TILL LOWEST POS FOUND CAML T2,[377777,,777777] RET ;NONE FOUND, THEN DONE MOVE T3,T1 ;GET THE AMOUNT OF SPACE TO DELETE SUB T3,T2 MOVE T4,TSKPTR FIXPS4: SKIPE TSKINV(T4) JRST FXPS4A CAMGE T1,TSKPOS(T4) ;THIS POSITION NEED UPDATING ADDM T3,TSKPOS(T4) ;YES, TRANSLATE IT FXPS4A: AOBJN T4,FIXPS4 ;LOOP BACK TIL TRANSLATING DONE MOVE T4,TSKPTR SETZ T2, ;NOW LOOK FOR NEXT WHITE SPACE FIXPS5: SKIPE TSKINV(T4) JRST FIXPS6 CAMGE T1,TSKPOS(T4) ;FOUND A BOX IN THE RANGE? JRST FIXPS6 ;NO MOVE T3,TSKPOS(T4) ;YES, GET THE END OF THE BOX ADD T3,TSKWID(T4) CAMGE T2,T3 ;NEW HIGH? MOVE T2,T3 ;YES, REMEMBER IT FIXPS6: AOBJN T4,FIXPS5 ;LOOP BACK OVER ALL TASKS MOVE T1,T2 ;USE THIS AS START OF WHITE SPACE JRST FIXPS1 ;LOOP BACK TIL DONE ;ROUTINE TO SET THE BOX WIDTHS FOR ALL BOXES ;ACCEPTS IN T1/ 0 = LPT, 1 = PLOTTER SETWID: SAVEQ MOVE Q3,T1 ;SAVE THE OUTPUT DEVICE TYPE MOVE Q1,TSKPTR ;LOOP OVER ALL TASKS SETWD1: SKIPE TSKINV(Q1) JRST SETWD2 HRRZ T1,Q1 ;GET THE TASK INDEX XCT [ CALL BOXWID ;GET THE WIDTH OF THE BOX CALL PBXWID](Q3) MOVEM T1,TSKWID(Q1) ;SAVE THE WIDTH SETWD2: AOBJN Q1,SETWD1 RET ;GANTT CHART GENERATOR GANTT: TDZA P4,P4 ;LPT GPLOT: MOVEI P4,1 ;PLOTTER HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (KEY) ;MUST BE A KEY WORD HRRZ P2,(P1) ;GET INDEX - 0=DEVELOPERS, 1=TASKS, 2=MILESTONES ; 4=ONLY-DEVELOPER AOS P1 ;STEP TO NEXT ARG CAIE P2,4 ;JUST WANT 1 DEVELOPER? JRST GNT1 ;NO--SKIP THIS PART HLRZ T1,(P1) ;GET THE NEXT TYPE CODE CHKTYP (USR) ;USER NAME CALL SCHCHK ;DEVLUK REQUIRES THAT A SCHEDULE ; PASS SETUP DEVTAB HRRZ T1,(P1) ;GET POINTER TO STRING HRROI T1,ANSWER+1(T1) ;POINTER TO NAME STRING CALL DEVLUK ;FIND HIME IN TABLE WARN (,) HRROI Q2,-DEVTAB-1(T1) ;FAKE AOBJN POINTER CALL FINDSD ;FIND STARTING DATE WARN (,) MOVEM T1,GANTSD ;SAVE STARTING DATE AOS P1 ;BUMP POINTER GNT1: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (OFI) ;OUTPUT FILE SPEC? HRRZ T1,(P1) ;GET THE JFN MOVE Q1,ANSWER(T1) ;FROM ANSWER BLOCK MOVE T1,Q1 ;GET JFN MOVE T2,[070000,,OF%WR] ;OPEN IT FOR WRITE OPENF JSP ERROR ;FIALED TO OPEN IT CAIN P2,4 ;ONLY 1 DEVELOPER? JRST GANTT0 ;YES--ALREADY HAVE GOOD STARTING DATE HRROI T1,[ASCIZ/STARTING DATE OF GANTT CHART: /] MOVEI T2,DDATA ;GET ADR OF COMMAND TABLE MOVEI T3,ANSWER CALL PARSE ;GET START DATE ERRMES HLRZ T1,ANSWER ;GET TYPE CODE CHKTYP (TAD) HRRZ T1,ANSWER ;GET DATE MOVE T1,ANSWER(T1) MOVEM T1,GANTSD ;SAVE START DATE CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED HLRZ Q2,DEVTAB ;GET LENGTH OF DEVELOPER TABLE JUMPE Q2,GANTT4 ;IF NONE, THEN DONE MOVNS Q2 ;SET UP AOBJN POINTER HRLZS Q2 SKIPN SKTLST ;ANY TASKS ON LIST? JUMPN P2,GANTT4 ;IF NONE, AND IF DOING TASKS, THEN DONE GANTT0: SETZB P3,GNTCMX ;INIT THE COL MAXIMUM GANTT1: MOVN Q3,TSKCNT ;SET UP POINTER TO TASK LIST HRLZS T1,Q3 JUMPE Q3,GANTT4 ;IF NO TASKS, THEN DONE HRROS TSKLST(T1) ;INIT TABLE AOBJN T1,.-1 HRRZ T1,P3 ;GET THE ROW OFFSET CALL INISTO ;INITIALIZE THE ANSWER ARRAY SETZM GNTRMX ;INIT THE ROW NUMBER GANTT2: MOVEI P1,0 ;START AT COLUMN 0 SETO Q3, ;FIND THE EARLIEST STARTER MOVE T1,TSKPTR HRLOI T2,377777 ;START WITH HIGHEST POSSIBLE DATE GANTT6: SKIPL TSKLST(T1) ;HAS THIS ENTRY BEEN USED YET? JRST GANTT7 ;YES, SKIP IT CAMG T2,TSKSDL(T1) ;IS THIS A NEW LOW START DATE JRST GANTT7 ;NO MOVE T2,TSKSDL(T1) ;YES, REMEMBER IT HRRZ Q3,T1 ;AND THE INDEX GANTT7: AOBJN T1,GANTT6 ;LOOP BACK THRU ALL TASKS JUMPL Q3,GANTT5 ;FOUND ANY? HRRZS TSKLST(Q3) ;YES, GO USE THIS TASK GANTT3: HRRZ T1,TSKLST(Q3) ;GET THE NEXT TASK LOAD T2,TKFLG,(T1) ;GET THE FLAGS OF THIS TASK TXNN T2,TK%MIL ;MILESTONE? CAIE P2,2 ;NO, IS THIS A MILE STONE LIST? SKIPA JRST GANTT2 ;SKIP TASKS THAT AREN'T MILESTONES HRRZ T2,DEVTAB+1(Q2) ;GET THIS DEVELOPER TRNE P2,3 ;DOING TASKS? MOVE T2,SKTLST ;YES, GET POINTER TO TASK LIST HRLZ T3,P1 ;GET COL HRR T3,GNTRMX ;ALWAYS START AT LAST USED ROW MOVE T4,GANTSD ;GET GANTT START DATE CALL STOGTK ;STORE THE TASK JRST GANTT2 ;NONE FOUND JUMPL T3,GANTT2 ;IF NOTHING STORED, DONT STORE ROW MOVEI T1,GW ;GET WIDTH OF ONE GANTT ROW ADDM T1,GNTRMX ;STEP TO NEXT FREE ROW CAMLE T3,GNTCMX ;NEW MAX COL? MOVEM T3,GNTCMX ;YES JRST GANTT2 ;LOOP BACK FOR ALL TASKS GANTT5: JUMPN P3,GANTT8 ;IF NOT FIRST TIME, DONT TYPE HEADER MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/ .TEXTSIZE;0.12,0.14/] SETZ T3, SKIPE P4 ;LPT? SOUT ;NO, GIVE PLOTTER COMMAND HRROI T2,[ASCIZ/ GANTT CHART FOR DEVELOPER /] TRNE P2,3 ;DOING ALL TASKS? HRROI T2,[ASCIZ/ GANTT CHART FOR ALL TASKS/] CAIN P2,2 ;MILESTONES? HRROI T2,[ASCIZ/ GANTT CHART OF MILESTONES/] SETZ T3, SOUT HLRO T2,DEVTAB+1(Q2) ;GET DEVELOPER TRNN P2,3 ;UNLESS DOING ALL TASKS SOUT ;YES, OUTPUT IT HRROI T2,[ASCIZ/ ON /] SOUT SETO T2, ODTIM ;OUTPUT THE DATE AND TIME HRROI T2,[ASCIZ/ /] SETZ T3, SOUT GANTT8: MOVE T1,Q1 ;GET THE JFN HLRZ T2,P3 ;GET THE START COL HRRZ T3,GNTRMX ;GET MAX ROW SUBI T3,(P3) ;GET MAX ROW - OFFSET MOVE T4,GNTCMX ;GET MAX COL SUB T4,T2 ;SEE IF IT NEEDS TRUNCATING SKIPN P4 ;GOING TO THE PLOTTER? CAIG T4,^D132 ;NO, WIDER THAN A PAGE? SKIPA ;NO MOVEI T4,^D132 ;LIMIT TO ONE PAGE ADD T4,T2 ;GET COL MAX HRL T3,T4 MOVE T4,GANTSD ;GET START DATE XCT [ CALL PRIGNT ;PRINT THE GANTT CHART ON LPT OR PLOTTER CALL PLOGNT](P4) ADDI P3,NROW ;STEP TO NEXT SET OF ROWS HRRZ T1,GNTRMX ;SEE IF DONE SUBI T1,(P3) ;DONE ENOUGH? JUMPG T1,GANTT1 ;IF MORE TO DO, GO DO THEM JUMPN P4,GANTT9 ;IF PLOTTER, THEN DONE HLRZ T1,P3 ;GET COL OFFSET ADDI T1,^D132 ;STEP TO NEXT PAGE HRLZM T1,P3 ;RESET ROW TO 0 CAML T1,GNTCMX ;DONE? JRST GANTT9 ;YES, GO DO OTHER DEVELOPERS MOVE T1,Q1 ;JFN HRROI T2,[ASCIZ/ . /] SETZ T3, SOUT MOVEI T2,14 ;FORM FEED BOUT HRROI T2,[ASCIZ/ /] SOUT JRST GANTT1 ;LOOP BACK TILL DONE ALL COL'S GANTT9: TRNE P2,3 ;DOING DEVELOPERS? JRST GANTT4 ;NO--ALL DONE HRRZ T1,Q1 ;GET THE JFN MOVEI T2,14 ;FORM FEED SKIPN P4 ;LPT? BOUT ;YES, PUT A FORM FEED BETWEEN EACH DEV AOBJN Q2,GANTT0 ;LOOP BACK FOR ALL DEVELOPERS GANTT4: HRRZ T1,Q1 ;DONE, CLOSE THE JFN CLOSF JFCL JRST LEVEL0 ;ALL DONE ;SUBROUTINE TO FIGURE OUT A GOOD PLACE TO START A GANTT CHART ;CALL WITH: ; T1/ ADDRESS OF DEVTAB ENTRY (NOT INDEX!) ;RETURNS +1: NO TASKS LEFT TO DO ; +2: T1/ STARTING DATE ; FINDSD: SAVEQ STKVAR <> HRRZ Q1,(T1) ;START OF CHAIN HRLOI Q2,377777 ;LARGEST DATE MOVEI Q3,0 ;FLAG JUMPE Q1,R ;SHOULD NEVER BE NULL LIST ;AC USE IN THIS LOOP ; Q1/ CURRENT NODE IN TASK CHAIN ; Q2/ EARLIEST STARTING DATE ; Q3/ TASK WHICH STARTS THEN FNDSD1: LOAD T1,SCHTK,(Q1) ;POINTER TO TASK BLOCK LOAD T2,TKAFD,(T1) ;ACTUAL FINISH DATE JUMPN T2,FNDSD2 ;IGNORE COMPLETED TASKS MOVEI T1,FSDTMP ;POINTER TO DUMMY STRING HRLI T1,(POINT 7,0) ;MAKE BYTE POINTER LOAD T2,SCHTK,(Q1) ;GET TASK BLOCK ADDRESS CALL GETPTS ;SEE HOW LONG HEADER IS HRLZ T1,T1 ;PUT IN LEFT HALF LOAD T2,SCHSD,(Q1) ;GET THE START DATE FOR THE TASK SUB T2,T1 ;BACKUP DATE TO START OF HEADER CAML T2,Q2 ;NEW LOW? JRST FNDSD2 ;NO--SKIP IT MOVE Q2,T2 ;YES--SAVE DATE LOAD Q3,SCHTK,(Q1) ;SAVE TASK BLOCK ADDRESS ALSO FNDSD2: LOAD Q1,SCHLN,(Q1) ;STEP TO NEXT TASK JUMPN Q1,FNDSD1 ;KEEP LOOPING JUMPE Q3,R ;ERROR RETURN IF NOTHING FOUND MOVE T1,Q2 ;RETURN START DATE RETSKP ;ROUTINE TO STORE THE DATE STRING ;ACCEPTS IN T1/ COL ; T2/ ROW ; T3/ STRING POINTER STODST: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS TLC T3,-1 ;GET STRING POINTER TLCN T3,-1 HRLI T3,(POINT 7,0) MOVE Q3,T3 ;SAVE STRING POINTER STODS1: ILDB T1,Q3 ;GET THE NEXT CHAR JUMPE T1,R ;IF NULL, THEN DONE MOVE T2,Q1 ;GET THE COL MOVE T3,Q2 ;GET THE ROW CALL STOCHA ;STORE THE CHAR JFCL AOJA Q2,STODS1 ;STEP TO THE NEXT ROW ;ROUTINE TO STORE A TASK ON THE GANTT CHART ;ACCEPTS IN T1/ TASK ADR ; T2/ DEVELOPER LIST ; T3/ FIRST AVAIL COL ,, START ROW ; T4/ GANTT START ADR ;RETURNS +1: NONE FOUND ; +2: T1/ 0 = EXCEEDED STORAGE SPACE ; -1 = OK ; T2/ MAX ROW USED ; T3/ MAX COL USED STOGTK: SAVEP STKVAR ,> DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 HLRZS P4,T4 ;ONLY NEED THE DAY PART OF THE DATE HRROI T1,STOGTS ;GET THE NAME STRING MOVE T2,P1 ;GET THE TASK ADR CALL GETPTS ;GET PROJECT/NAME STRING MOVEM T1,STOGTN ;SAVE THE LENGTH OF THE NAME STRING MOVEI T1,STOGTB ;NOW SET UP THE STRING POINTERS CALL INISTB MOVEI T1,STOGTB ;GET POINTER TO STRING BLOCK MOVE T2,P1 ;GET TASK ADR MOVE T3,P2 ;GET THE DEVELOPER LIST CALL GETGST ;GET THE TASK STRINGS SET UP RET ;NONE FOUND MOVEM T1,STOGTL ;SAVE THE STRING LENGTH SUB T2,P4 ;GET THE ACTUAL STARTING COL # HLRZ T3,P3 ;GET STARTING COL ADD T2,T3 ;GOT COL NUMBER SUB T2,STOGTN ;BACK UP OVER THE NAME STRING MOVEM T2,STOGTC ;SAVE THE COLUMN HRRZ T1,P3 ;GET THE ROW NUMBER MOVE T3,STOGTN ;GET TOTAL LENGTH OF STRING ADD T3,STOGTL ;LENGTH = NAME + TASK STRING MOVEI T4,GW ;GET THE ROW INCREMENT CALL FNDROW ;FIND A FREE ROW JRST [ SETZ T1, ;EXCEEDED SPACE SETZB T2,T3 ;NO ROW OR COL USED RETSKP] HRRM T1,P3 ;SAVE THE ROW HRL T1,STOGTC ;GET COL NUMBER FOR NAME HRR T1,P3 ;GET THE ROW HRROI T2,STOGTS ;GET POINTER TO NAME STRING MOVE T3,P1 ;GET THE TASK ADR MOVEI T4,GW ;GET ROW WIDTH CALL STOGNM ;STORE THE STRING MOVEI T1,STOGTB ;GET POINTER TO STRINGS CALL INISTB ;INIT POINTERS MOVSI P5,-GW ;NOW PUT STRINGS INTO BUFFER HRRI P5,STOGTB STOGT1: MOVE T1,STOGTC ;GET STARTING COL NUMBER ADD T1,STOGTN ;STEP OVER THE NAME STRING HRRZ T2,P3 ;GET ROW ADDI P3,1 ;STEP ROW MOVE T3,(P5) ;GET STRING POINTER CALL STOSTR ;STORE THE STRING AOBJN P5,STOGT1 ;LOOP BACK FOR ALL STRINGS SETO T1, ;FINISHED OK HRRZ T2,P3 ;RETURN ROW NUMBER MOVE T3,STOGTC ;GET COL MAXIMUM ADD T3,STOGTN ;ADD IN NAME ADD T3,STOGTL ;AND ADD IN THE TASK STRING LENGTH RETSKP ;ROUTINE TO FIND A FREE ROW ;ACCEPTS IN T1/ START ROW ; T2/ COL ; T3/ LENGTH OF STRING ; T4/ ROW INCREMENT ;RETURNS +1: EXCEEDS THE TABLE SPACE ; +2: T1/ ROW FOUND FNDROW: SAVEP DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 FNDRO1: DMOVE T1,P1 ;GET ROW AND COL MOVE T3,P3 ;GET STRING LENGTH CALL CHKROW ;SEE IF THIS ROW IS FREE RET ;EXCEEDED TABLE SPACE JUMPN T1,FNDRO2 ;IF -1, THEN DONE ADD P1,P4 ;STEP THE ROW JRST FNDRO1 ;LOOP BACK TILL ROW FOUND FNDRO2: MOVE T1,P1 ;RETURN THE ROW SELECTED RETSKP ;ROUTINE TO CHECK IF A SLOT IS FREE ;ACCEPTS IN T1/ ROW ; T2/ COL ; T3/ LENGTH OF THE STRING ;RETURNS +1: EXCEEDED TABLE SPACE ; +2: T1/ 0 = IN USE, -1 = FREE CHKROW: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS MOVE Q3,T3 CHKRO1: MOVEI T1," " ;GET DUMMY CHAR MOVE T2,Q2 ;GET THE COL MOVE T3,Q1 ;GET THE ROW JUMPL T2,CHKRO2 ;IF NEG COL, THEN OK CALL CHKCHR ;SEE IF THIS POSITION IS FREE RET ;EXCEEDED TABLE SIZE JUMPE T1,RSKP ;NOT FREE CHKRO2: AOS Q2 ;STEP COL SOJG Q3,CHKRO1 ;LOOP BACK FOR WHOLE STRING SETO T1, ;ALL FREE RETSKP ;ROUTINE TO GET THE PROJECT/TASK STRING ;ACCEPTS IN T1/ STRING POINTER ; T2/ TASK ADR ;RETURNS +1: T1/ LENGTH GETPTS: SAVEQ STKVAR DMOVE Q1,T1 ;SAVE THE ARGS LOAD T1,TKPRJ,(Q2) ;GET THE PROJECT ADR LOAD T1,PJNAM,(T1) ;GET THE ADR OF THE NAME HRLI T1,(POINT 7,0) ;BUILD A BYTE POINTER CALL CNTSTC ;COUNT CHARACTERS IN THE STRING MOVEM T1,GETPTC ;SAVE THE COUNT LOAD T1,TKNAM,(Q2) ;GET ADR OF TASK NAME HRLI T1,(POINT 7,0) CALL CNTSTC ;GET COUNT OF CHARS IN STRING CAMLE T1,GETPTC ;NEW HIGH? MOVEM T1,GETPTC ;YES, SAVE IT MOVE T1,Q2 ;GET TASK ADR MOVE T2,Q1 ;GET STRING POINTER CALL BLDNST ;GO BUILD THE NAME STRING CAMLE T1,GETPTC ;NEW HIGH LENGTH? MOVEM T1,GETPTC ;YES AOS T1,GETPTC ;GET THE LONGEST LENGTH PLUS 1 SPACE RET ;DONE ;ROUTINE TO COUNT THE CHARACTERS IN A STRING ;ACCEPTS IN T1/ STRING POINTER ;RETURNS +1: T1/ COUNT CNTSTC: TLC T1,-1 ;BYTE POINTER? TLCN T1,-1 HRLI T1,(POINT 7,0) ;NO, MAKE A BYTE POINTER SETZ T4, ;INIT COUNT CNTST1: ILDB T2,T1 ;GET NEXT CHAR SKIPE T2 ;NULL? AOJA T4,CNTST1 ;NO, LOOP BACK TIL DONE MOVE T1,T4 ;GET THE COUNT RET ;DONE ;ROUTINE TO BUILD A TASK STRING ;ACCEPTS IN T1/ STRING BLOCK POINTER ; T2/ TASK ADR ; T3/ DEVELOPER LIST ;RETURNS +1: NONE FOUND ; +2: T1/ LENGTH OF STRING ; T2/ START ADR GETGST: SAVEQ STKVAR SETZM GETGSZ ;INIT TASK ADR DMOVE Q1,T1 ;SAVE THE ARGS MOVE Q3,T3 SETZM GETGSC ;INIT COUNT GETGS1: LOAD T1,SCHTK,(Q3) ;FIND THE FIRST MATCHING TASK CAMN T1,Q2 ;MATCH? JRST GETGS3 ;YES GETGS2: LOAD Q3,SCHLN,(Q3) ;STEP TO NEXT DEV IN LIST JUMPN Q3,GETGS1 ;LOOP BACK TILL FIRST TASK IS FOUND SKIPN Q3,GETGSZ ;WAS A TASK FOUND? RET ;NO JRST GETGS4 ;YES GETGS3: LOAD T1,SCHSD,(Q3) ;GET START DATE HLRZM T1,GETGSD ;SAVE THE START DATE MOVEM Q3,GETGSZ ;SAVE ADR OF TASK LOAD T1,SCHRT,(Q3) ;GET RATE JUMPE T1,GETGS2 ;IF 0, GO LOOK SOME MORE GETGS4: LOAD T2,SCHSD,(Q3) ;GET THE START DATE HLRZS T2 LOAD T1,SCHFD,(Q3) ;GET FINISH DATE HLRZS T1 MOVEM T1,GETGSF ;SAVE THE FINISH DATE SUB T1,T2 ;CALCULATE THE TASK LENGTH MOVEM T1,GETGSL ;SAVE THE LENGTH LOAD T1,SCHRT,(Q3) ;GET THE RATE SKIPG GETGSL ;LONGER THAN 0? SETZ T1, ;NO, SET THE RATE TO 0 MOVEM T1,GETGSR ;SAVE THE RATE MOVE T2,GETGSR ;GET THE RATE SKIPG T3,GETGSL ;IS THIS A ZERO LENGTH TASK? MOVEI T3,1 ;YES, IT ALWAYS TAKES ONE SPACE ADDM T3,GETGSC ;SAVE THE LENGTH MOVE T1,Q1 ;GET POINTER TO STRING BLOCK MOVE T4,Q3 ;GET SCHED BLOCK ADR CALL STOGST ;STORE THE STRINGS GETGS5: LOAD Q3,SCHLN,(Q3) ;STEP TO THE NEXT TASK JUMPE Q3,GETGS6 ;DONE LOAD T1,SCHTK,(Q3) ;GET TASK ADR CAME T1,Q2 ;FOUND A MATCH? JRST GETGS5 ;NO, LOOP BACK TILL ONE FOUND LOAD T1,SCHRT,(Q3) ;GET THE RATE JUMPE T1,GETGS5 ;SKIP 0'S LOAD T1,SCHSD,(Q3) ;GET START DATE HLRZS T2,T1 SUB T2,GETGSF ;GET THE DIF BETWEEN START AND LAST FIN SKIPLE T2 ;IF NO DIFFERENCE, SKIP THIS ADDM T2,GETGSC ;UPDATE THE FINAL COUNT MOVE T1,Q1 ;GET STRING BLOCK ADR CALL STODOT ;YES JRST GETGS4 ;GO ADD THIS TASK TO STRING GETGS6: MOVE T1,Q1 ;GET STRING POINTER CALL STONUL ;STORE NULL AT END OF STRING MOVE T1,GETGSC ;RETURN THE LENGTH OF THE STRING MOVE T2,GETGSD ;RETURN THE START COL RETSKP ;ROUTINE TO STORE A GANNT STRING ;ACCEPTS IN T1/ STRING BLOCK ADR ; T2/ RATE ; T3/ LENGTH OF TASK IN DAYS ; T4/ SCHED BLOCK ADR STOGST: SAVEPQ DMOVE Q1,T1 ;SAVE THE ARGS MOVE Q3,T3 MOVE P4,T4 ;SAVE THE SCHED BLOCK ADR LOAD T4,SCHSD,(P4) ;GET THE START DATE HLRZ P1,T4 ;GET START DAY INTO P1 FMPR T2,[100.0] ;GET PERCENTAGE CALL STOFPT ;STORE THE RATE AOS P1 ;COUNT UP DAY STOGS1: HRLZ T1,P1 ;GET DATE CALL CHKHOL ;SEE IF IT IS A HOLIDAY SKIPA ;NO JRST STOGS2 ;YES MOVEI T2,">" LOAD T3,SCHTK,(P4) ;GET TASK ADR LOAD T3,TKAFD,(T3) ;GET FINISH DATE SKIPE T3 ;TASK DONE? CAML T3,SKDTAD ;AND BEFORE TODAY'S DATE SKIPA ;NO MOVEI T2,"*" ;YES, MARK IT WITH AN ASTERISK SKIPG Q2 ;ANY RATE? MOVEI T2,"." ;RATE = 0 MOVEI T3,2(P1) ;SEE IF THIS IS A WEEKEND IDIVI T3,7 CAIL T4,5 ;MON - FRI? STOGS2: MOVEI T2,"." ;NO, NO WORK ON WEEKEND OR HOLIDAY SOJLE Q3,R ;ANY MORE TO DO? MOVE T1,Q1 ;GET THE STRING BLOCK ADR CALL STOGCH ;YES, GO STORE THE CHAR AOJA P1,STOGS1 ;LOOP BACK FOR REST OF DAYS ;ROUTINE TO STORE A FLOATING POINT NUMBER ;ACCEPTS IN T1/ STRING BLOCK ADR ; T2/ FLOATING POINT NUMBER STOFPT: SAVEQ STKVAR <> DMOVE Q1,T1 ;SAVE THE ARGS HRROI T1,STOFPS ;GET THE NUMBER TRANSLATED TO A STRING MOVE T3,[FL%ONE+B23] FLOUT JFCL MOVEI T1,STOFPS HRLI T1,(POINT 7,0) ;GET POINTER TO THE NUMBER MOVSI T3,-GW ;GET POINTER TO STRINGS HRRI T3,(Q1) STOFP1: ILDB T2,T1 ;COPY THE NUMBER TO THE STRING IDPB T2,(T3) AOBJN T3,STOFP1 ;LOOP BACK FOR ALL DIGITS RET ;ROUTINE TO STORE THE NAME OF THE TASK IN THE GANTT CHART ;ACCEPTS IN T1/ COL ,, ROW ; T2/ STRING POINTER TO DEVELOPER STRING ; T3/ TASK ADR ; T4/ INCREMENT STOGNM: SAVEPQ DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 LOAD T3,TKPRJ,(P3) ;GET PROJECT NAME LOAD T3,PJNAM,(T3) HRLI T3,(POINT 7,0) ;GET POINTER TO PROJECT NAME STRING HLRE T1,P1 ;GET COL HRRE T2,P1 ;GET ROW ADDI T2,-3(P4) ;PLUS THE RIGHT INCREMENT CALL STOSTR ;STORE THIS STRING LOAD T3,TKNAM,(P3) ;NOW DO THE TASK NAME HRLI T3,(POINT 7,0) HLRE T1,P1 ;COL HRRE T2,P1 ;ROW ADDI T2,-2(P4) ;PLUS INCREMENT CALL STOSTR ;STORE THE TASK NAME HLRE T1,P1 ;COL HRRE T2,P1 ;ROW ADDI T2,-1(P4) ;PLUS INCREMENT MOVE T3,P2 ;GET STRING POINTER TO DEVELOPERS CALL STOSTR ;STORE THE STRING RET ;DONE ;ROUTINE TO STORE A GANTT CHAR ;ACCEPTS IN T1/ STRING BLOCK ADR ; T2/ CHAR STOGCH: MOVEI T3," " ;GET A SPACE MOVSI T4,- ;LOOP FOR ALL BUT THE LAST CHAR HRRI T4,(T1) ;GET POINTER TO FIRST STRING ADR STOGC1: IDPB T3,(T4) ;STORE THE SPACE AOBJN T4,STOGC1 IDPB T2,(T4) ;STORE THE CHAR RET ;ROUTINE TO STORE A NULL IN EACH STRING OF GANNT ENTRY ;ACCEPTS IN T1/ STRING BLOCK ADR STONUL: MOVEI T3,0 ;GET THE NULL MOVSI T4,-GW HRRI T4,(T1) ;SET UP AOBJN COUNTER STONU1: MOVE T2,(T4) ;GET BYTE POINTER IDPB T3,T2 ;STORE NULL WITHOUT INCREMENTING BP AOBJN T4,STONU1 ;LOOP BACK FOR REST RET ;ROUTINE TO STORE DOTS ;ACCEPTS IN T1/ STRING BLOCK ADR ; T2/ COUNT OF DOTS TO STORE STODOT: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS STODO1: MOVE T1,Q1 ;GET STRING BLOCK ADR MOVEI T2,"." ;GET THE DOT CHAR SOJL Q2,R ;ANY MORE TO DO? CALL STOGCH ;YES, STORE THE NEXT DOT JRST STODO1 ;LOOP BACK FOR REST ;ROUTINE TO INIT A STRING BLOCK ;ACCEPTS IN T1/ STRING BLOCK ADR INISTB: MOVSI T4,-GW ;SET UP COUNTER INIST1: MOVE T2,INITAB(T4) ;GET STRING POINTER MOVEM T2,(T1) ;STORE IT IN THE BLOCK AOS T1 AOBJN T4,INIST1 ;LOOP BACK FOR THE REST RET DEFINE BLDPNT(A) < POINT 7,GST'A> ZZ==0 INITAB: REPEAT GW, ;ROUTINE TO CHECK IF A TASK WILL FIT ON A PARTICULAR COLLUMN ;ACCEPTS IN T1/ TASK BLOCK ADR ; T2/ SCHED LIST POINTER (DEVTAB) ; T3/ COLUMN # ; T4/ START DATE OF GANTT CHART ;RETURNS +1: DID NOT FIT ; +2: OK, T1/ MAX ROW STORED INTO CHKGNT: SAVEPQ MOVEI P5,0 ;CHECK ONLY JRST CHKGN0 STOGNT: SAVEPQ MOVEI P5,1 ;STORE CHKGN0: HLRZS T4 ;GET FIRST DAY OF GANTT CHART DMOVE P1,T1 ;SAVE ARGS DMOVE P3,T3 STKVAR <,,CHKGNL,CHKGNR,CHKGNF,CHKGND> GTAD ;GET DATE HLRZM T1,CHKGND ;SAVE TODAYS DATE SETZM CHKGNF ;INIT THE FINISH DATE SETZB T1,CHKGNR ;INIT THE MAX ROW JUMPE P2,RSKP ;IF NO DEVELOPER, THEN QUIT MOVE Q3,TSKPTR ;FIND THE TASK IN THE TASK LIST CAME P1,TSKLST(Q3) ;FOUND THE TASK YET? AOBJN Q3,.-1 ;NO, CONTINUE LOOKING JUMPGE Q3,R ;IF NOT FOUND, THEN RETURN FAILURE MOVEI T4,11 ;BUILD THE NAME STRING AND LENGTH MOVEI Q1,CHKGNN ;GET ADR OF NAME BLOCK HRLI Q1,(POINT 7,0) ;BUILD BYTE POINTER TO IT LOAD T1,TKPRJ,(P1) ;GET PROJECT NAME LOAD T1,PJNAM,(T1) HRLI T1,(POINT 7,0) CHKGN1: ILDB T2,T1 ;COPY PROJECT NAME TO STRING JUMPE T2,CHKGN2 IDPB T2,Q1 TRUNC T4,MAXLEN,,CHKGN1,CHKGN2 AOJA T4,CHKGN1 ;COUNT THE # OF CHARACTERS IN NAME CHKGN2: MOVEI T2,"/" ;PUT A SLASH BETWEEN THE NAMES IDPB T2,Q1 LOAD T1,TKNAM,(P1) ;GET THE TASK NAME HRLI T1,(POINT 7,0) CHKGN3: ILDB T2,T1 ;COPY NAME TO STRING IDPB T2,Q1 TRUNC T4,MAXLEN,,CHKGN3,CKGN3A SKIPE T2 AOJA T4,CHKGN3 ;COUNT UP CHARACTERS IN NAME CKGN3A: MOVEM T4,CHKGNL ;REMEMBER THE LENGTH CHKGN4: LOAD T1,SCHTK,(P2) ;GET THE TASK ADR FROM SCHED BLOCK CAME T1,P1 ;IS IT THE ONE WE WANT? JRST CHKGN6 ;NO LOAD Q1,SCHSD,(P2) ;YES, GET THE STARTING DATE LOAD Q2,SCHFD,(P2) ;AND THE FINISH DATE HLRZS Q1 ;GET THE DAY HLRZS Q2 HLRZ T2,TSKFDL(Q3) ;GET THE END DATE CAMGE Q2,T2 ;IS THIS THE LAST PART OF THE TASK SUBI Q2,1 ;NO, DO NOT SCHEDULE WORK ON LAST DAY CHKGN5: HRROI T1,CHKGNS ;GET STRING LOAD T3,TKAFD,(P1) ;IS THERE A FINAL DATE? HRROI T2,[ASCIZ/ * /] SKIPN T3 ;IF NO FINAL DATE, PROJECT IS NOT DONE HRROI T2,[ASCIZ/ . /] ;NO FINAL DATE, TRY FOR START DATE LOAD T3,TKASD,(P1) ;HAS THE PROJECT BEEN STARTED? SKIPE T3 CAML Q1,CHKGND ;IS THIS BEFORE TODAY? HRROI T2,[ASCIZ/ /] ;NO SETZ T3, SOUT LOAD T2,SCHRT,(P2) ;GET THE RATE HLRZ T3,TSKFDL(Q3) ;GET THE END DATE CAMN T3,Q1 ;IS THIS THE END DATE? JRST [ HRROI T2,[ASCIZ/ END/] SETZ T3, SOUT JRST CHKGN7] MOVE T3,Q1 ;GET CURRENT DATE ADDI T3,2 ;SEE IF IT IS A WEEKEND IDIVI T3,7 CAIL T4,5 JRST [ HRROI T2,[ASCIZ/ -- /] SETZ T3, SOUT JRST CHKGN7] ;NO WORK IS SCHEDULED ON WEEKENDS MOVE T3,[FL%ONE!FL%PNT!1B23!2B29] CAML T2,[10.0] ;GREATER THAN 10? MOVE T3,[FL%ONE!FL%PNT!2B23!1B29] FLOUT ;OUTPUT THE RATE JSP ERROR ;.. ;.. CHKGN7: MOVEI T2," " BOUT ;SPACE HRROI T2,SPACES HLRZ T3,TSKSDL(Q3) ;GET THE START DATE CAMN T3,Q1 ;IS THIS THE START DATE? HRROI T2,CHKGNN ;YES, TYPE OUT THE TASK NAME HLRZ T4,TSKFDL(Q3) ;GET THE FINISH DATE CAMN T4,Q1 ;END OF PROJECT? HRROI T2,CHKGNN ;YES, TYPE OUT TASK NAME SKIPL CHKGNF ;FIRST TIME FOR THIS SCHED BLOCK? CAMG Q1,CHKGNF ;YES, IS THERE A HOLE IN THE GANTT SKIPA ;NO HRROI T2,CHKGNN ;YES, TYPE OUT PROJECT NAME AGAIN SETOM CHKGNF ;MARK THAT NO LONGER THE FIRST TIME MOVN T3,CHKGNL ADDI T3,7 ;GET LENGTH OF NAME STRING SOUT ;PUT NAME INTO STRING MOVE T1,P3 ;GET COLUMN NUMBER MOVE T2,CHKGNL ;AND LENGTH OF STRING HRROI T3,CHKGNS ;GET POINTER TO THE STRING MOVE T4,Q1 ;GET THE DATE SUB T4,P4 ;GET THE ROW CAMLE T4,CHKGNR ;NEW MAXIMUM ROW? MOVEM T4,CHKGNR ;YES XCT [ CALL CHKFLD CALL STOFLD](P5) ;CHECK THIS STRING RET ;FAILED TO FIT CAMGE Q1,Q2 ;REACHED THE FINISH DATE YET? AOJA Q1,CHKGN5 ;NO, LOOP BACK LOAD T1,SCHFD,(P2) HLRZM T1,CHKGNF ;STORE THE LAST DATE FOR THIS BLOCK CHKGN6: LOAD P2,SCHLN,(P2) ;GO TO NEXT TASK IN CHAIN JUMPN P2,CHKGN4 ;LOOP TIL LIST IS ENDED MOVE T1,CHKGNR ;GET MAX ROW RETSKP ;OK RETURN SPACES: XLIST REPEAT ROWLEN, 0 LIST ;ROUTINE TO INITIALIZE THE GANTT DATA BASE ;ACCEPTS IN T1/ ROW OFFSET INISTO: MOVEM T1,ROWOFS ;SAVE THE ROW OFFSET MOVE T1,[ROWSTG,,ROWSTG+1] SETZM ROWSTG BLT T1,ROWSTG+ROWSTL-1 SETZM COLMAX ;INIT MAX COLUMN RET ;ROUTINE TO STORE THE DATES IN THE DATA BASE ;ACCEPTS IN T1/ START DATE OF GANTT CHART STODAT: SAVEQ STKVAR <,STODAR> MOVEM T2,STODAR ;SAVE THE ROW MOVE Q1,T1 ;SAVE THE START DATE MOVSI Q2,-NCOL STODA1: HRLZ T2,Q2 ;GET THE DATE ADD T2,Q1 SETZ T4, ODCNV HLRZ Q3,T3 ;GET THE DAY OF THE MONTH AOS Q3 TRNE Q2,-1 ;FIRST TIME THRU? CAIN Q3,1 ;NO, IS THIS THE FIRST OF THE MONTH? JRST STODA3 ;YES, GO PRINT THE DATE HRROI T1,STODAS ;GET THE STRING ADR MOVE T2,Q3 ;GET THE DAY OF THE MONTH MOVE T3,[NO%LFL!6B17!^D10] NOUT ;OUTPUT JUST THE DAY NUMBER JSP ERROR HRROI T2,[ASCIZ/ /] SETZ T3, SOUT ;FILLER STODA2: HRRZ T1,Q2 ;GET THE COL MOVE T2,STODAR ;GET ROW HRROI T3,STODAS ;GET STRING POINTER CALL STODST ;GO STORE THE DATE STRING AOBJN Q2,STODA1 ;LOOP BACK FOR ALL DATES RET ;DONE STODA3: HRROI T1,STODAS ;GET FULL DATE HRLZ T2,Q2 ;GET THE OFFSET ADD T2,Q1 ;GET THE DATE MOVE T3,[OT%DAM!OT%SPA!OT%NTM] ODTIM HRROI T2,[ASCIZ/ /] SETZ T3, SOUT JRST STODA2 ;ROUTINE TO CHECK IF A FIELD WILL FIT WITHOUT OVERLAPPING ;ACCEPTS IN T1/ COL # ; T2/ WIDTH OF FIELD ; T3/ POINTER TO STRING ; T4/ ROW # CHKFLD: SAVEQ SETZ Q1, ;CHECK ONLY JRST STOFL1 STOFLD: SAVEQ MOVEI Q1,1 ;STORE THE FIELD STOFL1: TLC T3,-1 ;STRING POINTER TLCN T3,-1 HRLI T3,(POINT 7,0) ;YES JUMPL T4,RSKP ;IF TOO EARLY, THEN DONE ASUBR CAIL T4,NROW ;IS THE ROW TOO LARGE? RETSKP ;YES, OFF THE END CAIL T1,NCOL ;WITHIN BOUNDS? RETSKP ;NO ADD T1,T2 ;DOES FIELD GO OFF THE END? CAIL T1,NCOL ; MOVEI T1,NCOL-1 ;YES, JUST USE FIRST PART OF FIELD SUB T1,STOFLC ;GET UPDATED WIDTH MOVEM T1,STOFLW STOFL2: ILDB T1,STOFLP ;GET THE NEXT CHAR FROM THE FIELD JUMPE T1,RSKP ;IF NULL, THEN DONE MOVE T2,STOFLC ;GET COL NUMBER MOVE T3,STOFLR ;GET ROW NUMBER XCT [ CALL CHKCHR ;GO STORE/CHECK THIS CHAR CALL STOCHA](Q1) RETSKP ;EXCEEDED TABLE SIZE JUMPE T1,R ;FAILED? AOS STOFLC ;NO, GO CHECK THE NEXT COL SOSLE STOFLW ;ANY MORE CHARACTERS? JRST STOFL2 ;YES RETSKP ;NO, ALL DONE ;ROUTINE TO STORE A STRING ;ACCEPTS IN T1/ COL # ; T2/ ROW # ; T3/ STRING POINTER STOSTR: HRRES T1 ;EXTEND THE SIGN IF HALF WORD GIVEN HRRES T2 TLC T3,-1 ;CONVERT TO BYTE POINTER TLCN T3,-1 HRLI T3,(POINT 7,0) ASUBR STOST1: ILDB T1,STOSTP ;GET THE NEXT CHARACTER JUMPE T1,R ;NULL IS THE END MOVE T2,STOSTC ;GET THE COLUMN # MOVE T3,STOSTN ;GET THE ROW # CALL STOCHA ;GO STORE IT ALWAYS JFCL AOS STOSTC ;COUNT UP THE COLUMN JRST STOST1 ;LOOP BACK TILL NULL ;ROUTINES TO STORE CHARACTERS INTO THE DATA BASE ;ACCEPTS IN T1/ CHAR ; T2/ COL # ; T3/ ROW # ; CALL STOCHR ;RETURNS +1: FAILED, EXCEEDED TABLE SIZE ; +2: OK, T1/ 0 = ALREADY A CHAR THERE, -1 = OK STOCHA: MOVEI T4,1 ;STORE THE CHARACTER ALWAYS JRST STOCH1 CHKCHR: TDZA T4,T4 ;CHECK IF NO CHAR IN THIS COLLUMN STOCHR: SETO T4, ;STORE CHAR IF NONE THERE ALREADY STOCH1: HRRES T2 ;EXTEND THE SIGN IF HALF WORD GIVEN HRRES T3 ASUBR SUB T3,ROWOFS ;REMOVE THE OFFSET FROM THE ROW JUMPL T2,R ;NEGATIVE COL IS WRONG JUMPL T3,R ;NEGATIVE ROW IS WRONG CAIGE T2,NCOL ;LEGAL COLUMN? CAIL T3,NROW ;YES, LEGAL ROW? RET ;NO JUMPE T4,STOCH3 ;STORING? CAML T2,COLMAX ;YES, IS THIS A NEW MAXIMUM COLUMN? MOVEM T2,COLMAX ;YES, REMEMBER IT STOCH3: MOVEI T4,ROWLEN ;GET THE CHAR POSITION IMULI T4,0(T3) IDIVI T2,6 ;GET WORD POSITION IN COLUMN ADD T4,T2 ;GET WORD NUMBER WITHIN DATA BASE LDB T2,BPTAB(T3) ;GET THE APPROPRIATE BYTE SKIPE T2 ;ANY CHAR THERE ALREADY? SKIPLE STOCHF ;YES, STORE IT ANY WAYS? SKIPA ;YES JRST STOCH2 ;FAILED, CHARACTER ALREADY THERE CAIL T1,140 ;LOWER CASE? SUBI T1,40 ;YES, RAISE IT SUBI T1,40 ;STORE SIXBIT CHAR SKIPE STOCHF ;DONT STORE THE CHAR? DPB T1,BPTAB(T3) ;NO, STORE IT SKIPA T1,[-1] ;FLAG SUCCESS STOCH2: SETZ T1, ;FAILED RETSKP BPTAB: POINT 6,ROWSTG(T4),5 POINT 6,ROWSTG(T4),11 POINT 6,ROWSTG(T4),17 POINT 6,ROWSTG(T4),23 POINT 6,ROWSTG(T4),29 POINT 6,ROWSTG(T4),35 ;ROUTINE TO PRINT THE GANTT CHART ;ACCEPTS IN T1/ 0,,JFN = FIRST PASS, -1,,JFN = SECOND PPASS ; T2/ STARTING COL ; T3/ MAX COL ,, MAX ROW ; T4/ START DATE PRIGNT: SAVEPQ SETZ Q1, ;LPT JRST PRIGN0 PLOGNT: SAVEPQ MOVEI Q1,1 ;PLOTTER PRIGN0: STKVAR <,PRIGNF> MOVEM Q1,PRIGNF ;SAVE THE DEVICE FLAG DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 MOVE Q1,P2 ;GET STARTING COL PRIGN1: SETZ Q2, ;SET ROW TO 0 HRROI T1,PRIGNS ;GET THE DATE LINE MOVE T2,P4 ;START DATE MOVE T3,Q1 ;COL HLL T3,P3 ;GET MAX COL MOVE T4,PRIGNF ;GET FLAG (LPT OR PLOTTER) CALL PRIGDT ;GET DATE LINES PRIGN2: MOVEI Q3,NGROW ;GE NUMBER OF ROWS TO DO PRIGN3: MOVE T1,P1 ;GET JFN MOVEI T2," " ;IF PLOTTING, LEAVE A SPACE IN COL 1 SKIPE PRIGNF ;PLOTTING? BOUT ;YES, THIS KEEPS "TXT2P" FROM GETTING LOST MOVE T2,Q1 ;GET COL MOVE T3,Q2 ;GET ROW HLRZ T4,P3 ;GET MAX COL CALL PRIGCL ;GO PRINT THIS ROW AOS Q2 ;STEP ROW HRRZ T1,P3 ;GET MAX ROW CAIL T1,NROW ;BEYOND END OF TABLE? MOVEI T1,NROW ;YES, STOP HERE CAML Q2,T1 ;REACHED THE END? JRST PRIGN4 ;YES SOJG Q3,PRIGN3 ;LOOP BACK FOR MORE ROWS MOVE T1,P1 ;TIME TO OUTPUT THE DATE LINES HRROI T2,PRIGNS ;GET POINTER TO STRING SETZ T3, SOUT JRST PRIGN2 ;LOOP BACK FOR NEXT SET OF ROWS PRIGN4: MOVE T1,P1 ;TIME TO OUTPUT THE DATE LINES HRROI T2,PRIGNS ;GET POINTER TO STRING SETZ T3, SOUT RET ;DONE ;ROUTINE TO OUTPUT A ROW ;ACCEPTS IN T1/ JFN ; T2/ COL OFFSET ; T3/ ROW ; T4/ MAX COL PRIGCL: SAVEP STKVAR <> JUMPL T2,R ;NEGATIVE IS NOT ALLOWED JUMPL T3,R CAIL T3,NROW ;LEGAL ROW? RET ;NO CAIL T4,NCOL ;MAX COL? MOVEI T4,NCOL-1 ;NO, MAKE IT LEGAL DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 MOVEI T4,ROWLEN ;GET POINTER TO THE ROW IMULI T4,(P3) ADDI T4,ROWSTG HRLI T4,(POINT 6,0) MOVE T2,P2 ;GET COL OFFSET ADJBP T2,T4 ;GET CORRECT COL STARTING POINT MOVE T4,T2 ;SAVE POINTER IN T4 MOVE T3,P4 ;GET MAX COL SUB T3,P2 ;GET NUMBER OF COLS TO OUTPUT JUMPL T3,R ;IF NONE, THEN DONE MOVEI T1,PRIGCS ;GET POINTER TO TEMP STRING HRLI T1,(POINT 7,0) PRIGC1: ILDB T2,T4 ;GET NEXT CHAR ADDI T2,40 ;SIXBIT TO ASCII CAIN T2,"\" ;PLACE HOLDER? MOVEI T2," " ;YES, PRINT IT AS SPACE IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING SOJG T3,PRIGC1 ;LOOP BACK FOR ALL CHARS IN ROW MOVEI T2,15 ;CR IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING MOVEI T2,12 ;LF IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING MOVEI T2,0 ;PUT A NUL AT THE END IDPB T2,T1 MOVE T1,P1 ;GET THE JFN HRROI T2,PRIGCS ;GET POINTER TO THE STRING SETZ T3, SOUT ;OUTPUT THE LINE RET ;DONE ;ROUTINE TO BUILD THE DATE LINES ;ACCEPTS IN T1/ STRING POINTER ; T2/ START DATE ; T3/ MAX COL ,, STARTING COL ; T4/ 0 = LPT, 1 = PPLOTTER PRIGDT: SAVEPQ STKVAR <> MOVE P5,T4 ;SAVE FLAG HLRZ T4,T3 ;T4 = MAX COL HRRZS T3 ;T3 = STARTING COL DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 SUB P4,P3 ;GET THE NUMBER OF CHARS TO OUTPUT JUMPL P4,R ;IF NONE, RETURN HRROI T2,[ASCIZ/ /] SETZ T3, SOUT ;START WITH A CR-LF MOVEI T2," " ;PUT IN A SPACE IF PLOTTER SKIPE P5 ;PLOTTER? BOUT ;YES HRLZ T2,P3 ;GET STARTING COL ADDM T2,P2 ;STEP THE DATE TO THE RIGHT SPOT HLRZ T3,P2 ;GET DAY ADDI T3,2 ;SEE IF IT IS A MONDAY IDIVI T3,7 MOVE Q3,P4 ;GET COUNT OF COLS TO DO MOVEI T2," " ;SPACE JUMPE T4,PRIGD2 ;IF MONDAY, SKIP OVER INITIAL SPACES MOVNS T4 ;GET NUMBER OF DAYS TIL MONDAY ADDI T4,7 PRIGD1: BOUT ;OUTPUT SPACE SOJLE Q3,PRIGD3 ;COUNT DOWN COLS SOJG T4,PRIGD1 ;LOOP BACK UNTIL MONDAY PRIGD2: MOVEI T2,"!" BOUT SOJLE Q3,PRIGD3 ;DONE? SUBI Q3,3 JUMPL Q3,PRIGD3 ;ENOUGH ROOM FOR THE DATE? MOVEI T2," " BOUT MOVEM T1,P1 ;SAVE THE STRING POINTER MOVE T2,P4 ;GET CURRENT DATE... SUBI T2,4(Q3) ;GET OFFSET HRLZS T2 ADD T2,P2 ;GET TODAY'S DATE SETZ T4, ODCNV HLRZ T2,T3 ;GET DAY OF THE MONTH ADDI T2,1 ;PLUS ONE SINCE FIRST DAY = 0 MOVE T1,P1 ;GET JFN MOVE T3,[NO%ZRO+2B17+12] NOUT MOVE T1,P1 SUBI Q3,3 ;ENOUGH ROOM FOR SPACES JUMPLE Q3,PRIGD3 HRROI T2,[ASCIZ/ /] SETZ T3, SOUT JRST PRIGD2 PRIGD3: HRROI T2,[ASCIZ/ /] SETZ T3, SOUT MOVEI T2," " ;PUT A SPACE AT START OF LINE IF PLOTTER SKIPE P5 ;PLOTTER? BOUT ;YES, ADD A SPACE HLRZ T3,P2 ;GET START DATE ADDI T3,2 IDIVI T3,7 ;GET NUMBER OF DAYS FROM MONDAY ADJBP T4,[POINT 7,[ASCIZ/M.W.F..M.W.F../]] MOVE Q1,T4 ;SAVE THE BYTE POINTER MOVE Q3,P4 ;GET THE COUNT OF COLS TO DO PRIGD4: MOVE T3,Q1 ;GET THE BYTE POINTER MOVEI T4,7 ;DO 7 DAYS PRIGD5: ILDB T2,T3 ;GET NEXT CHAR BOUT SOJLE Q3,PRIGD6 ;DONE? SOJG T4,PRIGD5 ;NO, DO REST OF THE WEEK JRST PRIGD4 ;LOOP BACK FOR ANOTHER 7 DAYS PRIGD6: HRROI T2,[ASCIZ/ /] SETZ T3, SOUT MOVEI T2," " ;PUT A SPACE AT START OF LINE IF PLOTTER SKIPE P5 ;PLOTTER? BOUT ;YES, ADD A SPACE MOVE Q3,P4 ;GET COL COUNT MOVE Q2,P2 ;GET STARTING DATE PRIGD7: MOVEM T1,P1 ;SAVE THE STRING POINTER MOVE T2,Q2 ;GET DATE SETZ T4, ODCNV ;THIS THE FIRST OF THE MONTH? MOVE T1,P1 ;RESTORE THE STRING POINTER TLNN T3,-1 ;DAY 0? JRST PRIGD8 ;YES MOVE T1,P1 ;GET THE JFN MOVEI T2," " BOUT SOJLE Q3,PRIGD9 ;DONE? MOVSI T2,1 ;STEP TO NEXT DAY ADDM T2,Q2 JRST PRIGD7 ;LOOP BACK UNTIL 1ST OF THE MONTH PRIGD8: MOVEI T2,"!" BOUT MOVEM T1,P1 ;SAVE THE STRING POINTER SOJLE Q3,PRIGD9 ;DONE? SUBI Q3,7 ;ENOUGH ROOM FOR MONTH? JUMPL Q3,PRIGD9 HRROI T1,PRIGDS ;GET THE DATE MOVE T2,Q2 ;DATE MOVE T3,[OT%SPA!OT%NTM] ODTIM MOVE T1,P1 ;GET THE JFN MOVEI T2,PRIGDS ;GET POINTER TO STRING HRLI T2,(POINT 7,0,13) ;STEP OVER THE DAY FIELD SETZ T3, SOUT ;OUTPUT THE MONTH AND YEAR MOVSI T2,^D8 ;STEP DATE ADDM T2,Q2 JRST PRIGD7 ;LOOP BACK TIL DONE PRIGD9: MOVE T1,P1 ;GET THE JFN HRROI T2,[ASCIZ/ /] SETZ T3, SOUT RET ;ROUTINE TO PRINT THE STORED DATA BASE ;ACCEPTS IN T1/ JFN ; T2/ MAX ROW TO BE PRINTED ; T3/ MAXIMUM COLUMN TO BE PRINTED ; T4/ COLUMN OFFSET PRISTO: SAVEPQ STKVAR > MOVEM T1,PRISTA ;SAVE THE ARGS MOVEM T2,PRISTB MOVEM T3,PRISTC MOVEM T4,PRISTD DVCHR ;GET CHARACTERISTICS OF DEVICE LDB Q3,[POINT 9,T2,17] ;GET DEVICE TYPE MOVE T1,PRISTA ;GET BACK THE JFN MOVE T2,PRISTB ;GET ROW MOVE T3,PRISTC ;GET COL CAIL T2,NROW ;ABOVE MAXIMUM ROW? MOVEI T2,NROW ;YES MOVNS T2 CAIL T3,NCOL ;ABOVE THE MAX COLUMN? MOVEI T3,NCOL-1 ;YES MOVE P3,PRISTD ;INIT COL COUNTER HRLZ P1,T2 ;GET ROW COUNTER INTO P1 AOS P2,T3 ;P2 = MAXIMUM COLUMN PRIST0: MOVE Q1,P1 ;SET UP ROW COUNTER PRIST1: MOVEI T4,^D132 ;SET UP COLUMN COUNTER FOR THIS SECTION CAML T4,P2 ;REACHED THE END? MOVE T4,P2 ;YES, ONLY PRINT UP TO COLMAX MOVNS T4 ;SET UP AOBJN POINTER HRLZ Q2,T4 ;SET UP COLUMN COUNT HRR Q2,P3 ;SET UP STARTING COLUMN MOVEI T4,ROWLEN ;GET POINTER TO CORRECT ROW IMULI T4,(Q1) ADDI T4,ROWSTG ;GET CORRECT POSITION IN DATA BASE HRLI T4,(POINT 6,0) ;GET BYTE POINTER TO FIRST CHAR IN ROW MOVEI T2,(Q2) ;ADVANCE BYTE POINTER TO CORRECT SPOT ADJBP T2,T4 MOVE T4,T2 ;LEAVE ADJUSTED BYTE POINTER IN T4 MOVEI T1,PRISTS ;SET UP POINTER TO TEMP STRING HRLI T1,(POINT 7,0) PRIST2: ILDB T2,T4 ;GET NEXT CHAR ADDI T2,40 ;SIXBIT TO ASCIZ CAIN T2,"\" ;PLACE HOLDER? MOVEI T2," " ;YES, PRINT IT AS SPACE IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING AOBJN Q2,PRIST2 ;NO, LOOP BACK FOR ALL CHARACTERS IN ROW MOVEI T2,15 ;OUTPUT A CR-LF IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING MOVEI T2,12 CAIE Q3,.DVTTY ;IS THIS A TTY? MOVEI T2,"S"-100 ;NO, THEN PUT OUT A DC3 INSTEAD IDPB T2,T1 ;STORE THE CHARACTER IN THE TEMP STRING MOVEI T2,0 ;END WITH A NUL IDPB T2,T1 MOVE T1,PRISTA ;GET THE JFN HRROI T2,PRISTS ;GET POINTER TO THE TEMP STRING SETZ T3, SOUT ;OUTPUT THIS LINE AOBJN Q1,PRIST1 ;LOOP BACK FOR ALL ROWS RET ;DONE ;ROUTINE TO PRINT OUT THE PLOTTER DATA ;ACCEPTS IN T1/ JFN ; T2/ MAX ROW ; T3/ MAX COL PRIPLT: SAVEQ STKVAR >> MOVEM T1,PRIPLJ ;SAVE THE JFN CAIL T2,NROW ;LEGAL ROW? MOVEI T2,NROW-1 ;NO, TRUNCATE IT CAIL T3,NCOL ;LEGAL COL? MOVEI T3,NCOL-1 ;NO, TRUNCATE IT DMOVE Q2,T2 ;SAVE ROW AND COL HRROI T2,[ASCIZ/.TEXTSIZE;0.12 X .SIZE;1,/] SETZ T3, SOUT MOVEI T2,1(Q3) ;GET MAX COL MOVEI T3,^D10 NOUT JFCL HRROI T2,[ASCIZ/C,0 /] SETZ T3, SOUT SETZ Q1, ;START AT ROW 0 PRIPL1: MOVEI T4,ROWLEN ;GET ADR OF FIRST WORD OF ROW IMULI T4,(Q1) ADDI T4,ROWSTG HRLI T4,(POINT 6,0) ;GET BYTE POINTER TO ROW SETZ T3, ;START AT FIRST COL MOVEI T1,PRIPLS ;SET POINTER TO TEMP STRING HRLI T1,(POINT 7,0) PRIPL2: ILDB T2,T4 ;GET NEXT CHAR ADDI T2,40 ;SIXBIT TO ASCIZ CAIN T2,"\" ;PLACE HOLDER? MOVEI T2," " ;YES, PRINT IT AS SPACE IDPB T2,T1 ;PUT CHAR IN THE STRING CAMGE T3,Q3 ;FINISHED WITH ROW? AOJA T3,PRIPL2 ;NOT YET MOVEI T2,0 ;END WITH A NUL IDPB T2,T1 MOVE T1,PRIPLJ ;GET JFN HRROI T2,PRIPLS ;GET POINTER TO STRING SETZ T3, SOUT ;OUTPUT THE STRING HRROI T2,[ASCIZ/ /] SETZ T3, ;OUTPUT CRLF SOUT CAMGE Q1,Q2 ;AT THE LAST ROW? AOJA Q1,PRIPL1 ;NO, GO DO THE NEXT ROW RET ;DONE ;ROUTINE TO DRAW A BOX AROUND EACH TASK ;ACCEPTS IN T1/ JFN ; T2/ DATE DBOX: SAVEQ MOVE Q1,T1 ;SAVE THE JFN MOVE Q3,T2 ;SAVE TODAY'S DATE MOVE Q2,TSKPTR ;GET POINTER TO THE LIST DBOX1: SKIPE TSKINV(Q2) ;WANT THIS IN PERT? JRST DBOX2 ;NO--SKIP IT MOVE T1,Q1 ;GET THE JFN HRRZ T2,Q2 ;GET THE TASK INDEX CALL DLINI ;DRAW THE BOX JFCL ;FAILED HRRZ T4,TSKLST(Q2) ;GET TASK ADR LOAD T3,TKAFD,(T4) ;GET ACTUAL FINISH DATE JUMPE T3,DBOX2 ;IF NONE, THEN NOT DONE CAML Q3,TSKFDL(Q2) ;FINISH IN THE FUTURE? CAMLE T3,Q3 ;OR TASK ALREADY FINISHED? JRST DBOX2 ;TASK IS NOT DONE MOVE T1,Q1 ;GET THE JFN HRRZ T2,Q2 ;GET THE TASK INDEX CALL DLINO ;DRAW OUTER BOX JFCL DBOX2: AOBJN Q2,DBOX1 ;LOOP BACK FOR ALL BOXES RET ;ROUTINE TO DRAW THE INSIDE BOX ;ACCEPTS IN T1/ JFN ; T2/ TASK INDEX ;RETURNS +1: FAILED ; +2: OK DLINI: SAVEQ MOVE Q1,T2 ;SAVE THE TASK INDEX HRROI T2,[ASCIZ/.AMOVE;/] SETZ T3, SOUT MOVE T2,TSKPOS(Q1) ;GET START OF BOX ADDI T2,2 ;STEP OVER INITIAL SPACES MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.9C,-\] SETZ T3, SOUT HLRZ T2,TSKSKD(Q1) ;GET THE LEVEL # IMULI T2, ;GET THE Y COORD ADDI T2,1 ;STEP OVER THE FIRST LINE MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.9C .RLINE;0.0,-6.5C/\] SETZ T3, SOUT MOVE T2,TSKWID(Q1) ;GET BOX WIDTH SUBI T2,6 ;MINUS FILLER MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.1C,0.0C/0.0C,6.5C/-\] SETZ T3, SOUT MOVE T2,TSKWID(Q1) ;GET WIDTH AGAIN SUBI T2,6 MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.1C,0.0C \] SETZ T3, SOUT RETSKP ;ROUTINE TO DRAW THE OUTSIDE BOX ;ACCEPTS IN T1/ JFN ; T2/ TASK INDEX ;RETURNS +1: FAILED ; +2: OK DLINO: SAVEQ CALL TOBOX ;.AMOVE OVER TO BOX RET ;FAILED MOVE Q1,T2 HRROI T2,[ ASCIZ \.RLINE;0.0,-7.5C/\] SETZ T3, SOUT MOVE T2,TSKWID(Q1) ;GET BOX WIDTH SUBI T2,5 ;MINUS FILLER MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.9C,0.0C/0.0C,7.5C/-\] SETZ T3, SOUT MOVE T2,TSKWID(Q1) ;GET WIDTH AGAIN SUBI T2,5 MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.9C,0.0C \] SETZ T3, SOUT RETSKP ;ROUTINE TO CONNECT THE BOXES TOGETHER ;ACCEPTS IN T1/ JFN CBOX: SAVEPQ STKVAR <> MOVE P4,T1 ;SAVE THE JFN SETZ Q1, ;START AT LEVEL 0 CBOX1: MOVE Q2,TSKPTR ;SET UP POINTER TO TASK LIST SETZ Q3, ;INIT COUNT OF TASKS FOUND CBOX2: SKIPE TSKINV(Q2) JRST CBOX5 HLRZ T1,TSKSKD(Q2) ;GET LEVEL # CAME T1,Q1 ;IS THIS A DESIRED LEVEL? JRST CBOX5 ;NO AOS Q3 ;COUNT UP TASKS FOUND AT THIS LEVEL HRRZ P1,TSKLST(Q2) ;GET ADR OF TASK LOAD P2,TKBLP,(P1) ;SEE IF IT IS BLOCKING ANYTHING JUMPE P2,CBOX5 CBOX3: LOAD T1,DPTKP,(P2) ;GET ADR OF BLOCKED TASK LOAD T1,TKTKI,(T1) ;GET ITS TASK LIST INDEX MOVE T3,T1 ;GET INDEX OF DESTINATION BOX HRRZ T2,Q2 ;GET INDEX OF SOURCE BOX HRROI T1,CBOXST ;GET POINTER TO STRING CALL CBOXI ;DRAW THE LINES JRST CBOX4 ;FAILED HRROI T2,CBOXST ;OUTPUT LINE COMMAND TO JFN SETZ T3, MOVE T1,P4 ;GET THE JFN SOUT CBOX4: LOAD P2,DPBLP,(P2) ;STEP TO NEXT BLOCKED TASK JUMPN P2,CBOX3 ;IF THERE ARE ANY LEFT CBOX5: AOBJN Q2,CBOX2 ;LOOP BACK FOR THIS LEVEL JUMPE Q3,R ;IF NONE FOUND, THEN DONE AOJA Q1,CBOX1 ;LOOP BACK FOR THE NEXT LEVEL ;ROUTINE TO SET UP FOR DRAWING THE LINES ;ACCEPTS IN T1/ STRING POINTER ; T2/ INDEX OF FIRST TASK ; T3/ INDEX OF SECOND TASK CBOXI: SAVEQ MOVE Q1,T1 ;SET UP FOR DLINE DMOVE Q2,T2 ;SAVE THE ARGS SKIPN TSKINV(T2) ;WANT FIRST TASK SKIPE TSKINV(T3) ;AND SECOND TASK RET ;NO MOVE T1,TSKPOS(Q2) ;GET POSITION OF FIRST TASK MOVE T2,TSKWID(Q2) ;ADD IN HALF THE WIDTH LSH T2,-1 ADDI T1,-1(T2) ;WIDTH INCLUDES SOME BLANKS TO SKIP OVER HLRZ T2,TSKSKD(Q2) ;GET LEVEL # MOVE T3,TSKPOS(Q3) ;GET ADR OF SECOND BOX MOVE T4,TSKWID(Q3) LSH T4,-1 ADDI T3,-1(T4) ;ADD IN HALF THE WIDTH HLRZ T4,TSKSKD(Q3) ;GET THE LEVEL # CALL DLINE ;DRAW THE LINES RET RETSKP ;ROUTINE TO DRAW A LINE FROM ONE BOX TO ANOTHER ;ACCETPS IN T1/ START ADR ; T2/ LEVEL # OF FIRST BOX ; T3/ END ADR ; T4/ LEVEL # OF SECOND BOX ; Q1/ STRING POINTER TO RECEIVE THE ANSWER ; CALL DLINE ;RETURNS +1: FAILED ; +2: SUCCESS DLINE: ASUBR MOVE T1,Q1 ;GET POINTER TO STRING HRROI T2,[ASCIZ/.AMOVE;/] SETZ T3, SOUT ;START BY MOVING TO THE START ADR MOVE T2,DLINS ;GET START ADR MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ/.4C,-/] ;NOW DO THE Y COORD SETZ T3, SOUT MOVE T2,DLINL1 ;GET THE LEVEL # IMULI T2, ;GET Y COORD ADDI T2,BOXLEN-2 ;GET BOTTOM OF THE BOX MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ/.4C .RLINE;0.0C,-1.0C .ALINE;/] SETZ T3, SOUT MOVE Q1,T1 ;SET UP FOR CALL TO DLINE0 MOVE T1,DLINS MOVE T2,DLINL1 MOVE T3,DLINF MOVE T4,DLINL2 CALL DLINE0 ;GO DRAW THE LINES TO THE END BOX RET ;FAILED RETSKP ;OK ;ROUTINE TO DRAW LINES (CALLED RECURSIVELY) ;ACCEPTS SAME ARGS AS DLINE DLINE0: ASUBR CAIG T4,1(T2) ;AT THE END? JRST DLINE1 ;YES MOVE T1,DLST ;GET THE START ADR MOVE T2,DLEND MOVE T3,DLL1 ;GET THE LEVEL NUMBER ADDI T3,1 ;GET LEVEL NUMBER OF NEXT SET OF BOXES CALL FNDHOL ;FIND THE APPROPRIATE HOLE RET ;NONE FOUND MOVEM T1,DLST ;SAVE THE NEW X COORD MOVE T2,T1 ;GET X COORD INTO T2 MOVE T1,Q1 ;GET STRING POINTER MOVEI T3,^D10 NOUT ;OUTPUT X COORD OF THE HOLE RET HRROI T2,[ASCIZ/.4C,-/] SETZ T3, SOUT AOS T2,DLL1 ;GET THE LEVEL NUMBER OF NEXT LEVEL IMULI T2, MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.65C/\] SETZ T3, SOUT MOVE T2,DLST ;GET X COORD AGAIN MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ/.4C,-/] SETZ T3, SOUT MOVE T2,DLL1 ;GET Y COORD IMULI T2, ADDI T2,BOXLEN-1 MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.4C/\] SETZ T3, SOUT MOVE Q1,T1 ;SET UP FOR RECURSION MOVE T1,DLST ;GET BACK THE ARGS MOVE T2,DLL1 MOVE T3,DLEND MOVE T4,DLL2 CALL DLINE0 ;GO DO REST OF THE LINES RET RETSKP ;DONE ;COME HERE ON LAST LINE DLINE1: MOVE T1,Q1 ;GET THE STRING POINTER MOVE T2,DLEND ;GET X COORD OF FINAL POSITION MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ/.4C,-/] SETZ T3, SOUT MOVE T2,DLL2 ;GET THE Y COORD IMULI T2, ADDI T2,1 ;DRAW LINE TO THE BOX MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ/.4C .RLINE;0.0C,-0.5C /] SETZ T3, SOUT RETSKP ;DONE ;ROUTINE TO FIND A FREE HOLE BETWEEN BOXES AND THEN PLUG IT ;ACCEPTS IN T1/ START X ADR ; T2/ END X ADR ; T3/ LEVEL # TO LOOK AT ; CALL FNDHOL ;RETURNS +1: NONE FOUND ; +2: T1/ ADR OF THE HOLE ; HOLE FILLED WITH 1 FNDHOL: SAVEQ SETZ Q1, ;INIT COL COUNTER SETO Q2, ;NO SPACES SEEN YET IMULI T3,SPCTBL ;GET INDEX INTO SPACE TABLE ADDI T3,SPCTAB HRLI T3,(POINT 1,0) ;BUILD POINTER TO ROW FNDHL1: CAIL Q1,NCOL ;AT THE END OF THE ROW? JRST [ JUMPL Q2,R ;IF NONE FOUND, RETURN JRST FNDHL3] ;GO USE THE LAST HOLE FOUND ILDB T4,T3 ;GET NEXT CHAR SKIPE T4 ;FOUND A SPACE? AOJA Q1,FNDHL1 ;NO, LOOP BACK CAML Q1,T1 ;BEYOND WHERE WE WANT? JRST FNDHL2 ;YES, GO USE THIS HOLE MOVE Q2,Q1 ;SAVE THIS HOLE MOVE Q3,T3 ;SAVE THE BYTE POINTER ALSO AOJA Q1,FNDHL1 ;LOOP BACK FOR A MOR OPTIMUM HOLE FNDHL2: CAMN Q1,T1 ;EXACTLY THE RIGHT SPOT? JRST FNDHL4 ;YES, GO USE THIS ONE CAMLE T1,T2 ;BACKWARDS LINE OR FORWARD LINE? JUMPGE Q2,FNDHL3 ;BACKWARDS, USE LAST HOLE FOUND FNDHL4: MOVEI T4,1 ;GET PLUG CHARACTER DPB T4,T3 ;STORE IT MOVE T1,Q1 ;GET THE X COORD RETSKP ;DONE FNDHL3: MOVEI T4,1 ;GET PLUG CHARACTER DPB T4,Q3 ;STORE IT MOVE T1,Q2 ;GET X COORD RETSKP ;DONE ;ROUTINE TO INIT THE SPACE TABLE INISPC: SETZM SPCTAB ;ZERO THE FIRST WORD IN TABLE MOVE T1,[SPCTAB,,SPCTAB+1] BLT T1,SPCTBS-1+SPCTAB ;ZERO THE REST RET ;ROUTINE TO MARK USED COLUMNS ;ACCEPTS IN T1/ LEVEL # ; T2/ ROW # SETSPC: SUB T2,ROWOFS ;GET POINTER TO ROW JUMPL T2,R ;IF NEGATIVE ROW, DONT DO ANYTHING MOVEI T4,NCOL ;SET UP COUNTER IMULI T1,SPCTBL ;GET OFFSET INTO SPACE TABLE ADDI T1,SPCTAB HRLI T1,(POINT 1,0) ;GET POINTER TO THIS LINE IMULI T2,ROWLEN ADDI T2,ROWSTG HRLI T2,(POINT 6,0) SETSP1: ILDB T3,T2 ;GET THE NEXT CHAR ADDI T3,40 ;SIXBIT TO ASCIZ CAIN T3," " ;SPACE? TDZA T3,T3 ;YES, MARK THIS AS FREE MOVEI T3,1 ;NO, THIS SPOT IS IN USE IDPB T3,T1 ;STORE THIS IN THE SPACE TABLE SOJG T4,SETSP1 ;LOOP BACK FOR THE ENTIRE LINE RET ;SUBROUTINE TO MARK BOXES WHICH HAVE "OFF PERT" CONNECTIONS ;CALL WITH: ; T1/ JFN ; CALL TICKS ; RETURN HERE TICKS: SAVEPQ MOVE P4,T1 ;SAVE JFN MOVE Q1,TSKPTR ;MAKE AOBJN POINTER TICKS1: SKIPE TSKINV(Q1) ;IS THIS TASK IN THE PERT? JRST TICKS7 ;NO--IGNORE IT HRRZ P1,TSKLST(Q1) ;ADDRESS OF TASK BLOCK LOAD P2,TKBLP,(P1) ;LIST OF TASKS WE ARE BLOCKING JUMPE P2,TICKS4 ;JUMP IF NOT BLOCKING ANYTHING TICKS2: LOAD T1,DPTKP,(P2) ;POINTER TO ITS TASK BLOCK LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX SKIPN TSKINV(T1) ;IN PERT? JRST TICKS3 ;YES--LOOK AT NEXT BLOCKED TASK HRRZ T2,Q1 ;COPY TASK INDEX MOVE T1,P4 ;COPY JFN CALL DNTICK ;SOMETHING NOT IN THE PERT NEEDS US JRST TICKS4 ;SEE IF WE NEED AN UPTICK TICKS3: LOAD P2,DPBLP,(P2) ;STEP DOWN THE LIST JUMPN P2,TICKS2 ;KEEP LOOKING DOWN THE LIST ;NOW SEE IF AN UPTICK IS NEEDED TICKS4: LOAD P2,TKDLP,(P1) ;DO WE DEPEND ON ANYTHING? JUMPE P2,TICKS7 ;NO--ALL DONE WITH THIS BOX TICKS5: LOAD T1,DPBTK,(P2) ;POINTER TO TASK BLOCK LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX SKIPN TSKINV(T1) ;IN PERT? JRST TICKS6 ;YES--LOOK AT NEXT ITEN MOVE T1,P4 ;COPY JFN HRRZ T2,Q1 ;COPY TASK INDEX CALL UPTICK ;PUT IN THE LINE JRST TICKS7 ;ALL DONE WITH THIS BOX TICKS6: LOAD P2,DPDLP,(P2) ;SCAN DOWN THE LIST JUMPN P2,TICKS5 ;LOOK AT EVERYTHING WE DEPEND ON TICKS7: AOBJN Q1,TICKS1 ;LOOK AT ALL BOXES RET ;ALL DONE! ;SUBROUTINES TO DRAW THE TICK MARKS ;CALL WITH: ; T1/ JFN ; T2/ TSKLST INDEX OF BOX ; CALL UPTICK OR DNTICK ; RETURN HERE UPTICK: CALL TOBOX ;MOVE OVER TO BOX RET ;FAILED HRRZ T4,TSKLST(T2) ;GET POINTER TO TASK BLOCK LOAD T3,TKAFD,(T4) ;GET ACTUAL FINISH DATE HRROI T2,[ASCIZ ".RMOVE;0.9C,-0.5C "] SKIPN T3 ;DONE? SOUT ;NO--MOVE TO INNER BOX HRROI T2,[ASCIZ ".RLINE;-2C,2C/0C,2C/0.5C,-0.5C .RMOVE;-1.0C,0C .RLINE;0.5C,0.5C "] SETZ T3, SOUT RET DNTICK: SAVEQ MOVE Q1,T2 ;SAVE INDEX HRROI T2,[ASCIZ ".AMOVE;"] SETZ T3, SOUT MOVE T2,TSKPOS(Q1) ;GET POSITION ADD T2,TSKWID(Q1) ;MOVE TO OTHER CORNER SUBI T2,3 ;FUDGE MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ ".9C,-"] SETZ T3, SOUT HLRZ T2,TSKSKD(Q1) ;GET LEVEL IMULI T2, ;CONVERT TO COORDINATE ADDI T2,^D8 ;BOTTOM OF BOX MOVEI T3,^D10 ;RADIX NOUT RET HRROI T2,[ASCIZ ".9C "] MOVEI T3,0 SOUT HRRZ T4,TSKLST(Q1) ;GET POINTER TO TASK BLOCK LOAD T3,TKAFD,(T4) ;GET ACTUAL FINISH DATE HRROI T2,[ASCIZ ".RMOVE;-0.9C,0.5C "] SKIPN T3 ;DONE? SOUT ;NO--MOVE TO INNER BOX HRROI T2,[ASCIZ ".RLINE;2C,-2C/0C,-2C/0.5C,0.5C .RMOVE;-1C,0C .RLINE;0.5C,-0.5C "] SETZ T3, SOUT RET ;SUBROUTINE TO MOVE OVER TO A BOX ;CALL WITH: ; T1/ JFN ; T2/ TSKLST INDEX ; CALL TOBOX ; FAILED ; OK ;***NOTE: ALL AC'S ARE PRESERVED*** TOBOX: SAVEQ MOVE Q1,T2 ;SAVE THE TASK INDEX HRROI T2,[ASCIZ/.AMOVE;/] SETZ T3, SOUT MOVE T2,TSKPOS(Q1) ;GET START OF BOX ADDI T2,2 ;STEP OVER INITIAL SPACES MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.0C,-\] SETZ T3, SOUT HLRZ T2,TSKSKD(Q1) ;GET THE LEVEL # IMULI T2, ;GET THE Y COORD ADDI T2,1 ;STEP OVER THE FIRST LINE MOVEI T3,^D10 NOUT RET HRROI T2,[ASCIZ\.4C \] SETZ T3, SOUT MOVE T2,Q1 ;RESTORE T2 RETSKP ;ROUTINE TO LIST ALL TASKS LSTTSK: HLRZ T1,1(P1) ;GET TYPE CODE CHKTYP (OFI) HRRZ T1,1(P1) ;GET POINTER TO JFN MOVE Q1,ANSWER(T1) ;GET JFN MOVE T1,Q1 ;OPEN THE JFN MOVE T2,[070000,,OF%WR] OPENF JSP ERROR HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ Q2,(P1) ;GET DISPATCH ADDRESS CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED MOVE T1,Q1 ;GET THE JFN CALL (Q2) ;GO LIST HRRZ T1,Q1 ;GET THE JFN AGAIN CLOSF ;CLOSE IT JFCL JRST LEVEL0 ;DONE ;ROUTINE TO LIST TASKS SORTED BY PROJECT ;ACCEPTS IN T1/ JFN LSTTKP: SAVEQ MOVE Q1,T1 ;SAVE THE JFN MOVE T2,PRJTBL ;GET ADR OF PROJECT TABLE HLRZ T3,0(T2) ;GET LENGTH OF TABLE MOVNS T3 ;SET UP AN AOBJN POINTER JUMPE T3,LSTTP2 ;IF NONE, THEN DONE HRLZ Q2,T3 HRRI Q2,1(T2) ;GET ADR OF FIRST ENTRY IN TABLE LSTTP1: MOVE T1,Q1 ;GET JFN HRRZ T2,0(Q2) ;GET ADR OF NEXT PROJECT BLOCK CALL TYPPRJ ;GO OUTPUT THIS PROJECT AOBJN Q2,LSTTP1 ;LOOP BACK FOR ALL PROJECTS LSTTP2: RET ;ROUTINE TO PRINT ALL TASKS SORTED BY START DATES ;ACCEPTS IN T1/ JFN LSTTKE: TDZA T2,T2 ;EARLIEST START DATE LSTTKL: MOVEI T2,1 ;LATEST START DATE SAVEQ MOVE Q1,T1 ;SAVE THE JFN MOVE Q3,T2 ;SAVE FLAG CALL PRITKH ;PRINT THE HEADER MOVE Q2,TSKPTR ;SET UP POINTER TO THE TASK LIST LSTTS1: HRRZS TSKLST(Q2) ;CLEAR THE LH OF TASK LIST AOBJN Q2,LSTTS1 LSTTS2: SETZ T4, ;INIT THE INDEX VALUE HRLOI T3,377777 ;HIGHEST DATE SO FAR MOVE Q2,TSKPTR LSTTS3: SKIPGE T1,TSKLST(Q2) ;SEE IF THIS ONE HAS NOT BEEN USED JRST LSTTS4 ;ALREADY PRINTED, GO ON TO NEXT ONE XCT [ LOAD T2,TKESD,(T1) LOAD T2,TKLSD,(T1)](Q3) CAMG T3,T2 ;FOUND A NEW LOW? JRST LSTTS4 ;NO MOVE T3,T2 ;YES, REMEMBER IT MOVE T4,Q2 ;AND THE INDEX INTO TSKLST LSTTS4: AOBJN Q2,LSTTS3 ;LOOP THROUGH THE WHOLE TSKLST JUMPE T4,R ;IF NONE FOUND, RETURN HRROS TSKLST(T4) ;MARK THAT THIS ONE WAS PRINTED MOVE T1,Q1 ;GET THE JFN HRRZ T2,TSKLST(T4) ;GET THE TASK BLOCK ADDRESS CALL PRITSK ;PRINT THE TASK JRST LSTTS2 ;LOOP BACK FOR THE REST OF THE TASKS ;ROUTINE TO PRINT THE HEADER ;ACCEPTS IN T1/ JFN PRITKH: HRROI T2,[ASCIZ/ Task Name Length Start Finish Developers Blocking Tasks Blocked Tasks /] SETZ T3, SOUT RET ;ROUTINE TO PRINT A TASK ;ACCEPTS IN T1/ JFN ; T2/ TASK BLOCK ADDRESS PRITSK: SAVEPQ DMOVE Q1,T1 ;SAVE THE ARGS LOAD T3,TKPRJ,(Q2) ;GET ADR OF PROJECT BLOCK LOAD T2,PJNAM,(T3) ;GET ADR OF PROJECT NAME BLOCK HRLI T2,(POINT 7,0) MOVEI T4,1 ;COUNT UP THE LENGTH OF THE NAME PRITS1: ILDB T3,T2 ;GET NEXT CHAR IN NAME SKIPE T3 ;FOUND THE END YET? AOJA T4,PRITS1 ;NO LOAD T2,TKNAM,(Q2) ;YES, NOW GET TASK NAME HRLI T2,(POINT 7,0) PRITS5: ILDB T3,T2 ;GET NEXT CHAR AOS T4 ;COUNT IT JUMPN T3,PRITS5 LOAD T2,TKPRJ,(Q2) ;NOW PRINT THE NAME LOAD T2,PJNAM,(T2) HRLI T2,(POINT 7,0) SETZ T3, SOUT ;PROJECT NAME MOVEI T2,"/" BOUT ; "/" LOAD T2,TKNAM,(Q2) HRLI T2,(POINT 7,0) SOUT ;TASK NAME SUBI T4,^D20 ;NOW FILL WITH SPACES MOVNS T4 JUMPG T4,PRITS2 ;UNLESS TOO LONG MOVEI T2,15 ;THEN PUT IN A CRLF BOUT MOVEI T2,12 BOUT ;.. ;.. MOVEI T4,^D19 PRITS2: MOVEI T2," " ;PAD WITH SPACES BOUT SOJG T4,PRITS2 ;LOOP BACK TILL PADDING IS DONE LOAD T2,TKALN,(Q2) ;GET LENGTH SKIPN T2 ;IF SET YET LOAD T2,TKELN,(Q2) ;IF NOT, GET THE ESTIMATED LENGTH FIXR T2,T2 ;FIX THE NUMBER OF DAYS MOVE T3,[NO%LFL!5B17!^D10] NOUT JSP ERROR MOVEI T2," " BOUT LOAD T2,TKESD,(Q2) ;GET EARLIEST START DATE CALL PRIDAT MOVE T1,Q1 ;RESTORE JFN MOVEI T2," " BOUT LOAD T2,TKEFD,(Q2) ;GET THE EARLIEST FINISH DATE CALL PRIDAT MOVE T1,Q1 ;RESTORE JFN MOVEI T2," " BOUT REPEAT 0,< LOAD T2,TKLSD,(Q2) ;GET LATEST START DATE CALL PRIDAT MOVE T1,Q1 MOVEI T2," " BOUT LOAD T2,TKLFD,(Q2) ;GET THE LATEST FINISH DATE CALL PRIDAT MOVE T1,Q1 MOVEI T2," " BOUT LOAD T2,TKLSD,(Q2) ;NOW GET THE SLACK LOAD T1,TKESD,(Q2) CAMGE T2,T1 ;POSITIVE SLACK? EXCH T1,T2 ;NO CALL GETNWD ;GET NUMBER OF WORKING DAYS LOAD T2,TKLSD,(Q2) LOAD T3,TKESD,(Q2) CAMGE T2,T3 ;NEGATIVE SLACK? MOVNS T1 ;YES MOVE T2,T1 ;PRINT THE SLACK MOVE T1,Q1 MOVE T3,[NO%LFL!4B17!^D10] NOUT JSP ERROR MOVEI T2," " BOUT > ;.. ;.. LOAD P1,TKDVL,(Q2) ;GET POINTER TO DEVELOPER LIST LOAD T2,TKPRJ,(Q2) ;GET PROJECT ADR SKIPN P1 ;ANY DEVELOPERS ON TASK? LOAD P1,PJDVL,(T2) ;NO, GET THE PROJECT DEVELOPER LIST SKIPN P1 ;IS THERE A LIST? MOVE P1,DEVTBP ;NO, GET THE OVERALL LIST LOAD P2,TKDLP,(Q2) ;GET POINTER TO DEPENDENT LIST LOAD P3,TKBLP,(Q2) ;GET POINTER TO BLOCKED LIST PRITS3: MOVEI T4,SPACES ;PRINT DEVELOPER NAME IF ANY SKIPE P1 ;ANY THERE? LOAD T4,DVNAM,(P1) ;YES HRLI T4,(POINT 7,0) MOVEI T3,^D15 ;LENGTH OF NAME PRITS4: ILDB T2,T4 ;GET THE NEXT CHARACTER JUMPE T2,PRITS6 ;IF NULL, THEN GO PAD WITH SPACES BOUT ;OUTPUT THE CHAR SOJG T3,PRITS4 PRITS6: AOS T3 ;PUT A SPACE AT THE END MOVEI T2," " BOUT SOJG T3,.-1 ;PAD WITH SPACES SKIPE T2,P2 ;GET BLOCKING TASK (IF ANY) LOAD T2,DPBTK,(P2) CALL PRITNM ;GO PRINT THE NAME SKIPE T2,P3 ;GET THE BLOCKED TASK (IF ANY) LOAD T2,DPTKP,(P3) CALL PRITNM HRROI T2,[ASCIZ/ /] SETZ T3, SOUT SKIPE P1 ;STEP TO NEXT DEVELOPER LOAD P1,DVLNK,(P1) SKIPE P2 ;STEP TO NEXT BLOCKING TASK LOAD P2,DPDLP,(P2) SKIPE P3 ;STEP TO NEXT BLOCKED TASK LOAD P3,DPBLP,(P3) MOVE T2,P1 ;SEE IF THERE IS MORE TO BE DONE IOR T2,P2 IOR T2,P3 JUMPE T2,R ;IF NO MORE, THEN EXIT HRROI T2,SPACES MOVNI T3,^D45 ;SPACE OUT TO DEVELOPER LIST SOUT JRST PRITS3 ;LOOP BACK TIL LIST IS DONE ;OUTPUT SCHEDULE LSTSKD: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (OFI) ;MUST BE OUTPUT FILE HRRZ T1,(P1) ;ADDRESS OF JFN MOVE Q1,ANSWER(T1) ;GET THE JFN MOVE T1,Q1 ;COPY JFN MOVX T2,7B5+OF%WR ;ASCII OUTPUT OPENF WARN (,) SETZM LINCNT ;ZERO OUT LINE COUNTER CALL SCHCHK ;UPDATE ESTIMATED DATES IF NEDED MOVE T1,TSKPTR ;POINTER TO TASK LIST HRRZS TSKLST(T1) ;CLEAR FLAG AOBJN T1,.-1 ;IN ALL ENTRIES LSSKD1: SETZ T4, ;INIT INDEX HRLOI T3,377777 ;HIGHEST DATE SEEN MOVE Q2,TSKPTR ;POINTER TO TASK LIST LSSKD2: SKIPG T1,TSKLST(Q2) ;HAVE WE USED THIS ENTRY YET? JRST LSSKD3 ;YES. LOAD T2,TKESD,(T1) ;NO--GET START DATE CAMG T3,T2 ;FOUND A NEW LOW? JRST LSSKD3 ;NO--SKIP IT MOVE T3,T2 ;COPY DATE MOVE T4,Q2 ;COPY INDEX LSSKD3: AOBJN Q2,LSSKD2 ;LOOP OVER ALL TASKS JUMPE T4,LSSKD4 ;NONE FOUND--DONE HRROS TSKLST(T4) ;MARK THAT THIS ONE WAS PRINTED MOVE T1,Q1 ;COPY JFN HRRZ T2,TSKLST(T4) ;GET TASK BLOCK ADDRESS LOAD T3,TKEFD,(T2) ;GET COMPLETION DATE CAMLE T3,SKDTAD ;MUST BE IN THE FUTURE CALL PRISCH ;PRINT THE SCHEDULE MOVE T3,LINCNT ;GET THE LINE COUNTER CAIGE T3,^D50 ;TOO MANY? JRST LSSKD1 ;PRINT ALL TASKS MOVE T1,Q1 ;GET THE JFN MOVEI T2,"L"-100 ;FORM FEED BOUT ;SKIP TO NEW PAGE SETZM LINCNT ;RESET COUNTER JRST LSSKD1 ;LOOP BACK FOR ALL TASKS LSSKD4: MOVE T1,TSKPTR ;GET TASK POINTER HRRZS TSKLST(T1) ;CLEAR FLAG AOBJN T1,.-1 MOVE T1,Q1 CLOSF WARN (,) JRST LEVEL0 ;SUBROUTINE TO PRINT TASKS IS CALENDAR ORDER ; T1/ JFN ; T2/ TASK BLOCK ; PRISCH: SAVEP DMOVE P1,T1 ;COPY ARGUMENTS LOAD T2,TKESD,(T2) ;GET START DATE CALL PRIDAT ;PRINT IT TYPE P1,< TO > MOVE T1,P1 ;COPY JFN LOAD T2,TKEFD,(P2) ;GET END DATE CALL PRIDAT TYPE P1,< > DMOVE T1,P1 ;PUT ARGUMENTS BACK CALL PRITNM ;PRINT TASK NAME TYPE P1,<& PROJECT DESCRIPTION:&> MOVE T1,P1 ;COPY JFN LOAD T2,TKPRJ,(P2) ;GET PROJECT BLOCK ADDRESS LOAD T2,PJDSC,(T2) ;GET PROJECT DESCRIPTION CALL TYPDSC ;TYPE THE DESCRIPTION TYPE T1,<& TASK DESCRIPTION:&> LOAD T2,TKDSC,(P2) ;ADDRESS OF STRING CALL TYPDSC ;PRINT IT TYPE P1,<&&> ;ADD SOME WHITE SPACE MOVEI T1,6 ;PRINTED 6 LINES ADDM T1,LINCNT ;COUNT IT RET ;SUBROUTINE TO TYPE A TASK/PRODUCT DESCRIPTION ;CALL WITH: ; T1/ JFN ; T2/ STRING ADDRESS ; CALL TYPDSC ; TYPDSC: STKVAR HRLI T2,(POINT 7,0) ;MAKE BYTE POINTER MOVEM T2,STRPTR ;BYTE POINTER TO STRING TYDSC0: ILDB T2,STRPTR ;GET A BYTE JUMPE T2,R ;STOP ON NULL CAIG T2," " ;REAL TEXT? JRST TYDSC0 ;NO--STRIP IT OFF MOVEI T2," " ;PRINT A TAB BOUT LDB T2,STRPTR ;PRINT TEXT BOUT TYDSC1: ILDB T2,STRPTR ;GET THE NEXT BYTE JUMPE T2,TYDSC4 ;ADD CRLF AND QUIT ON NULL CAIGE T2," " ;REAL CHARACTER JRST TYDSC3 ;NO--SPECIAL HACK TYDSC2: BOUT ;TYPE IT JRST TYDSC1 ;LOOP BACK FOR MORE TYDSC3: TYPE T1,<&> ;ADD CRLF AOS LINCNT ;COUNT LINES JRST TYDSC0 ;STRIP JUNK TYDSC4: TYPE T1,<&> ;ADD CRLF AOS LINCNT ;COUNT LINES RET ;AND RETURN ;ROUTINE TO PRINT A TASK NAME ;ACCEPTS IN T1/ JFN ; T2/ 0 OR POINTER TO TASK BLOCK PRITNM: ASUBR JUMPE T2,PRITN1 ;IF 0, PRINT BLANKS LOAD T4,TKPRJ,(T2) ;GET POINTER TO PROJECT LOAD T4,PJNAM,(T4) ;GET POINTER TO PROJECT NAME HRLI T4,(POINT 7,0) MOVEI T3,^D32 PRITN2: ILDB T2,T4 ;GET THE NEXT CHAR JUMPE T2,PRITN3 ;IF DONE, GO PAD WITH SPACES BOUT ;OUTPUT THE NEXT CHAR SOJG T3,PRITN2 ;LOOP BACK TIL DONE JRST PRITN5 ;GO ADD FINAL SPACE PRITN3: MOVEI T2,"/" ;SLASH BETWEEN PROJECT AND TASK BOUT SOJLE T3,PRITN5 ;COUNT DOWN CHAR COUNT MOVE T4,PRITNT ;GET TASK BLOCK ADR AGAIN LOAD T4,TKNAM,(T4) ;GET POINTER TO TASK NAME HRLI T4,(POINT 7,0) PRITN4: ILDB T2,T4 ;GET NEXT CHAR OF TASK NAME JUMPE T2,PRITN5 ;IF DONE, GO PAD WITH SPACES BOUT SOJG T3,PRITN4 ;LOOP BACK THRU NAME PRITN5: MOVEI T2," " ;OUTPUT SPACES BOUT SOJGE T3,PRITN5 RET PRITN1: HRROI T2,SPACES ;PRINT SPACES MOVNI T3,^D33 SOUT RET ;ROUTINE TO PRINT OUT A DATE ;ACCEPTS IN T1/ JFN OR STRING POINTER ; T2/ DATE (GMT ADJUSTED TIME) PRIDAT: STKVAR JUMPE T2,PRIDT1 ;IF NO DATE, SAY "UNKNOWN" MOVEM T1,PRIDTJ ;SAVE THE JFN MOVX T4,IC%UTZ ;DONT PRINT THE TIME ODCNV ;NORMALIZE THE DATE SETZ T4, IDCNV JSP ERROR MOVE T1,PRIDTJ ;GET BACK THE JFN MOVE T3,[OT%NTM] ODTIM RET PRIDT1: HRROI T2,[ASCIZ/ UNKNOWN /] SETZ T3, SOUT RET ;ROUTINE TO STORE A BOX IN THE OUTPUT TABLES ;ACCEPTS IN T1/ INDEX INTO TSKLST ; T2/ COL # ; T3/ ROW # ; T4/ DATE ; CALL STOBOX ;RETURNS +1: ALWAYS, T1/ MAX COL USED ; T2/ MAX ROW USED PBXWID: SAVEPQ SETO P1, ;NO BOX CHAR JRST PBXWD1 BOXWID: SAVEPQ SETZ P1, ;PRINT THE BOX PBXWD1: MOVEI P5,1 ;ONLY WANT THE WIDTH OF THE BOX SETZB T2,T3 ;INIT OTHER PARAMETERS SETZ T4, JRST STOBX0 PSTOBX: SAVEPQ SETO P1, ;NO BOX CHAR JRST PSTOB1 STOBOX: SAVEPQ SETZ P1, ;DO BOX CHARS PSTOB1: MOVEI P5,0 ;STORE THE BOX STOBX0: STKVAR ,,,,,,,STOBXF,STOBXV,STOBXQ> MOVEM T4,STOBXQ ;SAVE THE DATE MOVEM P1,STOBXF ;SAVE BOX CHAR FLAG DMOVE Q2,T2 ;SAVE COL AND ROW MOVE Q1,TSKLST(T1) ;GET TASK ADR LOAD T3,TKFLG,(Q1) ;GET FLAGS MOVEI T2,"#" ;GET CRITICAL PATH BOX CHARACTER TXNN T3,TK%CP ;IS THIS TASK ON THE CRITICAL PATH? MOVEI T2,"%" ;NO, USE A DIFERENT CHAR LOAD T3,TKAFD,(Q1) ;GET ACTUAL FINISH DATE JUMPE T3,BOXWD0 ;IF NOT SET, THEN NOT DONE CAML T4,TSKFDL(T1) ;IS PROJECT ALREADY DONE? CAMLE T3,T4 ;ALREADY PAST COMPLETION DATE? SKIPA ;NO, NOT COMPLETE MOVEI T2,"*" ;YES, USE DIFFERENT CHAR BOXWD0: SKIPE STOBXF ;PLOTTING? MOVEI T2,"\" ;DO NOT PUT OUT BOX CHARS LOAD T3,TKFLG,(Q1) ;GET FLAGS AGAIN TXNE T3,TK%CP ;ON CRITICAL PATH? SKIPN STOBXF ;AND DRAWING BOXES? SKIPA ;NO MOVEI T2,"+" ;YES, GET CRITICAL PATH CHARACTER MOVEM T2,STOBXA ;SAVE BOX CHAR MOVEM T1,STOBXI ;SAVE INDEX CALL CHKDAT ;SEE IF THIS IS A RESONABLE DATE JRST BOXWD7 ;YES MOVEI T1,"?" ;NO, MARK THE BOX A QUESTIONABLE LOAD T3,TKAFD,(Q1) ;GET ACTUAL FINISH DATE JUMPE T3,BOXWD6 ;NOT DONE, SET "?" MOVE T2,STOBXI ;GET INDEX MOVE T4,STOBXQ ;GET DATE CAML T4,TSKFDL(T2) ;ALREADY DONE? CAMLE T3,T4 ;AND PAST COMPLETION DATE BOXWD6: MOVEM T1,STOBXA ;STORE THE NEW CHARACTER BOXWD7: MOVEI T1,BOXLEN ;MINIMUM BOX SIZE MOVEM T1,STOBXC LOAD T1,TKPRJ,(Q1) ;GET PROJECT BLOCK LOAD T1,PJNAM,(T1) ;GET ADR OF PROJ NAME MOVEI T2,STOBXP ;COPY NAME TO STRING AREA CALL BLDBNM CAMLE T1,STOBXC ;NEW COL MAX? MOVEM T1,STOBXC ;YES LOAD T1,TKNAM,(Q1) ;COPY TASK NAME STRING MOVEI T2,STOBXT CALL BLDBNM CAMLE T1,STOBXC ;NEW MAX COL? MOVEM T1,STOBXC ;YES MOVE T1,Q1 ;GET TASK ADR MOVEI T2,STOBXD CALL BLDBDT ;BUILD THE DEPENDENCY LIST SKIPE STOBXF ;PLOTTING SETZB T1,STOBXD ;YES, NO DEPENDENCY LINE CAMLE T1,STOBXC ;NEW MAX COL? MOVEM T1,STOBXC ;YES MOVE T1,Q1 ;NOW BUILD THE BLOCKED TASK LIST MOVEI T2,STOBXB CALL BLDBBT SKIPE STOBXF ;PLOTTING? SETZB T1,STOBXB ;YES, NO DEPENDENCY LINE CAMLE T1,STOBXC ;NEW MAX COL? MOVEM T1,STOBXC ;YES MOVE T1,Q1 ;GET TASK ADR HRROI T2,STOBXN ;GET STRING ADR FOR NAMES CALL BLDNST ;BUILD THE NAME STRING CAMLE T1,STOBXC ;NEW MAXIMUM? MOVEM T1,STOBXC ;YES MOVE T1,Q1 ;GET THE TASK ADR CALL GETPRF ;GET THE PREFERENCE VALUE MOVEM T1,STOBXV ;SAVE THE PREFERENCE VALUE HRROI T1,STOBXL ;GET THE LENGTH OF THE TASK SKIPE STOBXF ;PLOTTING? JRST BOXWD2 ;YES, DONT PUT IN TASK NUMBER MOVE T2,STOBXI ;GET INDEX OF TASK MOVEI T3,^D10 ;OUTPUT IT NOUT JSP ERROR MOVEI T2," " ;END WITH A SPACE BOUT BOXWD2: LOAD T2,TKALN,(Q1) ;GET THE ACTUAL LENGTH SKIPN T2 ;SET? LOAD T2,TKELN,(Q1) ;NO, USE THE ESTIMATED LENGTH SETZ T3, FLOUT JSP ERROR MOVEI T2,"d" ;END WITH "D" FOR DAYS IDPB T2,T1 SKIPN STOBXV ;IS THERE A PREFERENCE VALUE SET? JRST BOXWD5 ;NO HRROI T2,[ASCIZ/ PV=/] SETZ T3, SOUT MOVE T2,STOBXV ;GET THE PREFERENCE VALUE SETZ T3, FLOUT ;OUTPUT THE PREFERENCE VALUE JSP ERROR BOXWD5: LOAD T4,TKPL,(Q1) ;GET POINTER TO PATH LIST JUMPE T4,BOXWD3 ;IF ANY HRLI T4,(POINT 7,0) ILDB T3,T4 ;IS THERE ANY LIST? JUMPE T3,BOXWD3 ;... HRROI T2,[ASCIZ/ CP=/] SETZ T3, SOUT LOAD T2,TKPL,(Q1) ;GET PATH LIST HRLI T2,(POINT 7,0) SOUT BOXWD3: LOAD T3,TKSLK,(Q1) ;GET THE SLACK CAMN T3,[NOSLAK] ;ANY SET? JRST BOXWD4 ;NO HRROI T2,[ASCIZ/ SLK=/] SETZ T3, SOUT LOAD T2,TKSLK,(Q1) ;GET SLACK AGAIN MOVEI T3,^D10 NOUT ;OUTPUT IT AS DECIMAL NUMBER JSP ERROR BOXWD4: MOVEI T2,0 ;END WITH A NUL IDPB T2,T1 HRROI T1,STOBXL ;GET LENGTH OF STRING CALL GETCHC CAMLE T1,STOBXC ;NEW MAX? MOVEM T1,STOBXC ;YES, REMEMBER IT JUMPN P5,BOXWD1 ;NOW HAVE WIDTH IF THATS ALL THAT IS WANTED MOVEI T1,STOBXD ;NOW START THE BOX HRLZ T2,Q2 ;COL NUMBER HRRI T2,0(Q3) ;ROW MOVE T3,STOBXC ;BOX WIDTH MOVE T4,STOBXA ;BOX CHAR CALL STOBX1 ;OUTPUT THE DEPENDENCY LINE HRLZ T2,Q2 ;COL HRRI T2,1(Q3) ;ROW MOVE T3,STOBXC ;WIDTH MOVE T4,STOBXA ;BOX CHAR CALL STOBX2 ;PRINT TOP OF BOX MOVEI T1,STOBXL ;OUTPUT THE TASK NUMBER HRLZ T2,Q2 ;COL HRRI T2,2(Q3) ;ROW MOVE T3,STOBXC ;WIDTH MOVE T4,STOBXA ;BOX CHAR CALL STOBX3 MOVEI T1,STOBXP ;PROJECT NAME HRLZ T2,Q2 ;COL HRRI T2,3(Q3) ;ROW MOVE T3,STOBXC ;WIDTH MOVE T4,STOBXA ;BOX CHAR CALL STOBX3 MOVEI T1,STOBXT ;TASK NAME HRLZ T2,Q2 HRRI T2,4(Q3) MOVE T3,STOBXC MOVE T4,STOBXA CALL STOBX3 MOVE T1,STOBXI ;GET START DATE MOVE T2,TSKSDL(T1) HRROI T1,STOBXS CALL PRIDAT ;GET DATE INTO STOBXS MOVEI T1,STOBXS ;STORE START DATE IN BOX HRLZ T2,Q2 ;COL HRRI T2,5(Q3) ;ROW MOVE T4,STOBXA ;BOX CHAR LOAD T3,TKASD,(Q1) ;HAS THIS TASK STARTED YET? SKIPE T3 HRLI T4,"*" ;YES, FLAG IT MOVE T3,STOBXC ;WIDTH CALL STOBX3 MOVE T1,STOBXI ;GET FINISH DATE MOVE T2,TSKFDL(T1) HRROI T1,STOBXS CALL PRIDAT MOVEI T1,STOBXS ;OUTPUT FINISH DATE HRLZ T2,Q2 HRRI T2,6(Q3) MOVE T3,STOBXC MOVE T4,STOBXA CALL STOBX3 MOVEI T1,STOBXN ;PRINT THE NAMES HRLZ T2,Q2 ;COL HRRI T2,7(Q3) ;ROW MOVE T3,STOBXC MOVE T4,STOBXA CALL STOBX3 HRLZ T2,Q2 ;NOW DO CLOSING BOX LINE HRRI T2,10(Q3) MOVE T3,STOBXC MOVE T4,STOBXA CALL STOBX2 ;OUTPUT BOX LINE MOVEI T1,STOBXB ;GET LIST OF BLOCKED TASKS HRLZ T2,Q2 HRRI T2,11(Q3) MOVE T3,STOBXC MOVE T4,STOBXA CALL STOBX1 ;OUTPUT BLOCKED TASKS BOXWD1: MOVE T1,Q2 ;GET MAX COL USED ADD T1,STOBXC ;ADD IN THE WIDTH ADDI T1,8 ;PLUS THE OVERHEAD MOVE T2,Q3 ;GET THE ROW ADDI T2,BOXLEN-1 ;PLUS THE LENGTH OF A BOX RET ;ROUTINE TO STORE THE DEPENDENCY LINE ;ACCEPTS IN T1/ STRING ADR ; T2/ COL,,ROW ; T3/ WIDTH ; T4/ BOX CHAR STOBX1: SAVEQ STKVAR <> TRUNC T3,MAXLEN,DEPENDENCY,STOBX1 HRLI T1,(POINT 7,0) DMOVE Q2,T2 ;SAVE ARGS MOVEI T2,STOB1S ;GET POINTER TO SCRATCH STRING HRLI T2,(POINT 7,0) MOVEI T3," " IDPB T3,T2 ;SPACE IDPB T3,T2 ;SPACE IDPB T3,T2 ;SPACE IDPB T3,T2 ;SPACE STOB11: ILDB T4,T1 ;GET NEXT CHAR JUMPE T4,STOB12 ;NULL? IDPB T4,T2 ;NO, STORE IT SOJG Q3,STOB11 ;LOOP BACK FOR THE REST OF THE CHARS STOB12: IDPB T3,T2 ;END WITH SPACES SOJGE Q3,STOB12 IDPB T3,T2 IDPB T3,T2 IDPB T3,T2 SETZ T3, IDPB T3,T2 HLRZ T1,Q2 ;GET COL HRRZ T2,Q2 ;AND ROW HRROI T3,STOB1S ;AND STRING POINTER CALL STOSTR RET ;DONE ;ROUTINE TO STORE THE BOX LINE ;ACCEPTS IN T2/ COL,,ROW ; T3/ WIDTH ; T4/ BOX CHAR STOBX2: SAVEQ TRUNC T3,MAXLEN,,STOBX2 DMOVE Q2,T2 ;SAVE THE ARGS STKVAR <> MOVEI T1,STOB2S ;GET ADR OF SCRATCH STRING HRLI T1,(POINT 7,0) ADDI Q3,4 ;FINAL WIDTH MOVEI T2," " IDPB T2,T1 IDPB T2,T1 STOB21: IDPB T4,T1 ;STORE BOX CHAR SOJG Q3,STOB21 ;FOR FULL WIDTH IDPB T2,T1 ;SPACE IDPB T2,T1 ;SPACE SETZ T2, IDPB T2,T1 ;NULL HLRZ T1,Q2 ;COL HRRZ T2,Q2 ;ROW HRROI T3,STOB2S ;STRING CALL STOSTR RET ;DONE ;ROUTINE TO OUTPUT AN INNER LINE OF THE BOX ;ACCEPTS IN T1/ STRING ADDRESS ; T2/ COL,,ROW ; T3/ WIDTH ; T4/ FLAG CHAR ,, BOX CHAR STOBX3: SAVEP STKVAR <> TRUNC T3,MAXLEN,,STOBX3 HRLI T1,(POINT 7,0) MOVE P1,T1 ;SAVE BYTE POINTER HLRZ P2,T2 ;GET COL HRRZ P3,T2 ;GET ROW DMOVE P4,T3 ;GET WIDTH AND BOX CHAR MOVEI T1,STOB3S ;BUILD THE FULL STRING HRLI T1,(POINT 7,0) MOVEI T2," " IDPB T2,T1 ; * STRING * IDPB T2,T1 IDPB P5,T1 HLRZ T2,P5 ;GET FLAG CHARACTER SKIPN T2 ;ANY THERE MOVEI T2," " ;NO, USE A SPACE IDPB T2,T1 MOVEI T2," " ;FINISH WITH SPACES STOB31: ILDB T3,P1 ;NOW OUTPUT THE STRING JUMPE T3,STOB32 ;NULL? IDPB T3,T1 ;NO, STOR THE CHAR SOJG P4,STOB31 ;LOOP BACK TIL STRING DONE STOB32: IDPB T2,T1 ;FOLLOWED BY A SPACE SOJGE P4,STOB32 ;PAD WITH SPACES IDPB P5,T1 ;END OF BOX IDPB T2,T1 ;SPACE IDPB T2,T1 ;SPACE SETZ T2, IDPB T2,T1 ;NULL MOVE T1,P2 ;COL MOVE T2,P3 ;ROW HRROI T3,STOB3S ;STRING CALL STOSTR ;STORE THE STRING RET ;DONE ;ROUTINE TO COUNT CHARACTERS IN A STRING ;ACCEPTS IN T1/ STRING POINTER GETCHC: TLC T1,-1 ;STRING POINTER? TLCN T1,-1 HRLI T1,(POINT 7,0) SETZ T4, ;INIT COUNT GETCH1: ILDB T2,T1 ;GET NEXT CHAR SKIPE T2 AOJA T4,GETCH1 ;COUNT UP THE CHAR MOVE T1,T4 ;RETURN THE ANSWER RET ;ROUTINE TO BUILD A BOX NAME LINE ;ACCEPTS IN T1/ NAME STRING ADR ; T2/ ADR OF DESTINATION STRING ;RETURNS +1: ALWAYS, T1/ LENGTH OF STRING BLDBNM: HRLI T2,(POINT 7,0) ;SET UP DESTINATION BYTE POINTER HRLI T1,(POINT 7,0) ;SET UP SOURCE BYTE POINTER SETZ T4, ;INIT CHAR COUNT BLDBN1: ILDB T3,T1 ;GET NEXT CHAR IDPB T3,T2 ;PUT IN THE OUTPUT STRING TRUNC T4,MAXLEN,NAME,BLDBNM,BLDBN2 SKIPE T3 ;NULL? AOJA T4,BLDBN1 ;NO, LOOP BACK BLDBN2: MOVE T1,T4 ;GET CHAR COUNT RET ;DONE ;ROUTINE TO BUILD A LIST OF NAMES ;ACCEPTS IN T1/ TASK ADR ; T2/ STRING POINTER ;RETURNS +1: T1/ NUMBER OF CHARS IN STRING BLDNST: SAVEPQ STKVAR TLC T2,-1 ;GET A BYTE POINTER TLCN T2,-1 HRLI T2,(POINT 7,0) DMOVE P1,T1 ;SAVE THE ARGS SETZ T3, ;STORE A NULL AT END OF STRING IDPB T3,T2 ;IN CASE WE EXIT EARLY MOVEM P2,BLDNSP ;SAVE THE INITIAL STRING POINTER SETZM (T2) ;INIT FIRST WORD TO 0 HRLI T2,(POINT 7,0) ;SET UP STRING POINTER MOVE Q1,T1 ;SAVE TASK ADR HLRZ Q2,DEVTAB ;BUILD POINTER TO DEVTAB MOVNS Q2 HRLZS Q2 SETO Q3, ;INIT THE CHAR COUNT BLDNS1: HRRZ P3,DEVTAB+1(Q2) ;GET NEXT DEVELOPER LIST JUMPE P3,BLDNS4 ;IF NONE, SKIP IT SETZ Q1, ;INIT DAY COUNT BLDNS2: LOAD T1,SCHTK,(P3) ;GET TASK ADR CAME T1,P1 ;FOUND A MATCH? JRST BLDNS3 ;NO LOAD T1,SCHSD,(P3) ;GET THE START DATE LOAD T2,SCHFD,(P3) ;GET THE END DATE CALL GETNWD ;GET NUMBER OF WORKING DAYS LOAD T2,SCHRT,(P3) ;GET THE RATE FLTR T1,T1 ;GET DAYS FMPR T1,T2 ;GET THE NUMBER OF DAYS SPENT FADR Q1,T1 ;ADD IT TO THE TOTAL BLDNS3: LOAD P3,SCHLN,(P3) ;STEP TO THE NEXT TASK IN LIST JUMPN P3,BLDNS2 ;LOOP BACK TIL DONE JUMPE Q1,BLDNS4 ;IF NO DAYS, SKIP THIS TASK MOVEI T1,"," ;ADD A COMMA TO NAME AOSE Q3 ;UNLESS THIS IS THE FIRST TIME IDPB T1,P2 ;STORE THE COMMA HLRZ T1,DEVTAB+1(Q2) ;GET POINTER TO NAME STRING HRLI T1,(POINT 7,0) BLDNS5: ILDB T3,T1 ;GET NEXT CHAR IN NAME JUMPE T3,BLDNS6 ;DONE? IDPB T3,P2 ;NO, STORE THE CHAR AOJA Q3,BLDNS5 ;LOOP BACK TIL DONE BLDNS6: MOVEI T2,"(" ;NOW PUT IN THE DAYS SPENT IDPB T2,P2 MOVE T1,P2 ;GET STRING POINTER MOVE T2,Q1 ;GET NUMBER OF DAYS MOVE T3,[FL%ONE!FL%PNT!FL%OVL] MOVEI T4,1 ;CALCULATE THE ROUNDING CAML T2,[1.0] AOS T4 CAML T2,[10.0] AOS T4 CAML T2,[100.0] AOS T4 CAML T2,[1000.0] AOS T4 CAML T2,[10000.0] AOS T4 CAML T2,[100000.0] AOS T4 HRLZS T4 TDO T3,T4 ;SET WHERE TO ROUND AT FLOUT ;OUTPUT IT MOVE T1,P2 MOVE P2,T1 ;PUT BACK THE STRING POINTER MOVEI T2,")" IDPB T2,P2 ;CLOSE OUT THE DAYS MOVEI T3,0 ;END WITH A NULL MOVE T4,P2 IDPB T3,T4 BLDNS4: MOVE T1,BLDNSP ;GET STRING POINTER CALL CNTSTC ;COUNT THE CHARACTERS IN THE STRING TRUNC T1,MAXLEN,,BLDNST,R AOBJN Q2,BLDNS1 ;STEP TO NEXT DEVELOPER IN DEVTAB RET ;ROUTINE TO BUILD THE DEPENDENCY LIST ;ACCEPTS IN T1/ TASK ADR ; T2/ STRING ADR FOR OUTPUT ;RETURNS +1: ALWAYS, T1/ LENGTH OF STRING BLDBBT: TDZA T4,T4 ;BUILD BLOCKED LIST BLDBDT: MOVEI T4,1 ;BUILD BLOCKING LIST SAVEPQ MOVE P1,T4 ;SAVE THE INDEX HRLI T2,(POINT 7,0) ;SET UP THE DESTINATION BYTE POINTER MOVE Q2,T2 ;SAVE THE BYTE POINTER MOVE Q3,Q2 ;SAVE A COPY OF THE ORIGINAL BYTE PNTR XCT [ LOAD Q1,TKBLP,(T1) LOAD Q1,TKDLP,(T1)](P1) JUMPE Q1,BLDBD2 ;IF NO DEPENDENCY LIST, THEN DONE BLDBD1: XCT [ LOAD T1,DPTKP,(Q1) LOAD T1,DPBTK,(Q1)](P1) LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX MOVE T2,T1 ;NOW ADD THIS NUMBER TO THE LIST MOVE T1,Q2 ;GET THE STRING POITER MOVEI T3,^D10 ;DECIMAL NUMBER NOUT JSP ERROR MOVE Q2,T1 ;SAVE THE UPDATED STRING POINTER XCT [ LOAD Q1,DPBLP,(Q1) LOAD Q1,DPDLP,(Q1)](P1) JUMPE Q1,BLDBD2 ;ANY MORE TASKS ON LIST? MOVEI T1,"," ;YES, PUT A COMMA BETWEEN NUMBERS IDPB T1,Q2 MOVEI T1," " ;AND A SPACE IDPB T1,Q2 JRST BLDBD1 ;LOOP BACK FOR REST OF TASKS ON LIST BLDBD2: SETZ T1, ;COUNT UP THE CHARACTERS BLDBD3: CAMN Q2,Q3 ;REACHED THE END OF THE STRING? JRST BLDBD4 ;YES IBP Q3 ;STEP TO NEXT CHAR AOJA T1,BLDBD3 ;LOOP BACK TILL END IS FOUND BLDBD4: MOVEI T2,0 ;END WITH A NULL IDPB T2,Q2 RET ;DONE ;ROUTINE TO CHECK FOR A QUESTIONABLE TASK ;ACCEPTS IN T1/ TASK INDEX ;RETURNS +1: DATE IS OK ; +2: DATE IS QUESTIONABLE CHKDAT: SAVEQ HRRZ Q1,TSKLST(T1) ;GET THE ADR OF THE TASK BLOCK LOAD Q3,TKXSD,(Q1) ;GET THE START DATE OF THIS TASK LOAD T1,TKESD,(Q1) ;GET EARLIEST START DATE CAMGE Q3,T1 ;SEE WHICH IS LATER MOVE Q3,T1 LOAD T1,TKASD,(Q1) ;GET ACTUAL START SKIPE T1 ;SET YET? MOVE Q3,T1 ;YES, USE IT LOAD Q2,TKDLP,(Q1) ;GET POINTER TO BLOCKING LIST JUMPE Q2,R ;IF NONE, THEN DONE CHKDA1: LOAD T1,DPBTK,(Q2) ;GET THE BLOCKING TASK LOAD T2,TKXCD,(T1) ;SEE WHEN IT FINISHES LOAD T3,TKLFD,(T1) ;GET LATEST FINISH DATE CAMGE T2,T3 ;GET THE LATEST MOVE T2,T3 LOAD T3,TKAFD,(T1) ;GET THE ACTUAL FINISH DATE SKIPE T3 ;IF ANY MOVE T2,T3 CAMLE T2,Q3 ;IS THERE AN OVERLAP? RETSKP ;YES, QUESTINABLE DATE LOAD Q2,DPDLP,(Q2) ;STEP TO NEXT TASK IN THE LIST JUMPN Q2,CHKDA1 ;IF ANY MORE, LOOP BACK RET ;IF NOT, THEN DONE ;ROUTINE TO SORT THE AVLTSK LIST BY FINISH DATE BLDSPA: SAVEQ MOVN Q1,AVLCNT ;SET UP AOBJN POINTER HRLZS Q1 SETZ Q2, ;INIT COL NUMBER MOVE T1,Q1 ;GET AOBJN POINTER HRROS AVLTSK(T1) ;INIT THE TABLE AOBJN T1,.-1 BLDSP1: HRLOI T3,377777 ;GET THE LARGEST DATE MOVE T2,Q1 ;GET AOBJN POINTER BLDSP2: SKIPL T1,AVLTSK(T2) ;THIS BEEN LOOKED AT YET? JRST BLDSP3 ;YES CAMLE T3,TSKFDL(T1) ;NO, IS THIS A NEW LOW FINISH DATE MOVE T3,TSKFDL(T1) ;YES BLDSP3: AOBJN T2,BLDSP2 ;LOOP BACK FOR ALL TASKS CAML T3,[377777,,777777] ;FOUND ANY? RET ;NO, THEN ALL DONE MOVE T2,Q1 ;SET UP POINTER AGAIN BLDSP4: SKIPL T1,AVLTSK(T2) ;LOOKED AT THIS ONE YET? JRST BLDSP5 ;YES, SKIP IT CAML T3,TSKFDL(T1) ;FOUND ONE OF THE ONES TO SCHEDULE? HRLM Q2,AVLTSK(T2) ;YES, STORE THE ROW OFFSET BLDSP5: AOBJN T2,BLDSP4 ;LOOP BACK FOR ALL TASKS AOJA Q2,BLDSP1 ;LOOP BACK TILL ALL TASKS ARE SCHEDULED ;SUBROUTINE TO PLACE PERT BOXES ON THE PERT CHART ;CALL WITH: ; CALL PLACE ;RETURNS +1 HAVING SET TSKPOS ; PLACE: SAVEPQ ;SAVE P AND Q REGS ;AC USAGE ; Q1/ LEVEL NUMBER ; Q2/ FLAG. 0 MEANS FORWARD SCAN, 1 MEANS BACKWARD ; Q3/ HIGHEST LEVEL SEEN IN FORWARD SCAN ; P1/ LOWEST LEVEL SEEN IN REVERSE SCAN ; P3/ FLAG. 0 MEANS ALLOW REORGANIZATION, 1 MEANS DON'T ; P4/ PASS COUNTER SETOB Q3,P1 ;INIT MAX LEVEL SEEN SO FAR SETO P4, ;SET PASS COUNT PLACE2: JUMPG P4,PLACE6 ;AFTER SEVERAL PASSES, THEN DONE MOVEI Q1,0 ;GET LEVEL TO START WITH SETZ Q2, ;START IN THE FORWARD DIRECTION PLACE3: SETZM AVLCNT ;BUILD AVLTSK TABLE MOVE T1,TSKPTR ;SCAN TASK TABLES FOR THIS LEVEL PLACE4: SKIPE TSKINV(T1) JRST PLACE5 HLRZ T2,TSKSKD(T1) ;GET LEVEL CAME T2,Q1 ;THE ONE WE WANT? JRST PLACE5 ;NO AOS T2,AVLCNT ;COUNT UP AVLCNT HRRZM T1,AVLTSK-1(T2) ;STORE TASK INDEX PLACE5: AOBJN T1,PLACE4 SKIPG AVLCNT ;ANY FOUND? JRST [ SETOB Q3,P1 ;DO FINAL FORWARD SCAN AOJA P4,PLACE2] MOVE T1,Q2 ;GET SCAN DIRECTION SETZB T2,P3 ;ALLOW REORGANIZATION SKIPN Q2 ;GOING FORWARD? CAMLE Q1,Q3 ;YES, AT NEW HIGH? SKIPA ;YES, OK TO REORGANIZE SETOB T2,P3 ;NO, DO NOT REORGANIZE BOXES SKIPE Q2 ;REVERSE? CAMGE Q1,P1 ;YES, AT NEW LOW? SKIPA ;YES, CAN REORGANIZE SETOB T2,P3 ;NO, DO NOT REORGANIZE THE BOXES SKIPL P4 ;IN FIRST PASS? SETOB T2,P3 ;NO, DO NOT ALLOW REORGANIZATION CALL SRTAVL ;GO SORT THE LIST ; .. ; .. CALL SETPOS ;SET UP TSKPOS FOR THESE TASKS CALL [ JUMPLE P1,R ;IF MIN = 0, THEN GO UP TO NEXT LEVEL JUMPE P3,[TRC Q2,1 ;IF REORG ALLOWED, THEN CHANGE Q2 RET] SKIPN Q2 ;FORWARD? CAMGE Q1,Q3 ;YES, AT HIGH POINT? RET ;NO, GO TO HIGH POINT BEFORE SWITCHING MOVEI Q2,1 ;GO IN REVERSE DIRECTION CALL FIXPOS ;GET OUT WHITE SPACE RET] CAMGE Q1,P1 ;NEW LOW? MOVE P1,Q1 ;YES, REMEMBER IT SKIPE Q2 ;GOING IN REVERSE? SOSA Q1 ;YES, GO UP ONE LEVEL AOS Q1 ;NO, GO DOWN A LEVEL JUMPL Q1,PLACE2 ;IF AT 0, THEN TURN AROUND JUMPN Q2,PLACE3 ;IF IN REVERSE, CONTINUE ON DOWN CAMG Q1,Q3 ;NEW HIGH? JRST PLACE3 ;NO MOVE Q3,Q1 ;YES, REMEMBER IT MOVE P1,Q1 ;START WITH A NEW MINIMUM JRST PLACE3 ;GO CONTINUE ON PLACE6: CALL FIXPOS ;SQUEEZE OUT WHITE SPACE FROM PERT CHART RET ;ALL DONE ;SUBROUTINE TO PLACE PERT BOXES ON THE PERT CHART AT MAXIMUM DENSITY ;CALL WITH: ; CALL HDPLC ;RETURNS +1 HAVING SET TSKPOS ; HDPLC: SAVEPQ ;SAVE P AND Q REGS CALL GETPAS ;GET NUMBER OF PASSES CAIGE T1,2 ;AT LEAST 2? MOVEI T1,2 ;FORCE 2 MOVE P3,T1 ;SAVE FOR LATER CALL ADJLVL ;ADJUST LEVEL NUMBERS ;AC USAGE ; Q1/ LEVEL NUMBER ; Q2/ FLAG. 1 MEANS FORWARD SCAN, -1 MEANS BACKWARD ; Q3/ PREVIOUS VALUE OF P2 ; P1/ PASS COUNTER ; P2/ GLOBAL SCORE ; P3/ NUMBER OF PASSES HRLOI Q3,377777 ;MAKE OLD VALUE HUGE MOVEI P1,1 ;FIRST PASS MOVEI Q2,1 ;START GOING FORWARD MOVEI Q1,0 ;GET LEVEL TO START WITH HDPLC2: MOVEI P2,0 ;ZERO SCORE HDPLC3: SETZM AVLCNT ;BUILD AVLTSK TABLE MOVE T1,TSKPTR ;SCAN TASK TABLES FOR THIS LEVEL HDPLC4: SKIPE TSKINV(T1) JRST HDPLC5 HLRZ T2,TSKSKD(T1) ;GET LEVEL CAME T2,Q1 ;THE ONE WE WANT? JRST HDPLC5 ;NO AOS T2,AVLCNT ;COUNT UP AVLCNT HRRZM T1,AVLTSK-1(T2) ;STORE TASK INDEX HDPLC5: AOBJN T1,HDPLC4 SKIPG AVLCNT ;ANY FOUND? JRST HDPLC6 ;NO--THINK ABOUT TURNING AROUND MOVE T1,[EXP 1,0,0](Q2) ;GET DIRECTION MOVEI T2,0 ;ALLOW MIXING CALL SRTAVL ;GO SORT THE LIST CALL SETPOS ;SET UP TSKPOS FOR THESE TASKS JFCL CALL ASCORE ;SCORE ENTIRE AVLTSK LIST ADD P2,T1 ;TOTAL UP SCORE ADD Q1,Q2 ;STEP TO NEXT LEVEL JUMPGE Q1,HDPLC3 ;KEEP GOING HDPLC6: TMSG <[PLACEMENT PASS > MOVEI T1,.PRIOU MOVE T2,P1 MOVEI T3,^D10 NOUT ERJMP . TMSG < WITH SCORE > MOVEI T1,.PRIOU MOVE T2,P2 MOVEI T3,^D10 NOUT ERJMP . TMSG <] > MOVNS Q2 ;CHANGE DIRECTION ADD Q1,Q2 ;STEP BACK INTO PERT CAMG Q3,P2 ;DID THINGS GET BETTER? JRST HDPLC7 ;NO--TRY ANOTHER PASS MOVE Q3,P2 ;SET NEW BEST SCORE MOVE T1,[TSKPOS,,TSKSVP] ;SAVE POSITIONS BLT T1,TSKSVP+MAXTSK-1 ; .. HDPLC7: CAMGE P1,P3 ;ENOUGH PASSES? AOJA P1,HDPLC2 ;KEEP LOOPING MOVE T1,[TSKSVP,,TSKPOS] BLT T1,TSKPOS+MAXTSK-1 ;PUT BACK BEST NUMBER CALL FIXPOS ;SQUEEZE OUT WHITE SPACE FROM PERT CHART RET ;ALL DONE ;ROUTINE TO SORT AVLTSK BY LEAST NUMBER OF CROSSED LINES ;ACCEPTS IN T1/ 0 = FORWARD SCAN, 1 = REVERSE SCAN ; T2/ 0 = ALLOW REORGANIZATION, -1 = DO NOT REORGANIZE SRTAVL: SAVEPQ DMOVE P1,T1 ;SAVE INDEX AND FLAG MOVN Q1,AVLCNT ;SET UP POINTER TO THE LIST HRLZS Q1 SRTAV1: SETZ Q2, ;INIT COL COUNTER MOVE P3,P1 ;SET UP INITIAL INDEX HRRZ T1,AVLTSK(Q1) ;GET TASK INDEX HRRZ T1,TSKLST(T1) ;GET TASK ADR XCT [ LOAD Q3,TKDLP,(T1) ;GET POINTER TO LIST LOAD Q3,TKBLP,(T1)](P3) SKIPN Q3 ;ANY TASKS? TRC P3,1 ;NO, TRY THE OTHER DIRECTION SKIPN Q3 ;ANY TASKS? XCT [ LOAD Q3,TKDLP,(T1) ;GET POINTER TO LIST LOAD Q3,TKBLP,(T1)](P3) JUMPE Q3,SRTAV5 ;IF NONE, THEN SKIP TO NEXT TASK SRTAV3: XCT [ LOAD T1,DPBTK,(Q3) ;GET THE ADR OF THE TASK LOAD T1,DPTKP,(Q3)](P3) LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX HLRE T2,TSKLST(T1) ;GET THE COLUMN LEVEL JUMPL T2,SRTAV4 ;UNLESS IT IS NOT SET YET MOVE T3,TSKWID(T1) ;GET THE WIDTH OF THE BOX LSH T3,-1 ;DIVIDE BY 2 ADD Q2,T3 ;ADD IN HALF THE WIDTH OF THE BOX ADD Q2,TSKPOS(T1) ;COUNT UP ITS POSITION ADD Q2,[1,,0] ;COUNT UP THE # OF ADDITIONS SRTAV4: XCT [ LOAD Q3,DPDLP,(Q3) ;STEP TO NEXT TASK IN THE LIST LOAD Q3,DPBLP,(Q3)](P3) JUMPN Q3,SRTAV3 ;ANY MORE? SRTAV5: HRRZ T1,Q2 ;GET THE SUM HLRZ T2,Q2 ;GET THE # OF ADDITIONS FLTR T1,T1 FLTR T2,T2 FDVR T1,T2 ;GET COL POSITION AVERAGE MOVE T3,AVLTSK(Q1) ;GET TASK INDEX SKIPN T1 ;ANYTHING THERE? FLTR T1,TSKPOS(T3) ;NO, GET FROM LAST PASS MOVEM T1,AVLSST(Q1) ;SAVE THE SUM AOBJN Q1,SRTAV1 ;LOOP BACK FOR ALL TASKS SKIPE PERTPA ;ADVANCED PLACER? RET ;YES--DO NOT SORT ;.. ;.. JUMPN P2,SRTA11 ;IF NO REORGANIZATION, GO SORT TSKPOS SRTAV6: MOVN Q1,AVLCNT ;SET UP TO SORT THE LIST HRLZS Q1 SETZ Q2, ;INIT THE COUNTER OF ITEMS SWITCHED SRTAV7: AOBJP Q1,SRTAV8 ;STEP TO NEXT TASK MOVE T1,AVLSST-1(Q1) ;GET PREVIOUS ITEM CAMG T1,AVLSST(Q1) ;IS PREVIOUS ONE GREATER THAN THIS ONE JRST SRTAV7 ;NO EXCH T1,AVLSST(Q1) ;YES, SWITCH THEM MOVEM T1,AVLSST-1(Q1) MOVE T1,AVLTSK-1(Q1) ;AND SWITCH AVLTSK LIST ALSO EXCH T1,AVLTSK(Q1) MOVEM T1,AVLTSK-1(Q1) AOJA Q2,SRTAV7 ;LOOP BACK SRTAV8: JUMPG Q2,SRTAV6 ;IF ANY WERE SWITCHED, LOOP BACK RET ;DONE SRTA11: MOVN Q1,AVLCNT ;SORT BY TSKPOS HRLZS Q1 SETZ Q2, ;INIT SWITCH COUNT SRTA12: AOBJP Q1,SRTA13 ;STEP TO NEXT TASK HRRZ T1,AVLTSK-1(Q1) ;GET TASK INDEX HRRZ T2,AVLTSK(Q1) ; OF FIRST AND SECOND TASKS MOVE T3,TSKPOS(T1) ;GET POSITION OF FIRST TASK CAMG T3,TSKPOS(T2) ;OUT OF ORDER? JRST SRTA12 ;NO MOVE T1,AVLSST-1(Q1) ;YES, SWITCH THE ORDER EXCH T1,AVLSST(Q1) MOVEM T1,AVLSST-1(Q1) MOVE T1,AVLTSK-1(Q1) ;SWITCH AVLSST AND AVLTSK EXCH T1,AVLTSK(Q1) MOVEM T1,AVLTSK-1(Q1) AOJA Q2,SRTA12 ;MARK THAT A SWITCH WAS MADE SRTA13: JUMPG Q2,SRTA11 ;LOOP BACK TILL NO MORE SWITCHING RET ;DONE ;ROUTINE TO SET THE POSITION FOR ALL TASKS IN AVLTSK LIST ;RETURNS +1: POSITION OF SOME TASK CHANGED ; +2: NO POSITIONS CHANGED SETPOS: SKIPE PERTPA ;DEFAULT PLACER? JRST ASPOS ;NO--CALL ADVANCED ROUTINE SAVEPQ SETZB P3,P4 ;INIT REGS MOVN Q1,AVLCNT ;SET UP POINTER TO THE LIST HRLZS Q1 SETPO1: MOVEI Q2,0 ;INIT WIDTH MOVE Q3,Q1 ;START SCAN HERE MOVEI P1,1 ;START WITH A COUNT OF ONE SETPO2: HRRZ T1,AVLTSK(Q3) ;GET THE TASK INDEX ADD Q2,TSKWID(T1) ;SUM THE WIDTHS MOVE T1,AVLSST(Q3) ;GET THE DESIRED POSITION AOBJP Q3,SETPO3 ;STEP TO NEXT TASK CAMN T1,AVLSST(Q3) ;SAME AS LAST ONE? AOJA P1,SETPO2 ;YES, LOOP BACK SETPO3: EXCH Q1,Q3 ;GET START OF SCAN AGAIN FLTR T2,Q2 ;GET WIDTH FDVR T2,[2.0] ;GET OFFSET FSBR T1,T2 ;GET START OF THIS BLOCK OF BOXES FIX T1,T1 ;GET THE COL # SKIPGE T1 ;NEGATIVE NUMBER? MOVEI T1,0 ;YES, MAKE IT BE 0 CAMG T1,P3 ;TOO LOW? MOVE T1,P3 ;YES, USE THE HIGHER POSITION SETPO4: HRRZ T2,AVLTSK(Q3) ;GET INDEX INTO TSKLST CAME T1,TSKPOS(T2) ;NOT MOVING? SETO P4, ;NO, MARK THAT IT MOVED MOVEM T1,TSKPOS(T2) ;SAVE THIS POSITION ADD T1,TSKWID(T2) ;STEP TO START OF NEXT BOX MOVE P3,T1 ;SAVE START OF NEXT FREE SPOT AOBJP Q3,SETPO5 ;DONE? CAME Q3,Q1 ;DONE? JRST SETPO4 ;DEFAULT PLACE ALWAYS GOES RIGHT JUMPL Q1,SETPO1 ;GO GET REST OF TASKS SETPO5: JUMPN P4,R ;ANY CHANGES? RETSKP ;NO ;ROUTINE TO SET THE POSITION FOR ALL TASKS IN AVLTSK LIST ;RETURNS +1: POSITION OF SOME TASK CHANGED ; +2: NO POSITIONS CHANGED ASPOS: SAVEPQ ;SAVE SOME AC'S MOVN Q1,AVLCNT ;POINTER TO AVLTSK HRLZ Q1,Q1 ;MAKE AOBJN FORMAT MOVEI Q2,0 ;CONFLICT GROUP NUMBER MOVEI P4,0 ;COUNT OF POSITIONS CHANGED ASPOS1: HRRZ T2,Q1 ;COPY INDEX CALL CMPPOS ;COMPUTE DESIRED POSITION CALL CHKOVL ;ANY OVERLAP? JRST [ HRROS T2,AVLTSK(T2) ;NO--FLAG CORRECTLY PLACED CAME T1,TSKPOS(T2) ;SAME PLACE? ADDI P4,1 ;NO--POSITION CHANGED MOVEM T1,TSKPOS(T2) ;STORE POSITION JRST ASPOS2] ;LOOK AT NEXT TASK MOVE T4,AVLTSK(T3) ;GET INDEX OF OVERLAPPING TASK HLLM T4,AVLTSK(T2) ;MAKE PART OF THAT GROUP JUMPG T4,ASPOS2 ;OK IF ALREADY SET HRLM Q2,AVLTSK(T3) ;START A NEW GROUP HRLM Q2,AVLTSK(T2) ; .. ADDI Q2,1 ;GET READY FOR NEXT GROUP ASPOS2: AOBJN Q1,ASPOS1 ;LOOP OVER ALL TASKS JUMPE Q2,[JUMPE P4,RSKP ;SKIP RETURN IF NOTHING HAPPENED RET] ;ALL TASK FIT WHERE THEY WANT TO GO MOVEI Q3,0 ;LEVEL TO COLLECT ASPOS3: MOVN Q1,AVLCNT ;LOOP OVER LIST AGAIN HRLZ Q1,Q1 MOVEI P1,0 ;COUNT OF MATCHES ASPOS4: HLRZ P2,AVLTSK(Q1) ;GET GROUP NUMBER CAMN P2,Q3 ;THE ONE WE WANT? JRST [ HRRZ T1,Q1 ;GET AVLTSK INDEX MOVEM T1,LVLTAB(P1) ;STORE IN TEMP AOJA P1,.+1] ;BUMP INDEX AND CONTINUE AOBJN Q1,ASPOS4 ;COLLECT ALL MATCHES MOVN T1,P1 ;STORE AOBJN POINTER TO GROUP HRLZM T1,LVLPTR ; .. CALL POSGRP ;SET POSITION FOR GROUP ADDI P4,1 ;SOMETHING MOVED ADDI Q3,1 ;BUMP POINTER CAME Q2,Q3 ;ALL DONE? JRST ASPOS3 ;NO--KEEP LOOKING JUMPE P4,RSKP ;NOTHING MOVED RET ;SOMETHING MOVED ;SUBROUTINE TO SET POSITIONS FOR A GROUP OF BOXES THAT ALL WANT TO GO ; IN THE SAME PLACE ;CALL: LVLPTR/ AOBJN POINTER TO LVLTAB ; LVLTAB/ LIST OF AVLTSK INDICES FOR TASKS TO PLACE ;RETURNS +1: SOME POSITION CHANGED ; +2: NOTHING HAPPENED ; POSGRP: SAVEPQ MOVEI P5,^D1000 ;LIMIT THE NUMBER OF TRIES ; (NOT REALLY NEEDED BUT...) MOVEI P4,0 ;NUMBER OF THINGS THAT MOVED MOVE P1,LVLPTR ;POINTER TO CONFLICT LIST CAMG P1,[-BESTN,,0] ;TOO MANY TO TRY ALL? CALLRET EXCGRP ;YES--TRY ALL POSSIBLE SWAPS CALL PRMINI ;INIT PERMUTATION TABLE HRLOI P1,377777 ;BEST SCORE YET PSGRP1: CALL PLCGRP ;PLACE THIS GROUP ADDI P4,1 ;SOMETHING MOVED CALL SCORE ;EVALUATE PLACEMENT CAMG P1,T1 ;BETTER PLACEMENT? JRST PSGRP3 ;NO--KEEP LOOKING MOVE P1,T1 ;REMEMBER THE NEW SCORE MOVE P2,[LVLTAB,,BEST] ;COPY THE LIST BLT P2,BEST+BESTN-1 ; .. PSGRP3: CALL PERM ;PREMUTE LVLTAB SOJG P5,PSGRP1 ;KEEP LOOKING MOVE P2,[BEST,,LVLTAB] ;COPY THE BEST BACK BLT P2,LVLTAB+BESTN-1 ; .. MOVE Q1,P4 ;COPY FLAG CALLRET EXCGRP ;TRY TO DO SOME SWAPS ;SUBROUTINE TO LOOP THROUGH ALL PERMUATIONS OF LVLTAB ;THIS ROUTINE USES LVLCNT AS A TEMP ;TO USE: ; CALL PRMINI ;INIT ALGORITHM ;THEN: ; CALL PERM ;SWAP 2 ELEMENTS ;RETURNS +1: NOT DONE YET ; +2: DONE ; ;SEE CACM ALGORITHM 115 BY H. F. TROTTER ; PRMINI: MOVSI T1,1 ;INIT DIRECTION TO 1 (FORWARD) MOVEM T1,LVLCNT ; AND POSITION TO ZERO MOVE T1,[LVLCNT,,LVLCNT+1] BLT T1,LVLCNT+BESTN-1 RET PERM: SETZB T1,T2 ;ZERO OUT ARGUMENTS FOR FIRST CALL PERM0: SAVEP ;RECURSIVE WORK SPACE DMOVE P1,T1 ;SAVE ARGUMENTS HLRE P5,LVLPTR ;NEGATIVE COUNT MOVM P5,P5 ;POSITIVE COUNT SUBI P5,1 ;MAXIMUM INDEX CAMLE P1,P5 ;ARGUMENT IN RANGE? RETSKP ;NO--ALL DONE HRRZ P3,LVLCNT(P1) ;GET LOCATION ELEMENT HLRE P4,LVLCNT(P1) ;GET DIRECTION MOVE T1,P5 ;UPPER LIMIT SUB T1,P1 ;ADJUST CAIE P4,1 ;GOING UP? MOVEI T1,0 ;NO--SET LOWER LIMIT CAMN T1,P3 ;UP AGAINST LIMIT? JRST PERM1 ;YES--GO DO SOMETHING ABOUT THAT MOVE T1,P3 ;UPDATE RELATIVE LIMIT ADD T1,P4 ;+/- 1 HRRM T1,LVLCNT(P1) ;STORE FOR NEXT CALL ADD P2,P3 ;MAKE ABSOLUTE LIMIT ADD P4,P2 ; .. MOVE T1,LVLTAB(P2) ;EXACHANGE TWO ELEMENTS EXCH T1,LVLTAB(P4) ; .. MOVEM T1,LVLTAB(P2) ; .. RET ;HERE IF WE HIT AN END PERM1: MOVN T1,P4 ;CHANGE DIRECTION HRLM T1,LVLCNT(P1) ; .. MOVE T2,P2 ;COPY OFFSET CAIN P4,1 ;GOING UP? AOS T2,P2 ;YES--BUMP OFFSET AOS T1,P1 ;BUMP INDEX CALL PERM0 ;TRY AGAIN RET ;KEEP GOING RETSKP ;STOP ;SUBROUTINE TO SET POSITIONS FOR A GROUP OF BOXES THAT ALL WANT TO GO ; IN THE SAME PLACE ;CALL: LVLPTR/ AOBJN POINTER TO LVLTAB ; LVLTAB/ LIST OF AVLTSK INDICES FOR TASKS TO PLACE ;RETURNS +1: SOME POSITION CHANGED ; +2: NOTHING HAPPENED ; EXCGRP: MOVEI P5,^D1000 ;LIMIT THE NUMBER OF TRIES MOVEI P4,0 ;NUMBER OF THINGS THAT MOVED CALL EXCINI ;INIT PERMUTATION TABLE CALL PLCGRP ;POSITION FIRST TRY ADDI P4,1 ;SOMETHING CHANGED CALL SCORE ;EVALUATE PLACEMENT MOVE P1,T1 ;ASSUME IT IS THE BEST EXGRP1: CALL DOEXCH ;SWAP TWO BOXES SETOM P5 ;RAN OUT OF TRIES CALL PLCGRP ;PLACE THIS GROUP ADDI P4,1 ;SOMETHING MOVED CALL SCORE ;EVALUATE PLACEMENT CAMG P1,T1 ;BETTER PLACEMENT? JRST EXGRP3 ;NO--KEEP LOOKING MOVE P1,T1 ;REMEMBER NEW SCORE CALL EXCINI ;RESTART SWAP LIST SOJG P5,EXGRP1 ;LOOP BACK TO TRY A SWAP JRST EXGRP4 ;TOO MANY TRIES EXGRP3: CALL UNEXCH ;SWAP THE BOXES BACK SOJG P5,EXGRP1 ;KEEP TRYING SWAPS EXGRP4: MOVE Q1,P4 ;COPY FLAG JRST EXGRP6 ;GO DO THE FINAL PLACEMENT ;CALLED FROM ABOVE TO DO THE REAL WORK PLCGRP: MOVEI Q1,0 ;ASSUME NOTHING MOVED EXGRP6: MOVE Q2,LVLPTR ;GET AOBJN POINTER TO LVLTAB EXGRP7: HRRZ T2,LVLTAB(Q2) ;GET AVLTSK INDEX CALL CMPPOS ;COMPUTE DESIRED POSITION HRRZ T2,Q2 ;COPY LVLTAB INDEX CALL ADJPOS ;ADJUST TO ELIMINATE OVERLAP HRRZ T2,LVLTAB(Q2) ;GET AVLTSK INDEX HRRZ T3,AVLTSK(T2) ;GET TSKLST INDEX CAME T1,TSKPOS(T3) ;NEW POSITION SAME AS OLD ADDI Q1,1 ;NO--SOMETHING MOVED MOVEM T1,TSKPOS(T3) ;STORE (NEW) POSITION AOBJN Q2,EXGRP7 ;LOOP OVER WHOLE LIST JUMPE Q1,RSKP ;SKIP RETURN IF NOTHING MOVED RET ;ELSE NON-SKIP RETURN ;TEMP STORAGE FOR EXCHANGE ROUTINES EXCH.I==LVLCNT+0 EXCH.J==LVLCNT+1 EXCH.N==LVLCNT+2 EXCH.S==LVLCNT+3 ;ALSO USES +4 ;INIT THE ROUTINE EXCINI: SETZM EXCH.I ;I=0 MOVEI T1,1 ;J=1 MOVEM T1,EXCH.J ; .. HLRE T1,LVLPTR ;N=SIZE OF LIST MOVMM T1,EXCH.N ; .. SOS EXCH.N ;ADJUST SO IT IS MAX INDEX RET ;EXCHANGE LVLTAB(I) WITH LVLTAB(J) DOEXCH: DMOVE T1,EXCH.I ;SAVE I AND J IN CASE DMOVEM T1,EXCH.S ; WE WANT TO UNSWAP MOVE T3,LVLTAB(T1) ;GET FIRST ENTRY EXCH T3,LVLTAB(T2) ;SWAP WITH SECOND ENTRY MOVEM T3,LVLTAB(T1) ;STUFF NEW FIRST ENTRY BACK AOS EXCH.J ;BUMP TO POINTER CAME T2,EXCH.N ;AT END? RETSKP ;NO--ALL OK AOS T1,EXCH.I ;BUMP EXCH.I MOVEI T2,1(T1) ;RESET J TO I+1 MOVEM T2,EXCH.J ; .. CAME T1,EXCH.N ;LOOKING AT LAST ENTRY RETSKP ;NO--ALL OK RET ;YES--GIVE UP ;ROUTINE TO UNSWAP TWO ENTRIES UNEXCH: DMOVE T1,EXCH.S ;GET SAVED PARAMETERS MOVE T3,LVLTAB(T1) ;GET FIRST ENTRY EXCH T3,LVLTAB(T2) ;SWAP WITH SECOND ENTRY MOVEM T3,LVLTAB(T1) ;PUT NEW FIRST ENTRY BACK RET ;SUBROUTINE TO EVALUATE A PLACEMENT ;RETURNS +1: T1/ SCORE (SMALLER IS BETTER) ASCORE: SAVEP MOVEI P6,1 ;SCORE WHOLE AVLTSK LIST MOVN P1,AVLCNT ;BUILD AOBJN POINTER HRLZ P1,P1 ; TO AVLTSK JRST SCORE0 ;GO DO IT SCORE: SAVEP ;SAVE VITAL REGS MOVEI P6,0 ;JUST DO LVLTAB MOVE P1,LVLPTR ;POINTER TO LIST SCORE0: MOVEI P2,0 ;INITIAL SCORE SCORE1: HRRZ P3,LVLTAB(P1) ;LVLTAB HAS AVLTSK INDEX SKIPE P6 ;DOING LVLTAB? HRRZ P3,P1 ;NO--JUST COPY INDEX HRRZ P3,AVLTSK(P3) ;AVLTSK HAS TSKLST INDEX HRRZ P4,TSKLST(P3) ;TSKLST HAS TASK BLOCK ; ADDRESS LOAD P5,TKBLP,(P4) ;LIST OF LINES GOING DOWN JUMPE P5,SCORE3 ;DONE IF BOTTOM BOX SCORE2: LOAD T1,DPTKP,(P5) ;ADDRESS OF TASK BLOCK CALL SCORE6 ;COMPUTE DELTA LOAD P5,DPBLP,(P5) ;FOLLOW CHAIN JUMPN P5,SCORE2 ;COUNT UP ALL LINES SCORE3: LOAD P5,TKDLP,(P4) ;NOW LOOK AT LINES GOING UP JUMPE P5,SCORE5 ;QUIT IF TOP BOX SCORE4: LOAD T1,DPBTK,(P5) ;ADDRESS OF TASK BLOCK CALL SCORE6 ;COMPUTE DELTA LOAD P5,DPDLP,(P5) ;STEP TO NEXT BOX JUMPN P5,SCORE4 ;LOOP OVER ALL LINES SCORE5: AOBJN P1,SCORE1 ;LOOP OVER ALL CONFLICTS MOVE T1,P2 ;COPY ANSWER RET ;DONE ;COMMON CODE TO COMPUTE DELTA SCORE6: LOAD T1,TKTKI,(T1) ;TASK LIST INDEX FLTR T2,TSKWID(T1) ;TARGET WIDTH FDVR T2,[2.0] ;DIVIDE BY 2 FIXR T2,T2 ;CONVERT ADD T2,TSKPOS(T1) ;TARGET POSITION FLTR T3,TSKWID(P3) ;OUR WIDTH FDVR T3,[2.0] ;DIVIDE BY 2 FIXR T3,T3 ;CONVERT ADD T3,TSKPOS(P3) ;OUR POSITION SUB T2,T3 ;GET OFFSET MOVM T2,T2 ;DON'T CARE ABOUT DIRECTION ADD P2,T2 ;ACCUMULATE SKEW RET ;DONE ;ROUTINE TO COMPUTE THE DESIRED POSITION FOR A TASK ;CALL WITH: T2/AVLTSK INDEX ;RETURN +1: T1/POSTION ; CMPPOS: SAVEQ HRRZ Q1,AVLTSK(T2) ;GET TSKLST INDEX MOVE Q2,AVLSST(T2) ;GET SORTED SUM FLTR Q3,TSKWID(Q1) ;GET WIDTH FDVR Q3,[2.0] ;DIVIDE IN HALF FSBR Q2,Q3 ;ADJUST FIXR T1,Q2 ;MAKE INTEGER JUMPGE T1,R ;DONE IF GOOD POSITION MOVEI T1,0 ;ELSE MAKE ZERO RET ;SUBROUTINE TO ADJUST POSITION SO THAT NOTHING OVERLAPS ;CALL WITH: ; T1/ DESIRED POSITION ; T2/ LVLTAB INDEX ; CALL ADJPOS ;RETURNS +1 WITH NEW POSITION IN T1 ; ADJPOS: CALL CKLOVL ;ANY OVERLAP NOW? RET ;NO--ALL DONE STKVAR ;SETUP SOME TEMPS MOVEM T1,GOAL ;SAVE ORIGINAL GOAL SETOM LFTPOS ;ASSUME MOSTLY FULL HRRZ T3,LVLTAB(T2) ;CONVERT LVLTAB INDEX TO AVLTSK INDEX HRRZ T3,AVLTSK(T3) ;CONVERT AVLTSK INDEX TO TSKLST INDEX ADJPS1: HRRZ T1,LVLTAB(T2) ;GET AVLTSK INDEX HRRZ T1,AVLTSK(T1) ;GET TSKLST INDEX MOVN T1,TSKWID(T1) ;WIDTH OF TASK TO INSERT ADD T1,TSKPOS(T3) ;BACK OFF TO STARTINGING POINT JUMPL T1,ADJPS2 ;STOP AT MARGIN CALL CKLOVL ;DOES IT FIT NOW? JRST [ MOVEM T1,LFTPOS ;SAVE THIS POSITION JRST ADJPS2] ;TRY GOING THE OTHER WAY HRRZ T3,AVLTSK(T3) ;CONVERT AVLTSK INDEX TO TSKLST INDEX JUMPG T1,ADJPS1 ;NO--KEEP MOVING LEFT ADJPS2: MOVE T1,GOAL ;RESTORE STARTING POSITION ADJPS3: MOVE T1,TSKPOS(T3) ;GET POSITION OF TASK ADD T1,TSKWID(T3) ;WHERE IT ENDS CALL CKLOVL ;DOES IT FIT YET? JRST ADJPS4 ;YES--AT LAST HRRZ T3,AVLTSK(T3) ;CONVERT AVLTSK INDEX TO TSKLST INDEX JRST ADJPS3 ;NO--KEEP MOVING RIGHT ADJPS4: SKIPGE LFTPOS ;WAS THERE ARE ANYPLACE TO THE LEFT RET ;NO JUST RETURN MOVE T3,T1 ;COPY NEW LOCATION SUB T3,GOAL ;COMPUTE ERROR MOVE T4,GOAL ;ORIGINAL TARGET SUB T4,LFTPOS ;ERROR GOING THAT WAY CAML T4,T3 ;WAS IT BETTER TO GO RIGHT? RET ;YES--ALL DONE MOVE T1,LFTPOS ;NO--GO LEFT RET ;DONE ;SUBROUTINE TO CHECK FOR OVERLAP ;CALL WITH: ; T1/ DESIRED POSITION ; T2/ AVLTSK INDEX ;RETURNS: +1 IF BOX FITS ; +2 IF SOME OVERLAP EXISTS ; T3/ TSKLST INDEX OF OFFENDING BOX ; CHKOVL: JUMPE T2,R ;THE FIRST BOX ALWAYS FITS SAVEP HRRZ P1,AVLTSK(T2) ;GET TSKLST INDEX MOVE P2,TSKWID(P1) ;GET WIDTH ADD P2,T1 ;LOCATION OF RIGHT EDGE MOVN P1,T2 ;JUST LOOK AT BOXES ALREADY PLACED HRLZ P1,P1 ;MAKE AOBJN POINTER CHKOV1: HRRZ P3,AVLTSK(P1) ;GET TSKLST INDEX FOR TARGET MOVE P4,TSKPOS(P3) ;POSITION OF ALREADY PLACED BOX CAML P4,P2 ;NEW BOX TO THE LEFT OF OLD? JRST CHKOV2 ;YES--NO OVERLAP ADD P4,TSKWID(P3) ;GET TO OTHER SIDE OF OLD CAML T1,P4 ;NEW BOX TO THE RIGHT OF OLD? JRST CHKOV2 ;YES--NO OVERLAP HRRZ T3,P1 ;COPY AVLTSK INDEX RETSKP ;RETURN OVERLAP CHKOV2: AOBJN P1,CHKOV1 ;LOOP OVER ALL BOXES ALREADY PLACED RET ;SAME FUNCTION EXCEPT T2/ LVLTAB INDEX CKLOVL: SAVEP HRRZ P1,LVLTAB(T2) ;GET AVLTSK INDEX HRRZ P1,AVLTSK(P1) ;GET TSKLST INDEX MOVE P2,TSKWID(P1) ;GET WIDTH ADD P2,T1 ;LOCATION OF RIGHT EDGE MOVN P1,AVLCNT ;LOOK AT ALL OF AVLTSK HRLZ P1,P1 ;MAKE AOBJN POINTER CKLOV1: HRRZ P3,AVLTSK(P1) ;GET TSKLST INDEX FOR TARGET MOVE P4,TSKPOS(P3) ;POSITION OF ALREADY PLACED BOX CAML P4,P2 ;NEW BOX TO THE LEFT OF OLD? JRST CKLOV2 ;YES--NO OVERLAP ADD P4,TSKWID(P3) ;GET TO OTHER SIDE OF OLD CAML T1,P4 ;NEW BOX TO THE RIGHT OF OLD? JRST CKLOV2 ;YES--NO OVERLAP HRRZ T3,P1 ;COPY AVLTSK INDEX ;IGNORE OVERLAP IF ITEM IS AHEAD IN LVLTAB HRR P6,T2 ;MAKE AN AOBJN POINTER HRL P6,T2 ; FOR THE REST OF THE LIST ADD P6,LVLPTR ; .. JUMPGE P6,RSKP ;DONE IF POSITIVE CAME T3,LVLTAB(P6) ;IS IT IN TABLE? AOBJN P6,.-1 ;NOT YET--KEEP LOOKING JUMPL P6,CKLOV2 ;IGNORE OVERLAP IF FOUND RETSKP ;RETURN OVERLAP CKLOV2: AOBJN P1,CKLOV1 ;LOOP OVER ALL BOXES ALREADY PLACED RET ;SUBROUTINE TO ADJUST LEVEL NUMBERS TO MAKE PERT LOOK BETTER ;CALL CALL ADJLVL ; RETURN HERE ALWAYS ADJLVL: MOVE T1,TSKPTR ;GET NUMBER OF TASKS HRROS TSKLST(T1) ;SET LH=-1 AS A FLAG AOBJN T1,.-1 ;FLAG ALL TASKS ADJLV1: CALL LVLWID ;SETUP LVLTAB CALL MOVEND ;MOVE UP TERMINAL BOXES JRST ADJLV1 ;SOMETHING MOVED CALL FLTUP ;FLOAT UP A MAJOR GROUP JRST ADJLV1 ;SOMETHING MOVED CALL SPLIT ;BREAKUP FULL LINES JRST ADJLV1 ;SOMETHING MOVED MOVE T1,TSKPTR ;TASK COUNT HRRZS TSKLST(T1) ;CLEAR FLAG AOBJN T1,.-1 ;LOOP OVER ALL TASKS SETZM LVLTAB ;ZERO OUT LEVEL TABLE MOVE T1,[LVLTAB,,LVLTAB+1] BLT T1,LVLTAB+MAXTSK-1 ;ZAP! MOVE T4,TSKPTR ;POINTER TO TASK LIST ADJLV2: SKIPE TSKINV(T4) ;WANT THIS IN PERT? JRST ADJLV3 ;NO--SKIP IT HLRZ T1,TSKSKD(T4) ;GET LEVEL MOVE T2,LVLTAB(T1) ;GET CURRENT POSITION FOR THAT LEVEL MOVEM T2,TSKPOS(T4) ;INITIAL POSITION ADD T2,TSKWID(T4) ;UPDATE POSITION MOVEM T2,LVLTAB(T1) ;SAVE FOR NEXT GUY ADJLV3: AOBJN T4,ADJLV2 RET ;EVERYTHING STOPPED MOVING ;SUBROUTINE TO SETUP SOME TABLES FOR PERT PLACER ; CALL LVLWID ; RETURN HERE ALWAYS ; ;SETUP THE FOLLOWING STUFF ;LVLTAB/ 1B0 IF THIS LEVEL IS VERY FULL ; 1B1 IF THIS LEVEL IS VERY EMPTY ; RH: NUMBER OF BOXES IN THIS LEVEL ;LVLCNT/ WIDTH OF THIS LEVEL ;AVWID/ AVERAGE WIDTH OF A PERT LINE ; LVLWID: SAVEQ MOVE T1,[LVLTAB,,LVLTAB+1] ;ZERO OUT TABLES SETZM LVLTAB BLT T1,LVLTAB+MAXTSK-1 MOVE T1,[LVLCNT,,LVLCNT+1] SETZM LVLCNT BLT T1,LVLCNT+MAXTSK-1 MOVE T4,TSKPTR ;AOBJN POINTER TO TSKLST SETZB Q1,Q2 ;CLEAR COUNTERS LVLWI1: SKIPE TSKINV(T4) ;WANT THIS TASK IN PERT? JRST LVLWI2 ;NO--SKIP TO NEXT TASK HLRZ T3,TSKSKD(T4) ;GET LEVEL NUMBER AOS LVLTAB(T3) ;COUNT USE AT THIS LEVEL MOVE T1,TSKWID(T4) ;GET WIDTH ADDM T1,LVLCNT(T3) ;ADD TO THIS LEVEL ADD Q1,T1 ;ADD TO TOTAL CAMGE Q2,T3 ;REMEMBER MAX LEVEL MOVE Q2,T3 ; .. LVLWI2: AOBJN T4,LVLWI1 ;LOOP OVER ALL TASKS ADDI Q2,1 ;NUMBER OF LEVELS FLTR T1,Q1 ;TOTAL WIDTH FLTR T2,Q2 ;TOTAL NUMBER OF LEVELS FDVR T1,T2 ;AVERAGE WIDTH FIXR T1,T1 ;FIX AND ROUND MOVEM T1,AVWID MOVN T4,Q2 ;NUMBER OF LEVELS HRLZ T4,T4 ;AOBJN POINTER TO LVLTAB MOVEM T4,LVLPTR ;SAVE AOBJN POINTER ;NOW GO MARK FULL LEVELS SETOM T1 ;PRESET MAX LVLWI3: CAMGE T1,LVLCNT(T4) ;NEW HIGH JRST [ MOVE T1,LVLCNT(T4) ;UPDATE MAX MOVE T3,T4 ;REMEMBER HIGH JRST .+1] ;CONTINUE AOBJN T4,LVLWI3 ;LOOP OVER ALL TASKS MOVSI T2,(1B0) ;MARK WIDEST LEVEL AS FULL IORM T2,LVLTAB(T3) ; .. MOVE Q1,AVWID ;GET WIDTH ASH Q1,-1 ;DIVIDE BY 2 MOVE Q2,AVWID ;GET WIDTH AGAIN ASH Q2,1 ;DOUBLE IT MOVSI T2,(1B0) ;FULL LEVEL FLAG MOVSI T3,(1B1) ;EMPTY LEVEL FLAG LVLWI4: MOVE T1,LVLCNT(T4) ;WIDTH OF THIS LEVEL CAMGE T1,Q1 ;LESS THAN HALF AVERAGE? IORM T3,LVLTAB(T4) ;YES--MARK AS VERY EMPTY CAMLE T1,Q2 ;MORE THAN TWICE AVERAGE? IORM T2,LVLTAB(T4) ;YES--MARK AS VERY FULL AOBJN T4,LVLWI4 RET ;ALL DONE ;SUBROUTINE TO MOVE TERMINAL BOXES OFF THE BOTTOM LINE ;CALL WITH: ; CALL MOVEND ; RETURN HERE IF SOMETHING MOVED ; RETURN HERE WHEN DONE MOVEND: SAVEP MOVE P1,TSKPTR ;SETUP FOR LOOP MVEND1: MOVE P2,TSKLST(P1) ;GET POINTER TO A TASK LOAD P3,TKBLP,(P2) ;GET BLOCKING LIST POINTER JUMPE P3,MVEN1B ;JUMP IF TERMINAL BOX MVEN1A: LOAD T1,DPTKP,(P3) ;GET TASK POINTER LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX SKIPN TSKINV(T1) ;WANT IN PERT? JRST MVENDX ;YES--THEN NOT TERMINAL BOX LOAD P3,DPBLP,(P3) ;FOLLOW LIST JUMPN P3,MVEN1A ;LOOP OVER ALL BOXES -- OK ;IF ALL ARE INVISIBLE MVEN1B: LOAD P3,TKDLP,(P2) ;SEE WHO IS BLOCKING US JUMPE P3,MVEND5 ;SINGLE FLOATING BOX MOVEI P4,0 ;MAX LEVEL MVEND2: LOAD T1,DPBTK,(P3) ;POINTER TO BLOCKING TASK LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX HLRZ T1,TSKSKD(T1) ;GET LEVEL NUMBER CAMLE T1,P4 ;NEW MAX? MOVE P4,T1 ;YES REMEMBER THAT LOAD P3,DPDLP,(P3) ;FOLLOW LIST JUMPN P3,MVEND2 ;LOOP OVER ALL TASKS ADDI P4,1 ;BUMP TO NEXT LEVEL HLRZ P2,TSKSKD(P1) ;GET CURRENT LEVEL ;NOW WE WANT TO PUT THE BOX ON A NON-FULL LEVEL CLOSE TO THE TARGET MVEND3: CAMN P2,P4 ;WHERE WE SHOULD BE? JRST MVENDX ;YES--TRY NEXT SKIPL LVLTAB(P4) ;HOW ABOUT THIS LEVEL? JRST MVEND4 ;SOLD! ADDI P4,1 ;NO--BUMP LEVEL JRST MVEND3 ;LOOP BACK MVEND4: HRLM P4,TSKSKD(P1) ;NO--STORE NEW LEVEL JRST MVEND7 ;PRINT MESSAGE AND RETURN MVEND5: HLRZ T1,TSKSKD(P1) ;GET CURRENT LEVEL MOVSI T2,(1B1) ;FLAG FOR EMPTY LEVEL TDNE T2,LVLTAB(T1) ;ON EMPTY LEVEL NOW? JRST MVENDX ;YES--LEAVE ALONE MVEND6: TDNN T2,LVLTAB(T1) ;IS THIS AN EMPTY LEVEL SOJGE T1,MVEND6 ;NO--KEEP LOOKING JUMPLE T1,MVENDX ;NOPLACE TO GO HRLM T1,TSKSKD(P1) ;MOVE BOX UP MVEND7: HRRZ T1,P1 ;COPY INDEX CALL MOVMSG ;INDICATE SOMETING HAPPENED RET ;TRY AGAIN MVENDX: AOBJN P1,MVEND1 ;LOOP OVER ALL TASKS RETSKP ;NOTHING MOVED ;SUBROUTINE TO MOVE THINGS UP FROM A FULL PART OF THE PERT ; TO AN EMPTY PART OF THE PERT ;CALL WITH: ; CALL FLTUP ;RETURNS +1 IS SOMETHING MOVED ; +2 IFNOTHING MOVED ; FLTUP: SAVEQ CALL MAYFLT ;FIND SOMETHING TO FLOAT JRST FLTUP2 ;NOTHING FOUND MOVE Q1,T1 ;SAVE TSKLST INDEX CALL MOVMSG ;OUTPUT MESSAGE HLRZ Q3,TSKSKD(Q1) ;GET CURRENT LEVEL SUBI Q3,2 ;FIRST POSSIBLE PLACE TO PUT IT MOVSI T1,(1B1) ;FLAG FOR EMPTY LEVEL TDNN T1,LVLTAB(Q3) ;HOW ABOUT HERE? SOJGE Q3,.-1 ;NO--KEEP MOVING UP SKIPGE Q3 ;SOMEPLACE FOUND? ERRMES ADDI Q3,1 ;ADVANCE ONE LEVEL HRLM Q3,TSKSKD(Q1) ;SAVE ADJUSTED LEVEL SUBI Q3,1 ;BACK TO EMPTY LEVEL HRRZS Q2,TSKLST(Q1) ;GET ADR OF TASK BLOCK LOAD Q2,TKDLP,(Q2) ;GET POINTER TO DEP LIST JUMPN Q2,FLTUP1 ;MAKE SURE IT IS THERE ERRMES FLTUP1: LOAD T1,DPBTK,(Q2) ;POINTER TO BLOCKING TASK LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX HRLM Q3,TSKSKD(T1) ;STORE NEW LEVEL NUMBER HRRZS TSKLST(T1) ;CLEAR FLAG LOAD Q2,DPDLP,(Q2) ;FOLLOW LIST JUMPN Q2,FLTUP1 ;MOVE ALL BOXES UP RET FLTUP2: MOVEI T1,0 ;START AT THE TOP FLTU2A: CALL FFLVL ;FIND A GOOD PLACE TO DO A FLOAT RETSKP ;NONE FOUND! HRRZ Q1,T1 ;SAVE SOURCE HRRZ Q2,T2 ;SAVE DESTINATION MOVE Q3,TSKCNT ;SCAN TSKLST BACKWARDS SUBI Q3,1 ; .. FLTUP3: HLRZ T2,TSKSKD(Q3) ;GET LEVEL NUMBER CAME T2,Q1 ;THE ONE WE WANT? JRST FLTUP4 ;NO--KEEP LOOKING HRRZ T1,Q3 ;COPY TSKLST INDEX HRRZ T2,Q2 ;COPY TARGET LEVEL CALL LGLFLT ;IS THIS A LEGAL MOVE? JRST FLTUP4 ;NO! HRRZ T1,Q3 ;SETUP FOR MOVMSG CALL MOVMSG ;INDICATE WE ARE DOING THE MOVE HRRZS TSKLST(Q3) ;SET FLAG HRLM Q2,TSKSKD(Q3) ;MOVE THE BOX RET ;DO ANALYSIS AGAIN FLTUP4: SOJGE Q3,FLTUP3 ;LOOP OVER ALL TASKS MOVEI T1,1(Q1) ;ADJUST TARGET JRST FLTU2A ;KEEP TRYING ;ROUTINE TO FIND A PAIR OF LEVELS FOR MOTION ;RETURNS +1: NOTHING FOUND ; +2: T1/ SOURCE LEVEL T2/ DESTINATON LEVEL FFLVL: HRL T1,T1 ;MAKE XWD ADD T1,LVLPTR ;GET POINTER TO LVLTAB FFLVL1: SKIPL LVLTAB(T1) ;IS THIS LEVEL FULL? FFLVL2: AOBJN T1,FFLVL1 ;NO--KEEP LOOKING JUMPG T1,R ;NOTHING FOUND HRREI T2,-1(T1) ;TARGET LEVEL JUMPL T2,FFLVL2 ;DO NOT MOVE OFF TOP MOVEI T3,5 ;MAXIMUM MOTION MOVE T4,LVLCNT(T1) ;WIDTH OF THIS LEVEL ASH T4,-1 ;DIVIDE BY 2 FFLVL3: CAMLE T4,LVLCNT(T2) ;TARGET EMPTY ENOUGH? RETSKP ;YES SOJL T2,FFLVL2 ;REDUCE TARGET. SOJG T3,FFLVL3 ;KEEP LOOPING JRST FFLVL2 ;KEEP LOOKING ;ROUTINE TO CHECK FOR A LEGAL FLOAT ;CALL WITH: ; T1/ TSKLST INDEX ; T2/ TARGET ;RETURNS +1: NOT LEGAL ; +2: LEGAL LGLFLT: SAVEQ HRRZ Q2,T2 ;SAVE TARGET HRRZ T4,TSKLST(T1) ;GET ADDRESS OF TASK BLOCK LOAD T3,TKBLP,(T4) ;GET POINTER TO HIGHER LEVELS JUMPE T3,LGLFL1 ;JUMP IF BOTTOM BOX LOAD T3,DPBLP,(T3) ;SEE IF MORE BOXES JUMPN T3,R ;MAX OF 1 LINE DOWN LGLFL1: LOAD Q1,TKDLP,(T4) ;GET POINTER TO BOXES UP LGLFL2: JUMPE Q1,RSKP ;OK IF NONE ABOVE LOAD T1,DPBTK,(Q1) ;GET TASK ADDRESS LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX HLRZ T2,TSKSKD(T1) ;GET ITS LEVEL CAML T2,Q2 ;ABOVE TARGET? RET ;NO--LINES MAY NOT GO UP LOAD Q1,DPDLP,(Q1) ;LOOK AT NEXT TASK JRST LGLFL2 ;LOOP MOVMSG: RET ;PATCH TO JFCL TO PRINT MESSAGE MOVE T4,T1 ;SAVE TSKLST INDEX TMSG <[MOVING UP > ;SAY WHAT WE ARE DOING HRRZ T1,TSKLST(T4) ;GET ADDRES OF TASK BLOCK CALL TYPTNM ;TYPE TASK NAME TMSG<] > RET ;RETURN ;SUBROUTINE TO FIND A GROUP OF BOXES TO FLOAT UP ; CALL MAYFLT ;RETURNS +1: IF NOTHING TO MOVE ; +2: T1/ TSKLST INDEX OF ROOT MAYFLT: MOVE T4,TSKPTR ;USUAL AOBJN POINTER MAYFL1: SKIPE TSKINV(T4) ;IS THIS TASK IN THE PERT? JRST MAYFL4 ;NO--SKIP IT HLRZ T1,TSKSKD(T4) ;GET LEVEL CAIGE T1,2 ;ANY HOPE OF REDUCING JRST MAYFL4 ;NO--LOOK ON MOVE T2,LVLTAB-1(T1) ;LOOK AT PREVIOUS LEVEL HLRE T3,TSKLST(T4) ;GET FLAG XCT [ TLNE T2,(1B1) ;NOT ON EMPTY LEVEL AND NEVER MOVED TLNN T2,(1B0)]+1(T3) ; OR MOVED TO A FULL LEVEL JRST MAYFL4 ;NO--LOOK ON MOVSI T2,(1B1) ;EMPTY LEVEL FLAG SUBI T1,2 ;PLACE TO STRAT LOOKING TDNN T2,LVLTAB(T1) ;LOOK FOR EMPTY LEVEL SOJGE T1,.-1 ;LOOP OVER ALL LEVELS JUMPL T1,MAYFL4 ;LOOK ON IF NONE HRRZ T1,TSKLST(T4) ;GET POINTER TO TASK BLOCK LOAD T2,TKDLP,(T1) ;POINTER TO BLOCKING LIST MOVEI T3,0 MAYFL2: JUMPE T2,MAYFL3 ;STOP AT END OF LIST LOAD T1,DPBTK,(T2) ;GET BLOCKING TASK LOAD T1,TKDLP,(T1) ;GET IT DEP LIST JUMPN T1,MAYFL4 ;CAN ONLY DO ONE LEVEL NOW LOAD T2,DPDLP,(T2) ;FOLLOW LIST AOJA T3,MAYFL2 ;COUNT BOXES MAYFL3: CAIGE T3,3 ;WORTH MOVING? JRST MAYFL4 ;NO. HRRZ T1,T4 ;YES--GO MOVE IT RETSKP MAYFL4: AOBJN T4,MAYFL1 ;LOOP OVER ALL TASKS RET ;NOTHING WORTH MOVING ;SUBROUTINE TO BREAK FULL LEVELS INTO TWO LEVELS ;CALL: CALL SPLIT ;RETURNS: +1 IF SOMETHING MOVED ; +2 IF NOTHING MOVED SPLIT: RETSKP ;NOT TONIGHT ;SUBROUTINE TO DO THE SELECTION DIALOGUE ; CALL SELECT ; RETURN HERE WITH SELTAB SETUP ; SELECT: SAVEPQ ;SAVE SOME AC'S CALL SELINI ;INIT THE DATA BASE SELNXT: HRROI T1,[ASCIZ /SELECT: /] MOVEI T2,SEL MOVEI T3,ANSWER CALL PARSE ERRMES () MOVEI P1,ANSWER ;POINT TO ANSWER BLOCK HLRZ T1,(P1) ;GET TYPE CHKTYP (KEY) ;MUST BE KEYWORD HRRZ T1,(P1) ;POINTER TO DISPATCH AOJA P1,(T1) ;GO DO FUNCTION ; ; HERE ON INCLUDE COMMAND ; SELIP: HLRZ T1,(P1) ;CHECK FOR KEYWORD CHKTYP (KEY) HRRZ T1,(P1) ;POINTER TO DISPATCH AOJA P1,(T1) ;GO DISPATCH ; ; HERE ON INCLUDE PROJECT ; SELIPR: HLRZ T1,(P1) ;CHECK THE TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET POINTER TO PROJ BLOCK HRLI T1,.TYPRJ ;FLAG IT AS A PROJECT HLRZ P2,1(P1) ;GET TYPE OF NEXT ITEM CAIN P2,.CMCFM ;WAS IT JUST CR? JRST SLIPR1 ;YES--WHOLE PROJECT MOVE T1,P2 ;COPY TYPE CHKTYP (KEY) ;BETTER BE A KEYWORD MOVSI T1,.TYTSK ;GET POINTER TO TASK BLOCK HRR T1,1(P1) ; .. SLIPR1: CALL SELSTO ;STORE INTO SELTAB JRST SELNXT ;GET NEXT COMMAND ; ; HERE WHEN DONE ; SELFI: RET ;SUBROUTINE TO INIT SELECTION DATABASE ; CALL SELINI ; RETURN HERE ALWAYS ; SELINI: SETZM SELCNT ;CLEAR COUNTER RET ;ALL SET ;SUBROUTINE TO STORE INTO SELTAB ;CALL WITH: ; T1/ TYPE,,DATA ; CALL SELSTO ; RETURN HERE SELSTO: AOS T2,SELCNT ;BUMP COUNTER CAILE T2,MAXSEL ;ROOM? WARN (,) MOVEM T1,SELTAB-1(T2) ;STORE RET ;SUBROUTINE TO DECIDE IF A TASK SHOULD BE PERTED ;CALL WITH: ; T1/ TASK BLOCK ; CALL PRTTSK ; RETURN HERE IF NO ; RETURN HERE IF YES ; PRTTSK: SKIPN SELFLG ;ANY SELECTIONS DONE? RETSKP ;NO--ALWAYS PERT SAVEPQ ;SAVE SOME AC'S MOVN Q1,SELCNT ;NUMBER OF THINGS SELECTED HRLZ Q1,Q1 ;AOBJN'IZE LOAD Q2,TKPRJ,(T1) ;ADDRESS OF PROJ BLOCK HRLI Q2,.TYPRJ ;FLAG AS PROJECT MOVE Q3,T1 ;COPY POINTER TO TASK BLOCK HRLI Q3,.TYTSK ;FLAG AS TASK PRTSK1: CAME Q2,SELTAB(Q1) ;MATCH EITHER PROJECT CAMN Q3,SELTAB(Q1) ; OR TASK RETSKP ;YES--STUFF IT IN PERT AOBJN Q1,PRTSK1 ;SCAN WHOLE TABLE RET ;EXCLDE IF NOT THERE ;ADD COMMAND ADDCMD: HLRZ T1,(P1) ;GET FUNCTION CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET DISPATCH ADR AOJA P1,(T1) ;DISPATCH ;ADD PROJECT ADDP: HLRZ T1,(P1) ;CHECK THE CODE CHKTYP (FLD) HRRZ T1,(P1) ;GET ADR OF PROJECT NAME ADDI T1,ANSWER CALL ADDPRJ ;ADD THE PROJECT NAME TO THE TABLE WARN (,) MOVE P2,T1 ;SET UP THE ADR OF THE PROJECT BLOCK CAMN T2,PRJTBL ;IS THERE A NEW PROJECT TABLE? JRST LOGPRJ ;NO, GO GET THE NEXT COMMAND MOVE T1,PRJTBL ;YES, RELEASE THE OLD ONE MOVEM T2,PRJTBL ;STORE THE NEW ONE CALL RELFRE JRST LOGPRJ ;GO GET NEXT COMMAND ;ADD TASK ADDT: HLRZ T1,(P1) ;CHECK THE TYPE CODE CHKTYP (FLD) HLRZ T1,1(P1) ;NOW CHECK THE SECOND FIELD CHKTYP (KEY) HRRZ T1,0(P1) ;GET POINTER TO TASK NAME ADDI T1,ANSWER HRRZ T2,1(P1) ;GET POINTER TO PROJECT BLOCK LOAD T3,PJTKT,(T2) ;GET ADR OF TASK TABLE CALL ADDTSK ;ADD THIS TASK TO THE TABLE WARN (,) MOVE P3,T1 ;SET UP POINTER TO TASK BLOCK LOAD P2,TKPRJ,(P3) ;AND THE POINTER TO THE PROJECT BLOCK LOAD T1,PJTKT,(P2) ;GET THE TASK LIST ADDRESS CAMN T1,T2 ;IS THERE A NEW TASK LIST ADDRESS? JRST LOGTSK ;NO, GO GET NEXT COMMAND STOR T2,PJTKT,(P2) ;YES, STORE THE NEW ADDRESS CALL RELFRE ;RELEASE THE OLD BLOCK JRST LOGTSK ;GO GET NEXT COMMAND ;DELETE COMMAND DELETE: HLRZ T1,(P1) ;CHECK THE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET THE DISPATCH ADDRESS AOJA P1,(T1) ;DISPATCH ;DELETE OVERALL DEVELOPER DELODV: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (USR) HRRZ T1,(P1) HRROI T1,ANSWER+1(T1) ;GET A POINTER TO THE DEVELOPER NAME MOVE T2,DEVTBP ;GET POINTER TO DEVELOPER LIST CALL DELDEV ;DELETE THE DEVELOPER WARN (,) MOVEM T1,DEVTBP ;SAVE THE NEW POINTER CALL UPDDB ;UPDATE THE DATA BASE JRST LEVEL0 ;DELETE PROJECT DELPRJ: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ P2,(P1) ;GET ADR OF PROJECT BLOCK DELPR1: LOAD T1,PJTKT,(P2) ;GET ADR OF TASK TABLE HLRZ T2,(T1) ;GET NUMBER OF ENTRIES IN TABLE JUMPE T2,DELPR2 ;IF NONE, THEN DONE HRRZ T1,1(T1) ;GET FIRST ENTRY IN TABLE CALL DELT ;DELETE THIS TASK JRST DELPR1 ;LOOP BACK TILL ALL TASKS DELETED DELPR2: MOVE T1,PRJTBL ;GET ADR OF PROJECT TABLE LOAD T2,PJNAM,(P2) ;GET ADR OF NAME BLOCK HRLI T2,(POINT 7,0) TBLUK ;LOOK UP THIS PROJECT ERJMP DELPR3 ;FAILED TXNN T2,TL%EXM ;MUST FIND AN EXACT MATCH DELPR3: WARN (,) MOVE T2,T1 ;GET ADR OF ENTRY IN TABLE MOVE T1,PRJTBL ;GET ADR OF TABLE TBDEL ;DELETE THE ENTRY ERJMP DELPR3 LOAD T1,PJNAM,(P2) ;GET THE NAME STRING CALL RELFRE ;RELEASE IT LOAD T1,PJDSC,(P2) ;RELEASE THE DESCRIPTION BLOCK CALL RELFRE LOAD T1,PJTKT,(P2) ;NOW RELEASE THE TASK TABLE CALL RELFRE DELPR4: LOAD Q1,PJDVL,(P2) ;NOW RELEASE THE DEVELOPER LIST JUMPE Q1,DELPR6 ;IF THERE IS ONE DELPR5: MOVE T1,Q1 ;GET ADR OF THIS BLOCK LOAD Q1,DVLNK,(Q1) ;GET ADR OF NEXT ONE CALL RELDEV ;RELEASE THE BLOCK JUMPN Q1,DELPR5 ;LOOP BACK FOR THE OTHER BLOCKS DELPR6: MOVE T1,P2 ;FINALLY, RELEASE THE PROJECT BLOCK CALL RELFRE JRST LOGLV0 ;DONE ;ROUTINE TO DELETE A TASK DELTSK: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ P2,(P1) ;SET UP POINTER TO PROJECT BLOCK HLRZ T1,1(P1) ;GET SECOND TYPE CODE CHKTYP (KEY) HRRZ T1,1(P1) ;SET UP POINTER TO TASK BLOCK CALL DELT ;GO DELETE THE TASK JRST LOGLV0 ;ROUTINE TO DELETE A TASK BLOCK ;ACCEPTS IN T1/ TASK BLOCK ADR DELT: SAVEPQ MOVE P3,T1 ;GET ADR OF TASK INTO P3 LOAD P2,TKPRJ,(P3) ;GET ADR OF PROJECT BLOCK INTO P2 LOAD T1,PJTKT,(P2) ;GET THE ADR OF THE TASK TABLE LOAD T2,TKNAM,(P3) ;GET A POINTER TO THE NAME STRING HRLI T2,(POINT 7,0) ;SET UP A BYTE POINTER TO NAME TBLUK ;LOOK UP THE NAME IN THE TABLE ERJMP DELT1 ;FAILED TO FIND IT TXNN T2,TL%EXM ;FOUND AN EXACT MATCH? DELT1: WARN (,) MOVE T2,T1 ;SAVE ADR OF THE ENTRY TO BE DELETED LOAD T1,PJTKT,(P2) ;GET ADR OF TASK TABLE TBDEL ;DELETE THIS ENTRY ERJMP DELT1 ;FAILED LOAD T1,TKNAM,(P3) ;NOW RETURN THE NAME STRING SKIPE T1 CALL RELFRE LOAD T1,TKDSC,(P3) ;RELEASE DESCRIPTION BLOCK SKIPE T1 CALL RELFRE DELT1A: LOAD T1,TKDLP,(P3) ;GET POINTER TO DEPENDENCY LIST JUMPE T1,DELT1B ;IF NONE, GO ON TO BLOCKED LIST CALL RELDEP ;RELEASE THIS DEPENDENCY BLOCK JRST DELT1A ;LOOP BACK TIL LIST IS EMPTY DELT1B: LOAD T1,TKBLP,(P3) ;NOW EMPTY THE BLOCKED LIST JUMPE T1,DELT1C ;STOP WHEN LIST IS EMPTY CALL RELDEP ;RELEASE THIS BLOCK JRST DELT1B ;LOOP BACK TILL LIST IS EMPTY DELT1C: LOAD Q1,TKDVL,(P3) ;NOW RELEASE DEVELOPER LIST JUMPE Q1,DELT3 ;UNLESS ALREADY EMPTY DELT2: MOVE T1,Q1 ;RELEASE THIS BLOCK LOAD Q1,DVLNK,(Q1) ;GET POINTER TO NEXT BLOCK CALL RELDEV ;RELEASE THIS ONE JUMPN Q1,DELT2 ;LOOP BACK IF MORE TO BE DONE DELT3: MOVE T1,P3 ;FINALY, RELEASE TASK BLOCK CALL RELFRE RET ;DONE ;DEVELOPER COMMAND L0DEV: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (USR) HLRZ T1,1(P1) ;GET SECOND TYPE CODE CHKTYP (FLT) HLRZ T1,2(P1) ;GET THIRD TYPE CODE CHKTYP (FLT) HRRZ T1,0(P1) ;NOW GET THE USER NUMBER HRROI T1,ANSWER+1(T1) ;GET POINTER TO NAME STRING HRRZ T2,1(P1) ;AND GET THE RATE MOVE T2,ANSWER(T2) HRRZ T3,2(P1) ;GET THE HANDICAP MOVE T3,ANSWER(T3) MOVE T4,DEVTBP ;GET POINTER TO OVERALL LIST CALL BLDDEV ;GO ADD THE DEVELOPER WARN (,) JUMPN T2,L0DEV1 ;CHANGED FIRST BLOCK? MOVE T2,DEVTBP ;YES STOR T2,DVLNK,(T1) ;PUT NEXT POINTER INTO THE LIST MOVEM T1,DEVTBP ;PUT THIS BLOCK ON FRONT OF LIST L0DEV1: CALL UPDDB ;UPDATE THE DATA BASE L0DEV2: JRST LEVEL0 ;DONE ;UPDATE COMMAND UPDATE: HLRZ T1,(P1) ;CHECK THE TYPE CODE CHKTYP (KEY) HRRZ P2,(P1) ;SET UP POINTER TO PROJECT BLOCK HLRZ T1,1(P1) ;CHECK CODE OF NEXT ITEM CAIN T1,.CMCFM ;ID USER UPDATING PROJECT BLOCK? JRST LOGPRJ ;YES CHKTYP (KEY) HRRZ P3,1(P1) ;UPDATING THE TASK BLOCK JRST LOGTSK ;ROUTINES TO UPDATE A TASK OR PROJECT BLOCK LOGPRJ: CALL UPDDB ;UPDATE THE DATA BASE JRST UPDPRJ LOGTSK: CALL UPDDB ;GO UPDATE THE DATA BASE JRST UPDTSK UPDTSK: CALL INITRA ;INIT TRANSACTION AREA HRROI T1,[ASCIZ/TASK DATA: /] MOVEI T2,DATA ;GET POINTER TO COMMAND TABLE JRST UPDPR1 ;ENTER COMMON CODE UPDPRJ: CALL INITRA ;GO INITIALIZE THE TRANSACTION AREA HRROI T1,[ASCIZ/PROJECT DATA: /] MOVEI T2,PDATA UPDPR1: MOVEI T3,ANSWER ;GO PARSE THE NEXT LINE CALL PARSE ERRMES () CALL COPCMD ;COPY COMMAND TO CMDBLK MOVEI P1,ANSWER ;SET UP POINTER TO ANSWER BLOCK HLRZ T1,(P1) ;CHECK TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET DISPATCH ADR AOJA P1,(T1) ;DISPATCH ;ROUTINE TO GET THE DESCRIPTION OF A PROJECT PRJDSC: HRROI T1,[ASCIZ/PROJECT DESCRIPTION: /] CALL GETDSC ;GET A DESCRIPTIO WARN (,) LOAD T2,PJDSC,(P2) ;SEE IF THERE IS ALREADY A DESCRIPTION STOR T1,PJDSC,(P2) ;STORE THE NEW DESCRIPTION SKIPE T1,T2 ;WAS THERE AN OLD ONE? CALL RELFRE ;YES, RELEASE ITS SPACE JRST LOGPRJ ;GO BACK FOR THE NEXT COMMAND ;ROUTINE TO ADD A DEVELOPER TO A PROJECT PRJDEV: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (USR) HLRZ T1,1(P1) ;GET SECOND TYPE CODE CHKTYP (FLT) HLRZ T1,2(P1) ;GET THIRD TYPE CODE CHKTYP (FLT) HRRZ T1,0(P1) ;NOW GET THE USER NUMBER HRROI T1,ANSWER+1(T1) ;GET POINTER TO NAME STRING HRRZ T2,1(P1) ;AND GET THE RATE MOVE T2,ANSWER(T2) HRRZ T3,2(P1) ;GET THE HANDICAP MOVE T3,ANSWER(T3) LOAD T4,PJDVL,(P2) ;GET POINTER TO FIRST ELEMENT IN LIST CALL BLDDEV ;GO BUILD A DEVELOPER BLOCK WARN (,) JUMPN T2,PRJDV1 ;IF NOT NEW BLOCK, THEN DONE STOR P2,DVBKP,(T1) ;PUT THE BACK POINTER INTO THE BLOCK LOAD T2,PJDVL,(P2) ;NOW ADD THIS BLOCK TO THE LIST STOR T2,DVLNK,(T1) ;MAKE THIS BLOCK POINT DOWN THE LIST STOR T1,PJDVL,(P2) ;MAKE THE PROJECT BLOCK POINT TO THIS BLOCK PRJDV1: JRST LOGPRJ ;DONE ;PROJECT DELETE COMMAND PRJDEL: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ T1,0(P1) ;GET DISPATCH ADR AOJA P1,(T1) ;GO DISPATCH ;ROUTINE TO DELETE A DEVELOPER FROM A PROJECT PRJDLD: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (USR) HRRZ T1,0(P1) ;GET ADR OF USER CODE HRROI T1,ANSWER+1(T1) ;GET POINTER TO NAME STRING LOAD T2,PJDVL,(P2) ;GET ADR OF FIRST BLOCK IN LIST CALL DELDEV ;GO DELETE THE DEVELOPER WARN (,) STOR T1,PJDVL,(P2) ;STORE THE UPDATED BLOCK POINTER JRST LOGPRJ ;DONE ;ROUTINE TO FINISH UPDATING PROJECT DATA PRJFIN: JRST LOGLV0 ;GO BACK TO LEVEL 0 ;PROJECT PREFERENCE VALUE PRJPRF: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (FLT) HRRZ T1,(P1) ;GET POINTER TO VALUE MOVE T1,ANSWER(T1) ;GET VALUE STOR T1,PJPRF,(P2) ;SAVE IT JRST LOGPRJ ;ROUTINE TO LIST A PROJECT PRJLST: MOVEI T1,.PRIOU ;TYPE OUT THE PROJECT MOVE T2,P2 ;GET ADR OF PROJECT BLOCK CALL TYPPRJ ;OUTPUT THE PROJECT JRST UPDPRJ ;DONE ;ROUTINE TO TYPE OUT A PROJECT ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ ADR OF THE PROJECT BLOCK TYPPRJ: SAVEPQ MOVE P1,T1 ;SAVE THE JFN MOVE P2,T2 ;GET THE PROJECT BLOCK ADR TYPE T1,<&PROJECT: > LOAD T2,PJNAM,(P2) ;GET PROJECT NAME CALL TYPSTR TYPE T1,<&PROJECT DESCRIPTION: > LOAD T2,PJDSC,(P2) ;GET PROJECT DESCRIPTION CALL TYPSTR LOAD T2,PJPRF,(P2) ;GET PREFERENCE JUMPE T2,TYPPR0 ;IF NONE, SKIP THIS TYPE T1,<& PREFERENCE VALUE: > CALL TYPFLT TYPPR0: LOAD T2,PJDVL,(P2) ;GET POINTER TO DEVELOPER LIST CALL TYPDEV ;TYPE OUT DEVELOPERS TYPE T1,<&> LOAD T2,PJTKT,(P2) ;GET POINTER TO TASK LIST MOVEI Q1,1(T2) ;GET POINTER TO FIRST TASK IN LIST HLRZ T2,0(T2) ;GET LENGTH OF TABLE MOVNS T2 JUMPE T2,TYPPR2 ;IF NONE, THEN DONE HRL Q1,T2 ;FINISH MAKING AN AOBJN POINTER TYPPR1: HRRZ T2,0(Q1) ;GET NEXT TASK BLOCK ADR MOVE T1,P1 ;GET JFN CALL TYPTSK ;TYPE OUT THIS TASK AOBJN Q1,TYPPR1 ;LOOP BACK FOR ALL TASKS TYPPR2: RET ;DONE ;ROUTINE TO GET A DESCRIPTION ;ACCEPTS IN T1/ POINTER TO THE PROMPT STRING ; CALL GETDSC ;RETURNS +1: FAILED ; +2: OK, T1/ ADDRESS OF DESCRIPTION BLOCK GETDSC: STKVAR HRROI T2,STRING ;GET DESCRIPTION HERE MOVEI T3,STRNGC CALL GETSTR ;GET A STRING RET MOVEI T2,.TYDSC ;NOW GET A BLOCK FOR IT MOVEI T3,.VNDSC ;THE NUMBER OF WORDS IS ALREADY IN T1 CALL ASGFRE RET ;FAILED TO GET SPACE MOVEM T1,GETDSA ;SAVE THE ADR HRLI T1,(POINT 7,0) ;SET UP A BYTE POINTER HRROI T2,STRING SETZ T3, SOUT ;COPY STRING INTO DESCRIPTION BLOCK MOVE T1,GETDSA ;RETURN ADR OF BLOCK IN T1 RETSKP ;ROUTINE TO ENTER THE COMPLETION DATE TKCD: HLRZ T1,(P1) ;CHECK FOR DATE CHKTYP (TAD) HRRZ T1,(P1) ;GET POINTER TO THE DATE MOVE T1,ANSWER(T1) ;GET DATE CALL GETDAY ;GET THE CORRECTED DATE STOR T1,TKAFD,(P3) ;STORE ACTUAL FINISH DATE IN BLOCK JRST LOGTSK ;LOOP BACK FOR NEXT COMMAND ;ADD DEVELOPER TO TASK DATA BASE TKDV: HLRZ T1,(P1) ;GET TYPE CODE OF USER NAME CHKTYP (USR) HLRZ T1,1(P1) ;GET TYPE CODE OF RATE CHKTYP (FLT) HLRZ T1,2(P1) ;GET TYPE CODE OF HANDICAP CHKTYP (FLT) HRRZ T1,0(P1) ;GET USER NAME STRING HRROI T1,ANSWER+1(T1) HRRZ T2,1(P1) ;GET RATE MOVE T2,ANSWER(T2) HRRZ T3,2(P1) ;GET HANDICAP MOVE T3,ANSWER(T3) LOAD T4,TKDVL,(P3) ;GET ADR OF FIRST ADR IN LIST CALL BLDDEV ;GO BUILD A DEVELOPER BLOCK WARN (,) JUMPN T2,TKDV1 ;IF NOT NEW, DONT ADD TO LIST AGAIN STOR P3,DVBKP,(T1) ;SAVE POINTER TO TASK LOAD T2,TKDVL,(P3) ;GET POINTER TO LIST STOR T2,DVLNK,(T1) ;MAKE THIS BLOCK POINT DOWN THE LIST STOR T1,TKDVL,(P3) ;MAKE TASK POINT TO THIS BLOCK TKDV1: JRST LOGTSK ;DONE ;ADD A DEPENDENCY TO A TASK TKDP: HLRZ T1,0(P1) ;GET TYPE CODE OF PROJECT NAME CHKTYP (KEY) HLRZ T1,1(P1) ;GET TYPE CODE OF TASK NAME CHKTYP (KEY) HRRZ Q2,0(P1) ;GET ADR OF PROJECT BLOCK HRRZ Q3,1(P1) ;GET ADR OF TASK BLOCK MOVE T1,P3 ;NOW FIND OUT IF THIS DEPENDENCY MOVE T2,Q3 ; ALREADY EXISTS CALL FNDDEP ;GO SCAN THE LIST SKIPA ;NOT FOUND JRST TKDP1 ;ALREADY THERE, DO NOTHING MOVEI T1,.DPLEN ;NOW GET SPACE FOR A DEPENDENCY BLOCK MOVEI T2,.TYDEP MOVEI T3,.VNDEP CALL ASGFRE WARN (,) MOVE Q1,T1 ;SAVE THE BLOCK ADDRESS STOR P3,DPTKP,(Q1) ;SAVE POINTER TO DEPENDENT TASK STOR Q3,DPBTK,(Q1) ;SAVE THE ADR OF THE BLOCKING TASK LOAD T1,TKDLP,(P3) ;NOW ADD THIS TO THE DEPENDENT LIST STOR T1,DPDLP,(Q1) ;MAKE THIS BLOCK POINT DOWN LIST STOR Q1,TKDLP,(P3) ;MAKE TASK BLOCK POINT TO THIS BLOCK LOAD T1,TKBLP,(Q3) ;GET HEAD OF BLOCKED TASK LIST STOR T1,DPBLP,(Q1) ;MAKE DEP BLOCK POINT DOWN BLOCKED LIST STOR Q1,TKBLP,(Q3) ;ADD THIS BLOCK TO BLOCKED LIST SETZM NOLOOP ;MAY HAVE JUST CREATED A LOOP TKDP1: JRST LOGTSK ;DONE ;ESTIMATED TASK LENGTH TKEL: LDB T1,[POINT 9,0(P1),17] CHKTYP (NUM) HRRZ T1,(P1) ;GET THE LENGTH FLTR T1,ANSWER(T1) STOR T1,TKELN,(P3) ;SAVE THE TIME LENGTH JRST LOGTSK ;DONE ;FINALIZE THE CHANGES TKFC: JRST LOGLV0 ;GO UPDATE THE DATA BASE ;STARTING DATE TKSD: HLRZ T1,(P1) ;GET TYPE CODE OF DATE CHKTYP (TAD) HRRZ T1,(P1) ;GET DATE MOVE T1,ANSWER(T1) CALL GETDAY ;GET THE CORRECTED DATE STOR T1,TKASD,(P3) ;STORE ACTUAL STARTING DATE JRST LOGTSK ;EXPECTED DATES TKXD: HLRZ T1,(P1) ;CHECK THE CODE CHKTYP (KEY) HRRZ Q1,(P1) ;GET INDEX VALUE HLRZ T1,1(P1) ;GET TYPE CODE OF SECOND ARGUMENT CHKTYP (TAD) HRRZ T1,1(P1) ;GET INDEX OF DATE MOVE T1,ANSWER(T1) ;GET DATE CALL GETDAY ;CONVERT IT TO DAY,,0 XCT [ STOR T1,TKXCD,(P3) STOR T1,TKXSD,(P3)](Q1) JRST LOGTSK ;MINIMUM STARTING DATE TKMD: HLRZ T1,(P1) ;GET TYPE CODE OF DATE CHKTYP (TAD) HRRZ T1,(P1) ;GET DATE MOVE T1,ANSWER(T1) CALL GETDAY ;GET THE CORRECTED DATE STOR T1,TKMSD,(P3) ;STORE MINIMUM STARTING DATE JRST LOGTSK ;TASK DESCRIPTION TKTD: HRROI T1,[ASCIZ/TASK DESCRIPTION: /] CALL GETDSC ;GET A DESCRIPTION WARN (,) LOAD T2,TKDSC,(P3) ;SEE IF THERE ALREADY IS A DESCRIPTION STOR T1,TKDSC,(P3) ;STORE THE NEW DESCRIPTION SKIPE T1,T2 CALL RELFRE ;IF ONE WAS THERE BEFORE, RELEASE IT JRST LOGTSK ;DONE ;TASK TIME-TO-DATE TKTI: LDB T1,[POINT 9,0(P1),17] CHKTYP (NUM) HLRZ T1,1(P1) ;GET TYPE CODE OF DATE CHKTYP (TAD) HRRZ T1,0(P1) ;GET TIME FLTR T1,ANSWER(T1) STOR T1,TKTTD,(P3) ;SAVE TIME TO DATE HRRZ T1,1(P1) ;GET THE DATE MOVE T1,ANSWER(T1) CALL GETDAY ;CONVERT IT TO DAY NUMBER ,, 0 STOR T1,TKTAD,(P3) ;SAVE DATE JRST LOGTSK ;DONE ;MILESTONE TKMI: SETONE TKMIL,(P3) ;MARK THIS TASK AS A MILESTONE JRST LOGTSK ;ALL-DEVELOPERS-REQUIRED TKAR: SETONE TKADR,(P3) ;MARK SPECIAL SCHEDULING JRST LOGTSK ;TASK PREFERENCE VALUE TKPF: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (FLT) HRRZ T1,(P1) MOVE T1,ANSWER(T1) ;GET VALUE STOR T1,TKPRF,(P3) ;SAVE THE PREFERENCE VALUE JRST LOGTSK ;PATH-CHARACTER COMMAND TKPTH: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (FLD) HRRZ T1,(P1) ;GET POINTER TO ANSWER WORD MOVE T1,ANSWER(T1) ;GET FIRST WORD OF ANSWER ROT T1,7 ;GET FIRST CHAR TLNE T1,774000 ;DID USER GIVE MORE THAN ONE CHAR? JRST TKPTH1 ;YES, ERROR ANDI T1,177 ;CLEAR ALL BUT THE CHAR CAIL T1,"0" ;IS IT ALPHA-NUMERIC? CAILE T1,"Z" JRST TKPTH1 CAILE T1,"9" CAIL T1,"A" SKIPA JRST TKPTH1 ;NOT AN ALPHA NUMERIC CHAR STOR T1,TKPTC,(P3) ;STORE THE PATH CHAR JRST LOGTSK ;DONE TKPTH1: WARN (,) JRST UPDTSK ;ADD AN ATTRIBUTE TKAT: TDZA Q3,Q3 ;SHORT ATTRIBUTE TKLA: MOVX Q3,AT%LNG ;ATTRIBUTE IS LONG CALL ATFLD ;GET ATTRIBUTE FROM FIELD WARN (,) MOVE Q1,T1 ;SAVE ADDRESS OF NAME TXNN Q3,AT%LNG ;LONG ATTRIBUTE? AOJA P1,[CALL ATFLD ;GET ATTRIBUTE OUT OF ANSWER BLOCK WARN (,) MOVE Q2,T1 ;SAVE ANSWER JRST TKAT1] ;JOIN COMMON CODE HRROI T1,[ASCIZ "VALUE OF ATTRIBUTE ( WHEN DONE)"] CALL GETDSC ;GET THE TEXT WARN (,) MOVE Q2,T1 ;SAVE ADDRESS OF BLOCK TKAT1: CHKVER .VNTSK,(P3),VERERR MOVE T1,P3 ;ADDRESS OF TASK BLOCK MOVE T2,Q1 ;ATTRIBUTE NAME CALL FNDATR ;FIND THE ATTRIBUTE BLOCK JRST TKAT2 ;NOT FOUND--CREATE A NEW ONE LOAD T2,ATRVL,(T1) ;GET OLD VALUE STOR Q2,ATRVL,(T1) ;STORE NEW VALUE STOR Q3,ATRFL,(T1) ;SAVE FLAGS SKIPE T1,T2 ;FREE UP STORAGE CALL RELFRE MOVE T1,Q1 ;FREE UP NAME CALL RELFRE ; .. JRST LOGTSK ;ALL DONE TKAT2: MOVEI T1,.ATRLN MOVEI T2,.TYATR MOVEI T3,.VNATR CALL ASGFRE WARN (,) SETZRO ATRLK,(T1) ;CLEAR LINK STOR Q2,ATRVL,(T1) ;SAVE ATTRIBUTE VALUE STOR Q1,ATRNM,(T1) ;SAVE ATTRIBUTE NAME STOR Q3,ATRFL,(T1) ;SAVE FLAGS LOAD T2,TKATR,(P3) ;POINTER TO FIRST ATR BLOCK JUMPE T2,[ ;IF NONE YET STOR T1,TKATR,(P3) ;STORE THIS GUY JRST LOGTSK] ;ALL DONE TKAT3: LOAD T3,ATRLK,(T2) ;GET LINK TO NEXT BLOCK JUMPE T3,[ STOR T1,ATRLK,(T2) ;POINT TO NEW BLOCK JRST LOGTSK] ;ALL DONE MOVE T2,T3 ;STEP TO NEXT BLOCK JRST TKAT3 ;AND TRY AGAIN ;SUBROUTINE TO TAKE A FIELD AND STORE IT IN THE DATABASE ;CALL WITH: ; P1/ INDEX TO ANSWER ; CALL ATFLD ; FAILED ; OK--ADDRESS IN T1 ATFLD: SAVEPQ HLRZ T1,(P1) ;MAKE SURE WE HAAVE A FIELD CHKTYP (FLD) HRRZ Q1,(P1) ;POINTER TO ASCIZ STRING ADDI Q1,ANSWER ; .. MOVSI T2,(POINT 7,0) ;BYTE POINTER TO STRING ADD T2,Q1 ; .. MOVEI T1,0 ;LENGTH OF STRING ILDB T3,T2 ;GET A BYTE SKIPE T3 ;DONE? AOJA T1,.-2 ;NO--SCAN STRING SKIPN T1 ;MUST BE SOME RET ;NAME CAN NOT BE NULL IDIVI T1,5 ;CONVERT TO WORDS ADDI T1,1 ;ROUND UP MOVEI T2,.TYDSC ;CREATE A BLOCK MOVEI T3,.VNDSC ;VERSION NUMBER CALL ASGFRE ;ASSIGN THE SPACE RET MOVE Q2,T1 ;SAVE ADDRESS HRLI T1,(POINT 7,0) ;MAKE BYTE POINTER HRRO T2,Q1 ;POINTER TO SOURCE SETZ T3, SOUT MOVE T1,Q2 ;RETURN ADDRESS RETSKP ;SUBROUTINE TO FIND AN ATTRIBUTE ;CALL WITH: ; T1/ ADDRESS OF TASK BLOCK ; T2/ NAME OF ATTRIBUTE ;RETURNS: ; +1 ATTRIBUTE NOT FOUND ; +2 WITH T1/ ADDRESS OF ATTRIBUTE BLOCK ; FNDATR: SAVEQ DMOVE Q1,T1 ;SAVE ARGUMENTS LOAD Q3,TKATR,(Q1) ;FIRST NAME FNATR1: JUMPE Q3,R ;NOT FOUND IF NULL LOAD T1,ATRNM,(Q3) ;THIS ATR'S NAME TLO T1,(POINT 7,0) ;MAKE BYTE POINTER HRRO T2,Q2 ;WHAT WE ARE LOOKING FOR STCMP ;COMPARE JUMPE T1,[MOVE T1,Q3 ;RETURN ADDRESS RETSKP] ;SKIP LOAD Q3,ATRLK,(Q3) ;FOLLOW CHAIN JRST FNATR1 ;LOOP BACK ;THE DELETE COMMAND TKDL: HLRZ T1,(P1) ;CHECK THE TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET THE DISPATCH ADR AOJA P1,(T1) ;DISPATCH ;ROUTINE TO DELETE A DEVELOPER FROM A TASK LIST TKDLD: HLRZ T1,(P1) ;CHECK THE TYPE CODE CHKTYP (USR) HRRZ T1,(P1) ;GET USER NUMBER HRROI T1,ANSWER+1(T1) ;GET POINTER TO NAME STRING LOAD T2,TKDVL,(P3) ;GET THE FIRST ADR IN DEVELOPER LIST CALL DELDEV ;DELETE THIS DEVELOPER WARN (,) STOR T1,TKDVL,(P3) ;STORE THE UPDATED LIST POINTER JRST LOGTSK ;DONE ;ROUTINE TO DELETE A DEPENDENCY TKDDP: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HLRZ T1,1(P1) ;SECOND ARG CHKTYP (KEY) HRRZ T2,1(P1) ;GET ADR OF TASK MOVE T1,P3 ;GET ADR OF THIS TASK CALL FNDDEP ;FIND THE DEPENDENCY BLOCK JRST TKDDP1 ;NOT FOUND CALL RELDEP ;GO RELEASE THE BLOCK TKDDP1: JRST LOGTSK ;DONE ;DELETE COMPLETION DATE TKDCD: SETZRO TKAFD,(P3) ;ZERO COMPLETION DATE JRST LOGTSK ;DELETE ESTIMATED LENGTH TKDEL: SETZRO TKELN,(P3) JRST LOGTSK ;DELETE EXPECTED DATES TKDXD: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (KEY) HRRZ T1,(P1) ;GET THE INDEX VALUE XCT [ SETZRO TKXCD,(P3) SETZRO TKXSD,(P3)](T1) JRST LOGTSK ;DELETE MINIMUM STARTING DATE TKDMD: SETZRO TKMSD,(P3) JRST LOGTSK ;DELETE PREFERENCE VALUE TKDPF: SETZRO TKPRF,(P3) JRST LOGTSK ;DELETE STARTING DATE TKDSD: SETZRO TKASD,(P3) JRST LOGTSK ;DELETE TIME TO DATE TKDTI: SETZRO TKTTD,(P3) SETZRO TKTAD,(P3) JRST LOGTSK ;DELETE PATH-CHARACTER TKDPC: SETZRO TKPTC,(P3) ;ZERO THE PATH CHARACTER JRST LOGTSK ;ROUTINE TO LIST INFO ABOUT A TASK TKLS: CALL SCHWRN ;WARN HIM IF DATES ARE BAD MOVEI T1,.PRIOU ;OUTPUT TASK LIST TO TTY MOVE T2,P3 ;GET ADR OF TASK BLOCK CALL TYPTSK ;GO TYPE OUT THE TASK INFO JRST UPDTSK ;DONE ;ROUTINE TO TYPE OUT A TASK ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ ADR OF TASK BLOCK TYPTSK: SAVEP MOVE P3,T2 ;SAVE THE TASK BLOCK ADR LOAD P2,TKPRJ,(P3) ;SET UP THE PROJECT BLOCK ADR MOVE P1,T1 ;SAVE THE JFN TYPE T1,<&> LOAD T2,PJNAM,(P2) ;GET PROJECT NAME CALL TYPSTR ;TYPE IT TYPE T1, LOAD T2,TKNAM,(P3) ;GET ADR OF TASK NAME CALL TYPSTR TYPE T1,<& TASK DESCRIPTION: > LOAD T2,TKDSC,(P3) ;GET ADR OF TASK DESCRIPTION CALL TYPSTR LOAD T2,TKFLG,(P3) ;GET THE FLAGS TXNE T2,TK%CP ;THIS TASK ON THE CRITICAL PATH? TYPE T1,<& THIS TASK IS ON THE OVERALL CRITICAL PATH> LOAD T2,TKPTC,(P3) ;PATH CHAR? JUMPE T2,TKLS6 TYPE T1,<& PATH CHARACTER: > BOUT TKLS6: LOAD T3,TKPL,(P3) ;GET POINTER TO PATH LIST JUMPE T3,TKLS8 ;IF ANY HRLI T3,(POINT 7,0) ILDB T2,T3 ;GET FIRST CHAR JUMPE T2,TKLS8 ;IF ANY TYPE T1,<& CRITICAL PATHS: > TKLS7: BOUT ;OUTPUT THE PATH THIS TASK IS ON ILDB T2,T3 ;GET NEXT PATH CHAR JUMPE T2,TKLS8 ;IF NONE, THEN DONE TYPE T1,<, > JRST TKLS7 ;LOOP BACK FOR REST OF CHARS ; .. ; .. TKLS8: LOAD T2,TKFLG,(P3) TXNE T2,TK%MIL ;MILESTONE? TYPE T1,<& MILESTONE> LOAD T2,TKFLG,(P3) ;ALL-DEVELOPERS-REQUIRED? TXNE T2,TK%ADR TYPE T1,<& ALL-DEVELOPERS-REQUIRED> LOAD T2,TKPRF,(P3) ;GET THE PREFERENCE VALUE JUMPE T2,TKLS5 ;IF NONE, SKIP IT TYPE T1,<& PREFERENCE VALUE: > CALL TYPFLT TKLS5: LOAD T2,TKSLK,(P3) ;GET THE SLACK CAMN T2,[NOSLAK] ;ANY SET? JRST TKLS9 ;NO TYPE T1,<& SLACK: > MOVEI T3,^D10 ;DECIMAL CALL TYPNUM ;OUTPUT THE SLACK TKLS9: TYPE T1,<& ACTUAL STARTING DATE: > LOAD T2,TKASD,(P3) ;GET STARTING DATE CALL TYPDAT TYPE T1,<& ACTUAL COMPLETION DATE: > LOAD T2,TKAFD,(P3) ;GET COMPLETION DATE CALL TYPDAT TYPE T1,<& MINIMUM STARTING DATE: > LOAD T2,TKMSD,(P3) ;GET MINIMUM START DATE CALL TYPDAT LOAD T2,TKXSD,(P3) ;GET EXPECTED START JUMPE T2,TKLS3 ;IF NONE, SKIP IT TYPE T1,<& EXPECTED STARTING DATE: > CALL TYPDAT TKLS3: LOAD T2,TKXCD,(P3) ;GET EXPECTED COMPLETION DATE JUMPE T2,TKLS4 ;IF NONE, SKIP IT TYPE T1,<& EXPECTED COMPLETION DATE: > CALL TYPDAT TKLS4: TYPE T1,<& ESTIMATED STARTING DATE: > LOAD T2,TKESD,(P3) ;GET ESTIMATED STARTING DATE CALL TYPDAT TYPE T1,<& ESTIMATED COMPLETION DATE: > LOAD T2,TKEFD,(P3) ;GET ESTIMATED COMPLETION DATE CALL TYPDAT TYPE T1,<& ESTIMATED TASK LENGTH (IN DAYS): > LOAD T2,TKELN,(P3) ;GET ESTIMATED TASK LENGTH CALL TYPFLT ; .. ; .. LOAD T2,TKALN,(P3) ;GET ACTUAL LENGTH SKIPE T2 ;IF NOT SET, DONT TYPE IT TYPE T1,<& ACTUAL TASK LENGTH: > LOAD T2,TKALN,(P3) ;GET ACTUAL TASK LENGTH SKIPE T2 CALL TYPFLT LOAD T2,TKTAD,(P3) ;GET DATE JUMPE T2,[TYPE T1,<& TIME SPENT ON TASK: 0> JRST TKLS0] TYPE T1,<& TIME SPENT ON TASK UP TO > LOAD T2,TKTAD,(P3) ;GET CURRENT DATE CALL TYPDAT TYPE T1,< WAS: > LOAD T2,TKTTD,(P3) ;GET TIME TO DATE CALL TYPFLT TKLS0: MOVE T2,P3 ;COPY POINTER CALL TYPATR ;TYPE OUT THE ATTRIBUTES LOAD T2,TKDLP,(P3) ;GET POINTER TO DEPENDENCY LIST JUMPE T2,TKLS1 ;IF NONE, SKIP THIS PART TYPE T1,<& TASKS BLOCKING THIS TASK: > LOAD T2,TKDLP,(P3) ;GET POINTER TO DEPENDENCY LIST CALL TYPDEP ;TYPE OUT DEPENDENCIES TKLS1: LOAD T2,TKBLP,(P3) ;SEE IF THIS TASK IS BLOCKING OTHERS JUMPE T2,TKLS2 ;IF NO, DONT TYPE ANYTHING TYPE T1,<& TASKS BEING BLOCKED BY THIS TASK: > LOAD T2,TKBLP,(P3) CALL TYPBLK ;TYPE OUT NAMES TKLS2: LOAD T2,TKDVL,(P3) ;GET POINTER TO DEVELOPER LIST CALL TYPDEV ;TYPE OUT DEVELOPERS TYPE T1,<&> RET ;DONE ;SUBROUTINE TO TYPE OUT ALL THE ATTRIBUTES FOR A TASK ;CALL WITH: ; T1/ JFN ; T2/ ADDRESS OF TASK BLOCK ; CALL TYPATR ; TYPATR: SAVEQ DMOVE Q1,T1 ;SAVE ARGUMENTS CHKVER .VNTSK,(Q2),R ;NONE IF OLD DATA BASE LOAD Q3,TKATR,(Q2) ;START OF CHAIN TYATR1: JUMPE Q3,R ;EXIT AT END OF CHAIN TYPE Q1,<& > ;LEAD OFF WITH CRLF TAB MOVE T1,Q1 ;COPY JFN LOAD T2,ATRNM,(Q3) ;ATTRIBUTE NAME CALL TYPSTR ;TYPE IT TYPE Q1,<:> ;ADD A COLON LOAD T3,ATRFL,(Q3) ;GET FLAGS MOVE T2,[POINT 7,[ASCIZ " "]] TXNE T3,AT%LNG ;LONG ATTRIBUTE MOVE T2,[POINT 7,[ASCIZ " "]] CALL TYPSTR LOAD T2,ATRVL,(Q3) ;POINTER TO VALUE CALL TYPSTR LOAD Q3,ATRLK,(Q3) ;FOLLOW CHAIN JRST TYATR1 ;LOOP BACK ;ROUTINE TO BUILD A DEVELOPER BLOCK ;ACCEPTS IN T1/ USER NAME STRING POINTER ; T2/ RATE ; T3/ HANDICAP ; T4/ ADR OF FIRST DEVELOPER BLOCK IN THE LIST ; CALL BLDDEV ;RETURNS +1: FAILED ; +2: T1/ ADR OF DEVELOPER BLOCK ; T2/ 0 = NEW BLOCK, -1 = EXISTED BEFORE BLDDEV: SAVEQ STKVAR ,BLDDVC,BLDDVA> MOVEM T2,BLDDVR ;SAVE THE RATE MOVEM T3,BLDDVH ;SAVE THE HANDICAP MOVEM T4,BLDDVA ;SAVE ADR OF FIRST ITEM IN LIST SETOM BLDDVF ;INITIALIZE THE FLAG WORD HRROI T2,BLDDVS ;GET POINTER TO NAME STRING SPACE SETZ T3, SIN ;COPY NAME TO BLDDVS IBP T2 ;CALCULATE THE STRING LENGTH HRRZS T2 SUBI T2,BLDDVS ;INCLUDING THE NULL AOS T2 ;PLUS ONE FOR FIRST WORD MOVEM T2,BLDDVC ;SAVE COUNT HRROI T1,BLDDVS ;GET POINTER TO NAME STRING MOVE T2,BLDDVA ;GET ADR OF FIRST ITEM IN LIST CALL CHKDEV ;SEE IF THIS NAME IS ALREADY IN LIST SKIPA T1,BLDDVC ;NO, GO ADD IT TO LIST JRST BLDDV1 ;YES, JUST GO UPDATE THE DATA MOVEI T2,.TYNAM ;NOW GET A BLOCK FOR THE NAME MOVEI T3,.VNNAM CALL ASGFRE WARN (,) MOVE Q1,T1 ;SAVE THE NAME BLOCK ADDRESS HRLI T1,(POINT 7,0) ;BUILD A STRING POINTER TO THE BLOCK HRROI T2,BLDDVS SETZ T3, SOUT ;COPY NAME STRING INTO NAME BLOCK MOVEI T1,.DVLEN ;NOW GET THE DEVELOPER BLOCK MOVEI T2,.TYDEV MOVEI T3,.VNNAM CALL ASGFRE WARN (,) STOR Q1,DVNAM,(T1) ;STORE NAME STRING SETZM BLDDVF ;MARK THAT A NEW BLOCK WAS MADE ;.. ;.. BLDDV1: MOVE T2,BLDDVR ;GET RATE STOR T2,DVRAT,(T1) ;SAVE RATE MOVE T2,BLDDVH ;GET HANDICAP STOR T2,DVHCR,(T1) ;SAVE HANDICAP MOVE T2,BLDDVF ;RETURN FLAG IN T2 RETSKP ;DONE ;ROUTINE TO SEE IF A NAME IS ON THE LIST ALREADY ;ACCEPTS IN T1/ STRING POINTER TO THE NAME ; T2/ ADR OF FIRST BLOCK IN THE LIST ; CALL CHKDEV ;RETURNS +1: NOT IN LIST ; +2: T1/ ADR OF DEV BLOCK OF MATCHING USER ; T2/ ADR OF PREVIOUS BLOCK OR ; 0 IF THIS WAS THE FIRST ON THE LIST CHKDEV: SAVEQ DMOVE Q1,T1 ;SAVE ARGUMENTS SETZ Q3, ;INIT THE PREVIOUS BLOCK ADR CHKDV1: JUMPE Q2,R ;IF NO MORE IN LIST, THEN NOT FOUND LOAD T1,DVNAM,(Q2) ;GET ADR OF NAME STRING HRLI T1,(POINT 7,0) MOVE T2,Q1 ;GET POINTER TO ARGUMENT STRING STCMP ;COMPARE THEM JUMPE T1,CHKDV2 ;IF A MATCH, GO RETURN ADR OF BLOCK MOVE Q3,Q2 ;SAVE THE ADR OF THE PREVIOUS BLOCK LOAD Q2,DVLNK,(Q2) ;STEP TO NEXT ITEM IN LIST JRST CHKDV1 CHKDV2: MOVE T1,Q2 ;RETURN ADR OF BLOCK IN T1 MOVE T2,Q3 ;GET ADR OF PREVIOUS BLOCK RETSKP ;ROUTINE TO ADD A PROJECT TO THE DATA BASE ;ACCEPTS IN T1/ ADR OF PROJECT NAME STRING ; CALL ADDPRJ ;RETURNS +1: COULD NOT ADD IT ; +2: OK, T1/ ADR OF PROJECT BLOCK ; T2/ NEW ADDRESS OF PROJECT TABLE ADDPRJ: STKVAR MOVEM T1,ADDPRN ;SAVE THE ADR OF THE NAME STRING MOVE T4,0(T1) ;CHECK FOR NULL STRING TLNN T4,774000 RET ;NUL NAME IS NOT ALLOWED MOVE T2,PRJTBL ;GET ADDRESS OF THE TABLE CALL CHKTAB ;SEE IF THIS PROJECT IS ALREADY IN TABLE JRST ADDPR1 ;IT ISNT WARN (,) ADDPR1: HRROI T1,[ASCIZ/PROJECT DESCRIPTION: /] CALL GETDSC ;GET THE DESCRIPTION RET ;FAILED MOVEM T1,ADDPRD ;SAVE ADR OF DESCRIPTION STRING MOVEI T1,TABINC ;NOW CREATE AN EMPTY TASK TABLE MOVEI T2,.TYTKT MOVEI T3,.VNTKT CALL CRTTAB ;GO CREATE THE TASK TABLE RET ;FAILED MOVEM T1,ADDPRT ;SAVE THE TASK TABLE ADR MOVEI T1,.PJLEN ;NOW GET THE PROJECT BLOCK MOVEI T2,.TYPRJ MOVEI T3,.VNPRJ CALL ASGFRE RET MOVEM T1,ADDPRP ;SAVE THE PROJECT BLOCK ADR MOVE T2,ADDPRD ;GET ADR OF DESCRIPTION STOR T2,PJDSC,(T1) ;SAVE IT IN PROJECT BLOCK MOVE T2,ADDPRT ;GET TASK TABLE STOR T2,PJTKT,(T1) ;SAVE IT THE PROJECT BLOCK MOVE T1,ADDPRN ;GET NAME BLOCK ADR MOVE T2,ADDPRP ;GET ADR OF PROJECT BLOCK MOVE T3,PRJTBL ;GET ADR OF PROJECT TABLE CALL ADDNAM ;ADD THIS PROJECT TO THE TABLE RET ;FAILED TO ADD IT MOVEM T1,ADDPPT ;SAVE THE ADR OF THE PROJECT TABLE MOVE T1,ADDPRP ;GET ADR OF PROJECT BLOCK STOR T2,PJNAM,(T1) ;STORE POINTER TO NAME BLOCK MOVE T2,ADDPPT ;GET ADR OF PROJECT BLOCK RETSKP ;ALL DONE ;ROUTINE TO ADD A TASK TO A TASK TABLE ;ACCEPTS IN T1/ ADR OF TASK NAME STRING ; T2/ ADR OF PROJECT BLOCK ; T3/ ADR OF TASK TABLE ; CALL ADDTSK ;RETURNS +1: COULD NOT ADD IT ; +2: OK, T1/ ADR OF TASK BLOCK ; T2/ NEW ADR OF TASK TABLE ADDTSK: STKVAR MOVEM T1,ADDTKN ;SAVE THE ADR OF THE NAME STRING MOVEM T2,ADDTKJ ;SAVE ADR OF PROJECT BLOCK MOVEM T3,ADDTKT ;SAVE THE ADR OF THE TASK TABLE MOVE T4,0(T1) ;CHECK FOR NULL STRING TLNN T4,774000 RET ;NUL NAME IS NOT ALLOWED MOVE T2,ADDTKT ;GET ADR OF TASK TABLE CALL CHKTAB ;SEE IF THIS TASK ALREADY EXISTS JRST ADDTK1 ;IT DOESNT WARN (,) ADDTK1: HRROI T1,[ASCIZ/TASK DESCRIPTION: /] CALL GETDSC ;GET THE DESCRIPTION RET ;FAILED MOVEM T1,ADDTKD ;SAVE ADR OF DESCRIPTION STRING MOVEI T1,.TKLEN ;NOW GET THE TASK BLOCK MOVEI T2,.TYTSK MOVEI T3,.VNTSK CALL ASGFRE RET MOVEM T1,ADDTKP ;SAVE THE TASK BLOCK ADR SETZRO TKDLP,(T1) ;INIT DEPENDENCY LIST POINTER SETZRO TKBLP,(T1) ;AND BLOCKED LIST MOVE T2,ADDTKJ ;GET ADR OF PROJECT BLOCK STOR T2,TKPRJ,(T1) ;SAVE IT IN THE TASK BLOCK MOVE T2,ADDTKD ;GET ADR OF DESCRIPTION STOR T2,TKDSC,(T1) ;SAVE IT IN TASK BLOCK MOVE T1,ADDTKN ;GET NAME BLOCK ADR MOVE T2,ADDTKP ;GET ADR OF TASK BLOCK MOVE T3,ADDTKT ;GET ADR OF TASK TABLE CALL ADDNAM ;ADD THIS TASK TO THE TABLE RET ;FAILED TO ADD IT MOVEM T1,ADDTKT ;SAVE THE ADR OF THE TASK TABLE MOVE T1,ADDTKP ;GET ADR OF TASK BLOCK STOR T2,TKNAM,(T1) ;STORE POINTER TO TASK NAME MOVE T2,ADDTKT ;GET NEW ADR OF TASK TABLE RETSKP ;ALL DONE ;ROUTINE TO OPEN THE DATA BASE FILE ;ACCEPTS IN T1/ POINTER TO THE PROMPT STRING ; CALL OPNFIL ;RETURNS +1: FAILED, ERROR CODE IN T1 ; +2: DONE - T1/ JFN OF DATA BASE FILE ; T2/ JFN OF TRANSACTION LOG FILE OPNFIL: STKVAR > MOVE T2,[GTJBLK,,GTJBLK+1] SETZM GTJBLK ;INITIALIZE GTJFN BLOCK BLT T2,GTJBLK+GTJBLN-1 MOVEM T1,GTJBLK+.GJRTY ;SAVE PROMPT IN ^R BUFFER OPNFI1: PSOUT ;TYPE OUT THE PROMPT PBIN ;GET BYTE FROM TTY CAIN T1,"?" ;DOES HE WANT HELP JRST OPNHLP ;YES--HELP HIM MOVX T1,.PRIIN ;NO--BACKUP JFN BKJFN HRROI T1,[ASCIZ/PANTT/] ;SET UP DEFAULT FILE NAME MOVEM T1,GTJBLK+.GJNAM ; TO BE "PANTT.DATA-BASE" HRROI T1,[ASCIZ/DATA-BASE/] MOVEM T1,GTJBLK+.GJEXT MOVEI T1,GTJBLN-.GJF2-1 ;SET UP EXTENDED GTJFN BLOCK MOVEM T1,GTJBLK+.GJF2 MOVX T1,GJ%CFM!GJ%XTN ;SET UP FLAGS MOVEM T1,GTJBLK+.GJGEN MOVE T1,[.PRIIN,,.PRIOU] MOVEM T1,GTJBLK+.GJSRC ;SET UP TO GET INPUT FROM TTY SETZ T2, ;NO MAIN STRING POINTER MOVEI T1,GTJBLK GTJFN ;GET A JFN ON THE DATA BASE FILE RET ;FAILED MOVEM T1,OPNFIJ ;SAVE THE JFN MOVE T2,[440000,,OF%RD!OF%WR!OF%THW!OF%DUD] OPENF ;OPEN THE DATA BASE FILE JRST [ CAIN T1,OPNX4 ;NEED TO BE ABLE TO WRITE? JRST OPNRED ;YES--TRY TO OPEN READ ONLY MOVEM T1,OPNFIE ;FAILED, SAVE THE ERROR CODE MOVE T1,OPNFIJ ;GET BACK THE JFN RLJFN ;RELEASE IT JFCL MOVE T1,OPNFIE ;GET BACK ERROR CODE RET] HRROI T1,[ASCIZ/TRANSACTION-LOG/] MOVEM T1,GTJBLK+.GJEXT ;SET UP EXT OF TRANSACTION LOG FILE MOVE T1,[377777,,377777] MOVEM T1,GTJBLK+.GJSRC ;GET FILE NAME FROM STRING ONLY HRROI T1,OPNFIS ;NOW GET THE FILE NAME MOVE T2,OPNFIJ ;FROM THE DATA BASE JFN MOVE T3,[111000,,1] ;GET STR:NAME JFNS MOVEI T1,GTJBLK ;NOW GET JFN ON TRANSACTION LOG FILE HRROI T2,OPNFIS GTJFN WARN (,) MOVE T2,T1 ;RETURN JFN IN T2 MOVE T1,OPNFIJ ;AND DATA BASE JFN IN T1 SETZM TRAFLG ;MARK THAT THIS IS FIRST TIME THRU RETSKP ;DONE OPNRED: MOVE T1,OPNFIJ ;GET JFN MOVX T2,OF%RD ;JUST WANT TO READ OPENF ;OPEN THE FILE RET ;FAILED TMSG < % File is READ-ONLY. No changes will update the database. > SETOM RONLY ;FLAG READ ONLY SETOM SLOB ;NO NEED TO DO UFPGS MOVE T1,OPNFIJ ;GET JFN MOVX T2,.NULIO ;NO LOG NEEDED. RETSKP OPNHLP: TMSG < Enter the name of an existing PANTT data base or a new data dase you want to create. > MOVE T1,GTJBLK+.GJRTY ;POINTER TO PROMPT JRST OPNFI1 ;TRY AGAIN ;ROUTINE TO MAP IN THE DATA BASE FILE ;ACCEPTS IN T1/ JFN OF THE DATA BASE FILE ; T2/ PAGE NUMBER OF WHERE TO MAP THE FIRST PAGE ; T3/ MAXIMUM NUMBER OF PAGES TO MAP ; CALL MAPFIL ;RETURNS +1: FILE TOO LARGE TO FIT IN DESIGNATED AREA ; +2: OK MAPFIL: STKVAR MOVEM T1,MAPFLJ ;SAVE THE JFN MOVEM T3,MAPFLC ;SAVE THE COUNT OF PAGES HRLZS T1 ;SET UP FOR PMAP HRLI T2,.FHSLF HRLI T3,(PM%CNT!PM%RD!PM%WR) SKIPE RONLY ;READ ONLY TXC T3,PM%WR!PM%CPY ;YES--CLEAR WRITE AND SET COPY-ON-WRITE PMAP ;MAP IN THE FILE HRR T1,MAPFLC ;GET THE COUNT AGAIN HRL T1,MAPFLJ ;AND THE JFN FFUFP ;SEE IF THERE ARE ANY PAGES AFTER HERE CAIE T1,FFUFX3 ;THE DESIRED ERROR CODE IF NONE LEFT RET ;THERE WERE MORE PAGES IN THE FILE HRLZ T1,MAPFLJ ;SEE IF THE FIRST PAGE OF THE FILE EXISTS RPACS TXNE T2,PA%PEX RETSKP ;FIRST PAGE EXISTS, DO NOT INITIALIZE MOVEI T1,DBORG ;SET UP PAGE 0 WORDS MOVEM T1,DBORG MOVEI T1,NDBPAG ;NUMBER OF PAGES IN DATA BASE MOVEM T1,DBSIZ CALL FSHDR ;NEW DATA BASE FILE, GO INIT FREE POOL MOVEI T1,TABINC ;AND BUILD AN EMPTY PROJECT TABLE MOVEI T2,.TYPJT ;BLOCK TYPE IS "PROJECT TABLE" MOVEI T3,.VNPJT CALL CRTTAB ;CREATE A NEW TABLE ERRMES () MOVEM T1,PRJTBL ;SAVE THE POINTER TO THE PROJECT TABLE HRROI T1,[ASCIZ/[NEW DATA BASE FILE INITIALIZED] /] PSOUT RETSKP ;THE WHOLE FILE IS MAPPED ;ROUTINE TO UNMAP THE DATA BASE FILE UNMAP: SETO T1, ;UNMAP THE WHOLE DATA BASE AREA MOVE T2,[.FHSLF,,DBPAG] MOVE T3,[PM%CNT+NDBPAG] PMAP RET ;RETURN +1 ALWAYS ;ROUTINE TO ADD A NAME TO A TABLE ;THIS ROUTINE WILL EXPAND THE TABLE IF NECESSARY ;ACCEPTS IN T1/ ADDRESS OF THE NAME STRING ; T2/ DATA FOR THE RH OF TABLE ENTRY ; T3/ ADDRESS OF THE TABLE ; CALL ADDNAM ;RETURNS +1: COULD NOT EXPAND THE TABLE ; +2: OK, T1/ NEW ADDRESS OF THE TABLE ; T2/ ADDRESS OF NAME BLOCK ADDNAM: STKVAR MOVEM T1,ADDNMS ;SAVE ADR OF NAME STRING MOVEM T2,ADDNMD ;SAVE THE DATA MOVEM T3,ADDNMT ;SAVE THE ADR OF THE TABLE HRLI T1,(POINT 7,0) ;SET UP A BYTE POINTER TO THE STRING SETZ T2, ;INITIALIZE COUNT OF CHARACTERS IN NAME ADDNM1: ILDB T3,T1 ;COUNT THE CHARACTERS IN THE NAME AOS T2 JUMPN T3,ADDNM1 ;IF NOT AT END, LOOP BACK TILL NULL IDIVI T2,5 ;GET NUMBER OF WORDS IN NAME STRING SKIPE T3 ;ANY REMAINDER? AOS T2 ;YES, COUNT THE EXTRA WORD MOVE T1,T2 ;NOW GET SOME FREE SPACE FOR NAME MOVEI T2,.TYNAM ;THIS IS A NAME BLOCK MOVEI T3,.VNNAM ;VERSION NUMBER CALL ASGFRE ;GET A BLOCK RET ;NO MORE ROOM MOVEM T1,ADDNMF ;REMEMBER ADR OF FREE BLOCK HRLI T1,(POINT 7,0) ;NOW COPY THE NAME STRING INTO THE BLOCK HRRO T2,ADDNMS ;GET A POINTER TO THE STRING SETZ T3, SOUT ;COPY STRING TO FREE BLOCK MOVE T1,ADDNMT ;NOW ADD THE ENTRY TO THE TABLE CALL CHKTBS ;FIRST SEE IF TABLE NEEDS EXPANDING JRST ADDNM2 ;COULD NOT EXPAND THE TABLE MOVEM T1,ADDNMT ;SAVE NEW ADR OF TABLE HRLZ T2,ADDNMF ;SET UP THE ENTRY IN THE TABLE HRR T2,ADDNMD ;ADD IN THE RH OF THE ENTRY TBADD ;ADD THIS ENTRY TO THE TABLE ERJMP ADDNM2 ;FAILED MOVE T1,ADDNMT ;RETURN THE ADDRESS OF THE TABLE MOVE T2,ADDNMF ;GET POINTER TO NAME STRING IN T2 RETSKP ;ALL DONE ADDNM2: MOVE T1,ADDNMF ;RELEASE THE FREE BLOCK CALL RELFRE ;... RET ;GIVE FAILURE RETURN ;ROUTINE TO CHECK IF A TABLE NEEDS EXPANDING ;ACCEPTS IN T1/ THE TABLE ADDRESS ; CALL CHKTBS ;RETURNS +1: FAILED TO EXPAND THE TABLE ; +2: OK, T1/ ADDRESS OF TABLE AFTER EXPANSION CHKTBS: ASUBR HRRZ T2,0(T1) ;GET LENGTH OF THE TABLE HLRZ T3,0(T1) ;GET THE NUMBER OF WORDS USED IN TABLE CAMGE T3,T2 ;ANY MORE ROOM FOR ANOTHER ENTRY? RETSKP ;YES LOAD T3,BLKVER,(T1) ;NO, MUST EXPAND THE TABLE LOAD T2,BLKTYP,(T1) ;GET A BIGGER FREE BLOCK FOR TABLE HRRZ T1,0(T1) ;GET LENGTH OF OLD TABLE ADDI T1,TABINC+1 ;INCREMENT THE SIZE OF THE TABLE CALL ASGFRE ;GET SPACE FOR NEW TABLE RET ;FAILED MOVEM T1,CHKTBN ;SAVE ADR OF NEW TABLE HRLZ T2,CHKTBO ;NOW COPY THE OLD TABLE TO THE NEW HRR T2,CHKTBN MOVE T3,CHKTBO ;GET THE SIZE OF THE OLD TABLE HLRZ T3,0(T3) ;ONLY COPY THE USED ENTRIES ADD T3,CHKTBN ;GET THE ENDING ADDRESS OF THE TABLE BLT T2,0(T3) ;MOVE THE TABLE (INCLUDING THE 1ST WORD) MOVEI T2,TABINC ;NOW UPDATE THE LENGTH OF THE TABLE ADDM T2,0(T1) ;IN THE RH OF THE 1ST WORD OF THE TABLE MOVE T1,CHKTBN ;RETURN THE NEW ADDRESS OF THE TABLE RETSKP ;ROUTINE TO CHECK IF A NAME IS ALREADY IN A TABLE ;ACCEPTS IN T1/ ADR OF NAME STRING ; T2/ ADR OF TABLE ;RETURNS +1: NOT IN TABLE ; +2: IN TABLE, T1/ ADR OF ENTRY IN TABLE CHKTAB: EXCH T1,T2 ;SET UP FOR TBLUK HRLI T2,(POINT 7,0) ;SET UP BYTE POINTER TBLUK ;LOOK UP THIS ENTRY ERJMP R ;NOT IN THE TABLE TXNN T2,TL%EXM ;MUST BE AN EXACT MATCH RET ;NOT IN THE TABLE RETSKP ;ROUTINE TO FIND A DEPENDENCY BLOCK ;ACCEPTS IN T1/ ADR OF DEPENDENT TASK ; T2/ ADR OF BLOCKING TASK ; CALL FNDDEP ;RETURNS +1: NO DEPENDENCY FOUND ; +2: THERE IS A DEPENDENCY, T1/ ADR OF DEPENDENCY BLOCK FNDDEP: LOAD T3,TKDLP,(T1) ;GET ADR OF FIRST DEPENDENT BLOCK FNDDP1: JUMPE T3,R ;IF NO MORE, THEN RETURN +1 LOAD T4,DPBTK,(T3) ;GET ADR OF BLOCKING TASK CAMN T2,T4 ;FOUND A MATCH? JRST FNDDP2 ;YES LOAD T3,DPDLP,(T3) ;STEP DOWN THE LIST JRST FNDDP1 ;LOOP BACK TIL END REACHED FNDDP2: MOVE T1,T3 ;RETURN THE ADR OF THE DEPENDENCY BLOCK RETSKP ;ROUTINE TO CREATE A NEW TABLE ;ACCEPTS IN T1/ INITIAL SIZE OF THE TABLE ; T2/ TYPE CODE OF TABLE ; T3/ VERSION NUMBER OF TABLE ; CALL CRTTAB ;RETURNS +1: FAILED ; +2: OK, T1/ ADR OF TABLE CRTTAB: ASUBR CALL ASGFRE ;GET SPACE FOR THE TABLE RET ;FAILED TO GET SPACE MOVE T2,CRTTBS ;GET SIZE BACK SUBI T2,1 ;SIZE IS NOT INCLUSIVE OF 1ST WORD MOVEM T2,0(T1) ;STORE FIRST WORD IN TABLE RETSKP ;RETURN ;ROUTINE TO SET UP THE PROJECT TABLE ADDRESS IN PDB ;ACCEPTS IN T1/ ADR OF PDB ; CALL SETPRJ ;CALLED FROM PARSE ;RETURNS +1: ALWAYS SETPRJ: MOVE T2,PRJTBL ;GET THE CURRENT ADR OF THE PROJECT TABLE MOVEM T2,.CMDAT(T1) ;STORE IT IN THE PDB RET ;ROUTINE TO SET UP THE ADR OF A TASK BLOCK IN THE PDB SETTSK: MOVE T2,TSKTBL ;GET THE ADR OF THE CURRENT TASK TABLE MOVEM T2,.CMDAT(T1) ;STORE IT IN THE PDB RET ;ROUTINE TO STORE THE ADR OF THE CURRENT TASK TABLE ;ACCEPTS IN T1/ FUNCTION ; T2/ DATA FROM PARSE STOTSK: HRRZ T2,(T2) ;GET THE ADR OF THE PROJECT TABLE LOAD T2,PJTKT,(T2) ;GET THE ADR OF THE TASK TABLE MOVEM T2,TSKTBL ;SAVE IT FOR NEXT LEVEL OF COMMAND RET ;ROUTINE TO GET A YES OR NO ANSWER ;ACCEPTS IN T1/ POINTER TO THE PROMPT STRING ; CALL YESNO ;RETURNS +1: ANSWER IS "NO" ; +2: ANSWER IS "YES" YESNO: STKVAR <> MOVEI T2,YNCT ;GET ADDRESS OF THE YESNO COMMAND TABLE MOVEI T3,YNBLK CALL PARSE ;GO GET THE ANSWER ERRMES CALL COPCMD ;COPY THIS TO CMDBLK HLRZ T1,YNBLK ;GET TYPE CODE CAIE T1,.CMKEY ;IS IT WHAT WE WANT ERRMES HRRZ T1,YNBLK JUMPE T1,R ;0 = NO RETSKP ;1 = YES ;ROUTINE TO GET A STRING FROM THE TTY: ;ACCEPTS IN T1/ POINTER TO THE PROMPT ; T2/ POINTER TO THE STRING TO RECEIVE THE ANSWER ; T3/ NUMBER OF CHARACTERS IN STRING ; CALL GETSTR ;RETURNS +1: FAILED ; +2: OK, T1/ COUNT OF WORDS IN STRING GETSTR: ASUBR PSOUT ;OUTPUT THE PROMPT MOVE T1,GETSTB ;GET THE POINTER TO THE ANSWER STRING MOVE T2,GETSTC ;GET THE CHAR COUNT HRLI T2,(RD%BRK) MOVE T3,GETSTA ;GET THE PROMPT STRING POINTER RDTTY RET TXNN T2,RD%BTM ;ENDED CORRECTLY? RET ;NO MOVEM T1,GETSTA ;SAVE T1 MOVE T1,GETSTB ;GET POINTER TO ANSWER STRING MOVEM T2,GETSTB ;SAVE T2 CALL COPCMD ;COPY THIS COMMAND TO CMDBUF MOVE T1,GETSTA ;RESTORE T1 MOVE T2,GETSTB ;AND T2 MOVEI T3,0 ;OVERWRITE THE TERMINATOR WITH A NULL DPB T3,T1 HRRZS T2 ;GET UPDATED COUNT MOVE T1,GETSTC ;GET THE ORIGINAL COUNT SUB T1,T2 ;GET THE COUNT OF CHARS TYPED IDIVI T1,5 ;GET WORDS USED SKIPE T2 ;PLUS PARTIAL WORD AOS T1 RETSKP ;ROUTINE TO COMPARE TODAY'S EXPECTED DATES WITH REMEMBERED DATES CMPDAT: HLRZ T1,(P1) ;GET TYPE CODE CHKTYP (OFI) ;MAKE SURE IT IS A FILE HRRZ T1,(P1) ;GET JFN MOVE T1,ANSWER(T1) HRRZS Q1,T1 ;RH ONLY MOVE T2,[070000,,OF%WR] ;OPEN FOR WRITE OPENF WARN (,) CALL SCHCHK ; SETOM P1 ;HEADER FLAG MOVE Q3,TSKPTR ;POINTER TO TASK LIST CMPDT1: HRRZ Q2,TSKLST(Q3) ;ADDRESS OF TASK BLOCK LOAD T1,BLKVER,(Q2) ;GET VERSION CAIG T1,1 ;IS IT 2 OR BETTER? JRST VERERR ;NO--VERSION ERROR LOAD T1,TKEFD,(Q2) ;GET DATES LOAD T2,TKESD,(Q2) ; .. LOAD T3,TKRCD,(Q2) ; .. LOAD T4,TKRSD,(Q2) ; .. JUMPE T4,CMPDT4 ;SKIP IF NOTHING REMEMBERED CAME T2,T4 ;SAME STARTING DATE? JRST CMPDT2 ;NO--DUMP OUT MESSAGE CAMN T1,T3 ;SAME ENDING DATE? JRST CMPDT4 ;YES--STEP TO NEXT LINE CMPDT2: AOJN P1,CMPDT3 ;ANY HEADING NEEDED? TYPE Q1,< STARTING DATE ENDING DATE PROJECT/TASK OLD NEW DIF OLD NEW DIF --------------------- --------- --------- ---- --------- --------- ---- > CMPDT3: DMOVE T1,Q1 ;COPY ARGUMENTS CALL PRITNM ;OUTPUT TASK NAME LOAD T2,TKRSD,(Q2) ;GET REMEMBERED START DATE CALL PRIDAT ;OUTPUT THAT TYPE T1,< > LOAD T2,TKESD,(Q2) ;GET NEW ESTIMATE CALL PRIDAT ;OUTPUT THAT TYPE T1,< > LOAD T2,TKRSD,(Q2) ;ORIGINAL DATE LOAD T3,TKESD,(Q2) ;NEW ESTIMATE SUB T2,T3 ;IMPROVEMENT HLRE T2,T2 ;JUST DATE MOVX T3,NO%SGN+NO%LFL+NO%OOV+5B17+^D10 NOUT ERJMP . TYPE T1,< > ; .. ; .. LOAD T2,TKRCD,(Q2) ;GET REMEMBERED END DATE CALL PRIDAT ;OUTPUT THAT TYPE T1,< > LOAD T2,TKEFD,(Q2) ;GET NEW ESTIMATE CALL PRIDAT ;OUTPUT THAT TYPE T1,< > LOAD T2,TKRCD,(Q2) ;ORIGINAL DATE LOAD T3,TKEFD,(Q2) ;NEW ESTIMATE SUB T2,T3 ;IMPROVEMENT HLRE T2,T2 ;JUST DATE MOVX T3,NO%SGN+NO%LFL+NO%OOV+5B17+^D10 NOUT ERJMP . TYPE T1,<&> CMPDT4: AOBJN Q3,CMPDT1 ;LOOP OVER ALL TASKS HRRZ T1,Q1 ;COPY JFN CLOSF ;CLOSE IT WARN (,) JRST LEVEL0 ;DO NEXT COMMAND LPATHC: HLRZ T1,(P1) ;MAKE SURE WE HAVE A FILE CHKTYP (OFI) ; .. HRRZ T1,(P1) ;GET JFN MOVE T1,ANSWER(T1) ; .. HRRZS Q1,T1 ;RH ONLY MOVX T2,7B5+OF%WR OPENF WARN (,) CALL SCHWRN ;OUTPUT WARNING TYPE Q1,< PATH COMPLETION CHAR DATE PROJECT/TASK ---- ---------- ------------ > MOVE Q2,[-200+40,,40] LPTHC1: HRRZ T1,Q1 HRRZ T2,Q2 CALL PTHPRJ AOBJN Q2,LPTHC1 MOVE T1,Q1 ;COPY JFN CLOSF WARN (,) JRST LEVEL0 ;SUBROUTINE TO TYPE OUT THE TASK(S) WITH A GIVEN PATH CHARACTER ; T1/ JFN ; T2/ CHARACTER ; PTHPRJ: SAVEP DMOVE P1,T1 ;SVE ARGUMENTS SKIPN T1,PRJTBL ;ADDRESS OF PROJECT TABLE RET ;SHOULD BE ONE HLRZ P4,(T1) ;GET COUNT JUMPE P4,R ;MAKE SURE THERE ARE SOME MOVN P4,P4 ;MAKE NEGATIVE HRLZ P4,P4 HRRI P4,1(T1) ;AOBJN POINTER TO LIST PTPRJ1: MOVE T1,P1 HRRZ T2,(P4) MOVE T3,P2 ;PATH CHARACTER CALL PTHTSK AOBJN P4,PTPRJ1 RET ;HERE TO CHECK ONE PROJECT ; T1/ JFN T2/ PROJECT BLOCK T3/ PATH CHARACTER ; PTHTSK: SAVEP DMOVE P1,T1 ;SAVE ARGUMENTS MOVE P4,T3 ;PATH CHAR LOAD T1,PJTKT,(P2) ;ADDRESS OF TASK TABLE HLRZ P3,(T1) ;GET TASK COUNT JUMPE P3,R ;SKIP IF NONE MOVN P3,P3 ;MAKE NEGATIVE HRLZ P3,P3 ;PUT IN LEFT HALF HRRI P3,1(T1) ;MAKE AOBJN POINTER PTHTK1: HRRZ P5,(P3) ;POINTER TO TASK BLOCK LOAD T1,TKPTC,(P5) ;GET PATH CHARACTER CAME T1,P4 ;MATCH? JRST PTHTK2 ;NO--SKIP THIS TASK MOVE T1,P1 ;GET JFN MOVE T2,P4 ;PATH CHARACTER BOUT TYPE T1,< > ;ADD A TAB LOAD T2,TKEFD,(P5) ;GET THE DATE CALL TYPDAT ;TYPE IT OUT TYPE T1,< > ;ADD A TAB LOAD T2,TKPRJ,(P5) ;PROJECT BLOCK LOAD T2,PJNAM,(T2) ;NAME STRING HRLI T2,(POINT 7,0) ;MAKE BYTE POINTER CALL TYPSTR TYPE P1, LOAD T2,TKNAM,(P5) ;TASK NAME MOVE T1,P1 ;COPY JFN CALL TYPSTR TYPE P1,<&> ;ADD CRLF PTHTK2: AOBJN P3,PTHTK1 ;LOOP OVER ALL TASKS RET ;LIST A GIVEN CRITICAL PATH OUTCP: HLRZ T1,(P1) ;GET THE TYPE CODE CHKTYP (KEY) ;MUST BE A PROJECT ADDI P1,1 ;STEP TO TASK BLOCK ADDRESS HLRZ T1,(P1) ;GET THE NEXT TYPE CODE CHKTYP (KEY) ;MUST BE A KEYWORD HRRZ P2,(P1) ;ADDRESS OF TASK BLOCK ADDI P1,1 ;BUMP P1 HLRZ T1,(P1) ;GET TYPE CHKTYP (OFI) ;MUST BE OUTPUT FILE HRRZ P1,(P1) ;GET THE JFN HRRZ P1,ANSWER(P1) ; .. MOVE T1,P1 ;SETUP FOR OPENF MOVX T2,7B5+OF%WR ;WANT TO WRITE OPENF WARN (,) CALL SCHWRN ;INDICATE DATES MAY BE WRONG DMOVE T1,P1 ;COPY JFN AND TASK MOVEI T3,0 ;PRESET LEVEL CALL CPLOOK ;FOLLOW THE CHAIN MOVE T1,P1 ;GET JFN CLOSF WARN (,) JRST LEVEL0 ;ALL DONE ;SUBROUTINE TO FOLLOW THE CRITICAL PATH ;CALL WITH: ; T1/ JFN ; T2/ TASK BLOCK ADDRESS ; T3/ LEVEL # ; CALL CPLOOK ; RETURN HERE CPLOOK: ASUBR SAVEP MOVE T1,CPJFN ;GET JFN MOVEI T2," " ;GET A SPACE SKIPE T3,CPLVL ;GET LEVEL -- NO OUTPUT IF ZERO BOUT ;TYPE THE SPACE SOJG T3,.-1 ;TYPE "N" SPACES MOVE P1,CPJFN ;COPY JFN MOVE P2,CPTSK ;TASK BLOCK ADDRESS LOAD T2,TKPRJ,(P2) ;PROJECT BLOCK LOAD T2,PJNAM,(T2) ;NAME STRING HRLI T2,(POINT 7,0) ;MAKE BYTE POINTER CALL TYPSTR TYPE P1, LOAD T2,TKNAM,(P2) ;TASK NAME MOVE T1,P1 ;COPY JFN CALL TYPSTR LOAD T2,TKESD,(P2) LOAD T3,TKEFD,(P2) CAMN T2,T3 JRST [TYPE P1,< ON:> JRST CPLK0] TYPE P1,< START: > LOAD T2,TKESD,(P2) ;START DATE CALL PRIDAT ;PRINT IT TYPE P1,< END: > CPLK0: LOAD T2,TKEFD,(P2) ;GET ENDING DATE CALL PRIDAT ;PRINT THAT TYPE P1,<&> ;ADD CRLF LOAD P1,TKDLP,(P2) ;GET BLOCKING LIST POINTER JUMPE P1,R ;RETURN IF TOP-LEVEL TASK MOVEI P3,0 ;LATEST TASK TO START CPLK1: LOAD T2,DPBTK,(P1) ;GET BLOCKING TASK LOAD T3,TKEFD,(T2) ;GET BLOCKING FINISH DATE CAMGE P3,T3 ;NEW LATEST TASK? MOVE P3,T3 ;YES--REMEMBER THE DATE LOAD P1,DPDLP,(P1) ;GET NEXT TASK JUMPN P1,CPLK1 ;LOOP OVER ALL TASKS LOAD P1,TKDLP,(P2) ;GET POINTER CPLK1A: LOAD T2,DPBTK,(P1) ;ADDRESS OF BLOCKING TASK LOAD T3,TKEFD,(T2) ; .. CAMGE T3,P3 ;ON CRITICAL PATH? JRST CPLK2 ;NO--LOOK AT NEXT TASK MOVE T1,CPJFN ;GET JFN MOVE T3,CPLVL ;GET LEVEL ADDI T3,1 ;BUMP LEVEL CALL CPLOOK ;FOLLOW THE PATH CPLK2: LOAD P1,DPDLP,(P1) ;STEP TO NEXT TASK JUMPN P1,CPLK1A ;JUMP IF MORE TASKS RET ;END OF PATH ;ROUTINE TO INIT THE TRANSACTION AREA INITRA: MOVE T1,[POINT 7,CMDBUF] MOVEM T1,CMDPTR ;INITIALIZE THE POINTER TO CMDBUF RET ;ROUTINE TO COPY A COMMAND TO THE TRANSACTION LOG BUFFER (CMDBUF) ;ACCEPTS IN T1/ POINTER TO COMMAND ; CALL COPCMD ;RETURNS +1: ALWAYS COPCMD: MOVE T2,CMDPTR ;GET POINTER TO COMMAND BUFFER AREA SETZ T3, SIN ;COPY COMMAND INTO BUFFER MOVEM T2,CMDPTR ;UPDATE POINTER TO END OF COMMAND RET ;DONE ;ROUTINE TO UPDATE THE DATA BASE UPDDB: STKVAR <,UPDDBU> SKIPE SLOB ;WANT SAFE MODE? JRST UPDDB3 ;NO--SKIP THE UPDATE SKIPN T1,TLJFN ;GET TRANSACTION JFN JRST UPDDB2 ;NONE MOVE T2,[070000,,OF%APP] ;OPEN IT FOR APPEND OPENF WARN (,) SKIPE TRAFLG ;FIRST TIME THRU? JRST UPDDB1 ;NO, DONT PUT IN TIME STAMP SETO T1, ;YES, GET USER NAME HRROI T2,UPDDBU MOVEI T3,.JIUNO ;GET USER NUMBER GETJI JRST UPDDB1 ;FAILED HRROI T1,UPDDBS ;NOW BUILD TIME STAMP HRROI T2,[ASCIZ/ ; UPDATED BY /] SETZ T3, SOUT MOVE T2,UPDDBU ;NAOW ADD IN USER NAME DIRST JRST UPDDB1 ;FAILED HRROI T2,[ASCIZ/ ON /] SOUT SETO T2, ;AND THEN THE CURENT DATE ODTIM HRROI T2,[ASCIZ/ /] SOUT MOVE T1,TLJFN ;AND NOW COPY IT TO TLOG FILE HRROI T2,UPDDBS SOUT SETOM TRAFLG ;MARK THAT NO LONGER FIRST TIME THRU UPDDB1: MOVE T1,TLJFN ;GET TLOG JFN MOVE T2,[POINT 7,CMDBUF] SETZ T3, SOUT ;COPY COMMAND TO TLOG TXO T1,CO%NRJ ;DONT RELEASE THE JFN CLOSF ;CLOSE THE TLOG FILE JFCL UPDDB2: HRLZ T1,DBJFN ;NOW UPDATE THE DATA BASE MOVEI T2,NDBPAG UFPGS WARN (,) UPDDB3: SETZM SKDFLG ;MARK THAT SCHEDULING MUST BE DONE RET ;DONE ;TYPE OUT ROUTINES USED BY THE "LIST" COMMANDS ;ROUTINE TO TYPE OUT THE DEVELOPERS ON A TASK/PROJECT ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ ADR OF FIRST BLOCK IN LIST ;RETURNS +1: ALWAYS TYPDEV: SAVET SAVEQ MOVE Q1,T2 ;SAVE THE ADR OF THE BLOCK JUMPE Q1,R ;IF 0, THEN DONE TYPE T1,<& DEVELOPER RATE HANDICAP> TYPDV1: TYPE T1,<& > LOAD T2,DVNAM,(Q1) ;GET NAME OF DEVELOPER CALL TYPSTR MOVEI T2,^D28 ;SKIP TO COLUMN 20 CALL TYPSPA LOAD T2,DVRAT,(Q1) ;GET RATE CALL TYPFLT MOVEI T2,^D38 ;SKIP TO COLUMN 30 CALL TYPSPA LOAD T2,DVHCR,(Q1) ;GET HANDICAP CALL TYPFLT LOAD Q1,DVLNK,(Q1) ;STEP TO NEXT DEVELOPER BLOCK JUMPN Q1,TYPDV1 ;LOOP BACK FOR REST OF DEVELOPERS RET ;ROUTINE TO TYPE OUT THE DEPENDENCY LIST OR BLOCKED LIST ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ ADR OF FIRST ITEM IN LIST ; CALL TYPDEP OR CALL TYPBLK ;RETURNS +1: ALWAYS TYPDEP: SAVET MOVEI T3,0 ;DEPENDENCY LIST JRST TYPBL0 TYPBLK: SAVET MOVEI T3,1 ;BLOCKED LIST TYPBL0: SAVEQ DMOVE Q1,T2 ;SAVE ARGUMENTS IN Q1, Q2 TYPBL1: JUMPE Q1,R ;IF NO MORE, RETURN TYPE T1,<& > XCT [ LOAD Q3,DPBTK,(Q1) LOAD Q3,DPTKP,(Q1)](Q2) LOAD T2,TKPRJ,(Q3) ;GET PROJECT BLOCK ADR LOAD T2,PJNAM,(T2) ;GET ADR OF PROJECT NAME CALL TYPSTR ;TYPE OUT THE PROJECT NAME TYPE T1, LOAD T2,TKNAM,(Q3) ;GET ADR OF TASK NAME BLOCK CALL TYPSTR ;TYPE PRJ/TASK JUMPN Q2,TYPBL2 ;ONLY INCLUDE ON BLOCKING ;TASK LIST TYPE T1,< > LOAD T2,TKEFD,(Q3) ;GET DONE DATE CALL TYPDAT TYPBL2: XCT [ LOAD Q1,DPDLP,(Q1) LOAD Q1,DPBLP,(Q1)](Q2) JUMPE Q1,R ;IF NO MORE, RETURN JRST TYPBL1 ;GO TYPE OUT REST OF LIST ;ROUTINE TO OUTPUT A CONTROL FILE ;ACCEPTS IN T1/ JFN OUTCTL: SAVEQ STKVAR MOVEM T1,OUTCTJ ;SAVE THE JFN HRROI T2,[ASCIZ/ RENAME /] SETZ T3, SOUT ;RENAME THE DATA BASE FILE FIRST MOVE T2,DBJFN ;GET DATA BASE NAME MOVE T3,[1B8] JFNS HRROI T2,[ASCIZ/.DATA-BASE.* /] SETZ T3, SOUT MOVE T2,DBJFN ;RENAME IT TO .BACKUP-DATA-BASE MOVE T3,[1B8] JFNS HRROI T2,[ASCIZ/.BACKUP-DATA-BASE PANTT /] SETZ T3, SOUT ;START THE PROGRAM MOVE T2,DBJFN ;GET NAME OF DATA BASE FILE MOVE T3,[1B8] JFNS ;OUTPUT DATABASE NAME HRROI T2,[ASCIZ/ SET SLOPPY-BUT-FAST-UPDATE-MODE /] SETZ T3, SOUT HRROI T2,[ASCIZ / SET SCHEDULE-DATE /] SETZ T3, SKIPE SKDITD SOUT MOVE T2,SKDITD MOVX T3,OT%NTM SKIPE SKDITD CALL OUTDAT HRROI T2,[ASCIZ " "] SETZ T3, SOUT CALL OUTHOL ;OUTPUT THE HOLIDAYS MOVE T1,OUTCTJ ;GET THE JFN MOVE T2,DEVTBP ;GET POINTER TO DEVELOPER LIST CALL OUTADV ;OUTPUT THE DEVELOPERS SKIPN T1,PRJTBL ;NOW DO THE PROJECTS JRST OUTCT3 ;NONE HLRZ Q1,(T1) ;GET COUNT MOVNS Q1 JUMPE Q1,OUTCT3 ;CHECK IF ANY HRLZS Q1 HRRI Q1,1(T1) ;SET UP POINTER TO THE PROJECT LIST OUTCT1: MOVE T1,OUTCTJ ;GET THE JFN HRRZ T2,0(Q1) ;GET THE NEXT PROJECT CALL OUTPRJ ;OUTPUT THE PROJECT AOBJN Q1,OUTCT1 ;LOOP BACK FOR ALL PROJECTS SKIPN T1,PRJTBL ;NOW DO THE DEPENDENCIES JRST OUTCT3 ;NONE HLRZ Q1,(T1) ;GET COUNT MOVNS Q1 JUMPE Q1,OUTCT3 ;CHECK IF ANY HRLZS Q1 HRRI Q1,1(T1) ;SET UP POINTER TO THE PROJECT LIST OUTCT2: MOVE T1,OUTCTJ ;GET THE JFN HRRZ T2,0(Q1) ;GET THE NEXT PROJECT CALL OUTPDP ;OUTPUT THE PROJECT DEPENDENCIES AOBJN Q1,OUTCT2 ;LOOP BACK FOR ALL PROJECTS OUTCT3: MOVE T1,OUTCTJ ;GET THE JFN HRROI T2,[ASCIZ/EXIT /] SETZ T3, SOUT ;EXIT RET ;DONE ;ROUTINE TO OUTPUT THE HOLIDAYS ;ACCEPTS IN T1/ JFN OUTHOL: SAVEQ MOVEM T1,Q1 SKIPN T2,HOLTAB ;IS THERE A HOLIDAY LIST? RET ;NO LOAD Q2,HOLUSE,(T2) ;YES, GET NUMBER OF ENTRIES JUMPE Q2,R ;CHECK IF ANY MOVNS Q2 ;SET UP POINTER HRLZS Q2 HRRI Q2,1(T2) OUTHO1: MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/SET HOLIDAY /] SETZ T3, SOUT MOVE T2,(Q2) ;GET THE NEXT DATE CALL OUTDAT ;OUTPUT IT MOVE T1,Q1 HRROI T2,[ASCIZ/ /] SETZ T3, SOUT AOBJN Q2,OUTHO1 ;LOOP BACK FOR REST OF DATES RET ;DONE ;ROUTINE TO OUTPUT A PROJECT ;ACCEPTS IN T1/ JFN ; T2/ ADR OF PROJECT BLOCK OUTPRJ: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS HRROI T2,[ASCIZ/ADD PROJECT /] SETZ T3, SOUT LOAD T2,PJNAM,(Q2) ;GET THE PROJECT NAME HRLI T2,(POINT 7,0) SOUT ;OUTPUT THE PROJECT NAME HRROI T2,[ASCIZ/ /] SOUT LOAD T2,PJDSC,(Q2) ;NOW OUTPUT THE DESCRIPTION HRLI T2,(POINT 7,0) SOUT MOVEI T2,33 ;FOLLOWED BY AN ALTMODE BOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,PJDVL,(Q2) ;OUTPUT THE DEVELOPER LIST CALL OUTDEV MOVE T1,Q1 ;GET THE JFN LOAD T2,PJPRF,(Q2) ;GET THE PREFERENCE VALUE CALL OUTPRF MOVE T1,Q1 HRROI T2,[ASCIZ/FINISHED /] SETZ T3, SOUT LOAD T2,PJTKT,(Q2) ;GET ADR OF TASK LIST HLRZ Q3,(T2) ;GET COUNT OF TASKS MOVNS Q3 JUMPE Q3,OUTPR2 ;ANY TASKS? HRLZS Q3 HRRI Q3,1(T2) ;BUILD POINTER TO TASK LIST OUTPR1: MOVE T1,Q1 ;GET THE JFN HRRZ T2,0(Q3) ;GET TASK ADR CALL OUTTSK ;OUTPUT THE TASK AOBJN Q3,OUTPR1 ;LOOP BACK FOR ALL TASKS OUTPR2: RET ;ROUTINE TO OUTPUT THE DEPENDENCIES ;ACCEPTS IN T1/ JFN ; T2/ PROJECT ADR OUTPDP: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS LOAD T2,PJTKT,(Q2) ;GET ADR OF TASK LIST HLRZ Q3,(T2) ;GET COUNT OF TASKS MOVNS Q3 JUMPE Q3,OUTPD2 ;ANY TASKS? HRLZS Q3 HRRI Q3,1(T2) ;BUILD POINTER TO TASK LIST OUTPD1: MOVE T1,Q1 ;GET THE JFN HRRZ T2,0(Q3) ;GET TASK ADR CALL OUTTDP ;OUTPUT THE TASK DEPENDENCIES AOBJN Q3,OUTPD1 ;LOOP BACK FOR ALL TASKS OUTPD2: RET ;ROUTINE TO OUTPUT TASK DEPENDENCIES ;ACCEPTS IN T1/ JFN ; T2/ TASK ADR OUTTDP: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS LOAD T2,TKDLP,(Q2) ;IS THERE A DEPENDENCY LIST? JUMPE T2,R ;... HRROI T2,[ASCIZ/UPDATE (PROJECT) /] SETZ T3, SOUT LOAD T2,TKPRJ,(Q2) ;GET PROJECT NAME LOAD T2,PJNAM,(T2) HRLI T2,(POINT 7,0) ;SET UP POINTER TO PROJECT NAME SOUT HRROI T2,[ASCIZ/ (TASK) /] SOUT LOAD T2,TKNAM,(Q2) ;GET TASK NAME HRLI T2,(POINT 7,0) SOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,TKDLP,(Q2) ;GET POINTER TO THE DEPENDENCY LIST CALL OUTDEP ;OUTPUT THE DEPENDENCIES MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/FINISHED /] SETZ T3, SOUT RET ;DONE ;ROUTINE TO OUTPUT A DEVELOPER LIST ;ACCEPTS IN T1/ JFN ; T2/ DEVELOPER LIST POINTER OUTADV: SAVEQ SETOM Q3 ;MARK THIS AS NEEDING AN "ADD" JRST OUTDV0 OUTDEV: SAVEQ SETZ Q3, ;NO "ADD" NEEDED OUTDV0: DMOVE Q1,T1 ;SAVE THE ARGS OUTDV1: JUMPE Q2,R ;ANY THERE? MOVE T1,Q1 ;YES, GET THE JFN HRROI T2,[ASCIZ/ADD /] SETZ T3, SKIPE Q3 ;NEED AN "ADD"? SOUT ;YES HRROI T2,[ASCIZ/DEVELOPER /] SETZ T3, SOUT LOAD T2,DVNAM,(Q2) ;GET DEVELOPER NAME HRLI T2,(POINT 7,0) SOUT HRROI T2,[ASCIZ/ (RATE) /] SOUT LOAD T2,DVRAT,(Q2) ;GET THE RATE FLOUT JFCL HRROI T2,[ASCIZ/ (HANDICAP) /] SOUT LOAD T2,DVHCR,(Q2) ;GET THE HANDICAP FLOUT JFCL HRROI T2,[ASCIZ/ /] SOUT LOAD Q2,DVLNK,(Q2) ;STEP TO THE NEXT IN THE LIST JRST OUTDV1 ;LOOP BACK FOR ALL DEVELOPERS ;ROUTINE TO OUTPUT THE PREFERENCE VALUE ;ACCEPTS IN T1/ JFN ; T2/ PREFERENCE VALUE OUTPRF: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS HRROI T2,[ASCIZ/PREFERENCE-VALUE /] SETZ T3, SOUT MOVE T2,Q2 ;GET THE VALUE FLOUT JFCL HRROI T2,[ASCIZ/ /] SOUT RET ;ROUTINE TO OUTPUT A TASK ;ACCEPTS IN T1/ JFN ; T2/ TASK ADR OUTTSK: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS HRROI T2,[ASCIZ/ADD TASK /] SETZ T3, SOUT LOAD T2,TKNAM,(Q2) ;GET THE TASK NAME HRLI T2,(POINT 7,0) SOUT HRROI T2,[ASCIZ/ (TO PROJECT) /] SOUT LOAD T2,TKPRJ,(Q2) ;GET PROJECT BLOCK LOAD T2,PJNAM,(T2) ;GET PROJECT NAME HRLI T2,(POINT 7,0) SOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,TKDSC,(Q2) ;GET THE DESCRIPTION HRLI T2,(POINT 7,0) SOUT MOVEI T2,33 ;FOLLOWED WITH AN ALTMODE BOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,TKASD,(Q2) ;GET THE STARTING DATE JUMPE T2,OUTTS1 ;IF ANY HRROI T2,[ASCIZ/STARTING-DATE /] SETZ T3, SOUT LOAD T2,TKASD,(Q2) ;GET STARTING DATE CALL OUTDAT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS1: LOAD T2,TKAFD,(Q2) ;GET THE COMPLETION DATE JUMPE T2,OUTTS2 ;IF ANY HRROI T2,[ASCIZ/COMPLETION-DATE /] SETZ T3, SOUT LOAD T2,TKAFD,(Q2) ;GET DATE AGAIN CALL OUTDAT ;OUTPUT IT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS2: HRROI T2,[ASCIZ/ESTIMATED-PROJECT-LENGTH /] SETZ T3, SOUT LOAD T2,TKELN,(Q2) ;GET THE ESTIMATED LENGTH FLOUT JFCL HRROI T2,[ASCIZ/ /] SETZ T3, SOUT LOAD T2,TKTAD,(Q2) ;TIME TO DATE? JUMPE T2,OUTTS3 HRROI T2,[ASCIZ/TIME-TO-DATE /] SETZ T3, SOUT LOAD T2,TKTTD,(Q2) ;GET TIME FLOUT JFCL HRROI T2,[ASCIZ/ (AT DATE) /] SETZ T3, SOUT LOAD T2,TKTAD,(Q2) ;GET DATE CALL OUTDAT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS3: MOVE T1,Q1 ;COPY JFN MOVE T2,Q2 ;COPY TASK BLOCK ADDRESS CALL OUTATR ;OUTPUT ATTRIBUTES MOVE T1,Q1 ;GET JFN LOAD T2,TKDVL,(Q2) ;GET DEVELOPER LIST CALL OUTDEV ;OUTPUT THE DEVELOPERS MOVE T1,Q1 ;GET THE JFN LOAD T2,TKXSD,(Q2) ;GET EXPECTED STARTING DATE JUMPE T2,OUTTS4 ;IF ANY HRROI T2,[ASCIZ/EXPECTED STARTING-DATE /] SETZ T3, SOUT LOAD T2,TKXSD,(Q2) ;GET STARTING DATE AGAIN CALL OUTDAT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS4: MOVE T1,Q1 ;GET THE JFN LOAD T2,TKXCD,(Q2) ;GET THE EXPECTED COMPLETION DATE JUMPE T2,OUTTS5 ;IF ANY HRROI T2,[ASCIZ/EXPECTED COMPLETION-DATE /] SETZ T3, SOUT LOAD T2,TKXCD,(Q2) ;GET DATE AGAIN CALL OUTDAT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS5: MOVE T1,Q1 ;GET THE JFN LOAD T2,TKMSD,(Q2) ;GET THE MINIMUM STARTING DATE JUMPE T2,OUTTS6 ;IF ANY HRROI T2,[ASCIZ/MINIMUM-STARTING-DATE /] SETZ T3, SOUT LOAD T2,TKMSD,(Q2) ;GET THE DATE AGAIN CALL OUTDAT HRROI T2,[ASCIZ/ /] SETZ T3, SOUT OUTTS6: MOVE T1,Q1 ;GET THE JFN LOAD T2,TKPRF,(Q2) ;GET THE PREFERENCE VALUE CALL OUTPRF MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/MILESTONE /] SETZ T3, LOAD T4,TKFLG,(Q2) ;GET THE FLAGS TXNE T4,TK%MIL ;IS THIS A MILESTONE? SOUT ;YES, SAY SO MOVE T1,Q1 ;GET THE JFN HRROI T2,[ASCIZ/ALL-DEVELOPERS-REQUIRED /] SETZ T3, LOAD T4,TKFLG,(Q2) ;GET THE FLAGS TXNE T4,TK%ADR ;IS THIS ALL-DEVELOPERS-REQUIRED? SOUT ;YES, SAY SO LOAD T2,TKPTC,(Q2) ;GET THE PATH CHARACTER JUMPE T2,OUTTS7 ;IF ANY HRROI T2,[ASCIZ/PATH-CHARACTER /] SETZ T3, SOUT LOAD T2,TKPTC,(Q2) ;GET THE PATH CHARACTER BOUT HRROI T2,[ASCIZ/ /] SOUT OUTTS7: HRROI T2,[ASCIZ/FINISHED /] SETZ T3, SOUT RET ;DONE ;ROUTINE TO OUTPUT A DEPENDENCY LIST ;ACCEPTS IN T1/ JFN ; T2/ DEPENDENCY LIST OUTDEP: SAVEQ OUTDP1: DMOVE Q1,T1 ;SAVE THE ARGS JUMPE T2,R ;IF NO LIST, THEN DONE HRROI T2,[ASCIZ/DEPENDENCY /] SETZ T3, SOUT LOAD Q3,DPBTK,(Q2) ;GET TASK ADR OF BLOCKING TASK LOAD T2,TKPRJ,(Q3) ;GET ITS PROJECT LOAD T2,PJNAM,(T2) ;AND THE PROJECT NAME HRLI T2,(POINT 7,0) SETZ T3, SOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,TKNAM,(Q3) ;GET THE TASK NAME HRLI T2,(POINT 7,0) SOUT HRROI T2,[ASCIZ/ /] SOUT LOAD T2,DPDLP,(Q2) ;STEP TO THE NEXT NAME IN THE LIST JRST OUTDP1 ;LOOP BACK TIL THE LIST IS DONE ;SUBROUTINE TO OUTPUT ALL THE ATTRIBUTES FOR A TASK TO CONTROL FILE ;CALL WITH: ; T1/ JFN ; T2/ ADDRESS OF TASK BLOCK ; CALL OUTATR ; OUTATR: SAVEQ DMOVE Q1,T1 ;SAVE ARGUMENTS CHKVER .VNTSK,(Q2),R ;NONE IF OLD DATA BASE LOAD Q3,TKATR,(Q2) ;START OF CHAIN OUATR1: JUMPE Q3,R ;EXIT AT END OF CHAIN MOVE T1,Q1 ;COPY JFN LOAD T3,ATRFL,(Q3) ;GET FLAGS MOVE T2,[POINT 7,[ASCIZ "ATTRIBUTE "]] TXNE T3,AT%LNG ;LONG ATTRIBUTE MOVE T2,[POINT 7,[ASCIZ "LONG-ATTRIBUTE "]] CALL TYPSTR LOAD T2,ATRNM,(Q3) ;ATTRIBUTE NAME CALL TYPSTR ;TYPE IT MOVE T2,[POINT 7,[ASCIZ " "]] TXNE T3,AT%LNG ;LONG ATTRIBUTE MOVE T2,[POINT 7,[ASCIZ " "]] CALL TYPSTR LOAD T2,ATRVL,(Q3) ;POINTER TO VALUE CALL TYPSTR MOVE T2,[POINT 7,[BYTE (7)33,15,12,0]] TXNE T3,AT%LNG ;LONG ATTRIBUTE? CALL TYPSTR ;YES--ADD ESCAPE TYPE Q1,<&> ;ADD A CRLF LOAD Q3,ATRLK,(Q3) ;FOLLOW CHAIN JRST OUATR1 ;LOOP BACK ;ROUTINE TO DELETE A DELVELOPER BLOCK ;ACCEPTS IN T1/ USER NAME STRING POINTER ; T2/ ADR OF FIRST BLOCK IN LIST ; CALL DELDEV ;RETURNS +1: FAILED TO FIND THE BLOCK ; +2: T1/ UPDATED ADR OF FIRST BLOCK IN LIST DELDEV: STKVAR <,DELDVL,DELDVT> MOVEM T2,DELDVL ;SAVE ADR OF LIST HRROI T2,DELDVS ;COPY NAME STRING INTO STKVAR SETZ T3, SIN HRROI T1,DELDVS ;GET POINTER TO NAME STRING MOVE T2,DELDVL ;GET ADR OF FIRST BLOCK IN LIST CALL CHKDEV ;GO FIND THE BLOCK RET ;NOT FOUND MOVEM T1,DELDVT ;SAVE ADR OF TASK BLOCK JUMPE T2,DELDV2 ;IS THIS THE FIRST ONE ON THE LIST LOAD T3,DVLNK,(T1) ;NO, REMOVE IT FROM THE LIST STOR T3,DVLNK,(T2) ;MAKE PREVIOUS BLOCK POINT TO NEXT ONE DELDV1: LOAD T1,DVNAM,(T1) ;GET ADR OF NAME STRING CALL RELFRE ;RELEASE IT MOVE T1,DELDVT ;GET ADR OF TASK BLOCK AGAIN CALL RELFRE ;RELEASE THE DEVELOPER BLOCK MOVE T1,DELDVL ;RETURN THE UPDATED START OF LIST RETSKP DELDV2: LOAD T2,DVLNK,(T1) ;GET THE NEXT BLOCK IN THE LIST MOVEM T2,DELDVL ;THIS IS THE NEW HEAD OF THE LIST JRST DELDV1 ;GO DELETE THE BLOCK ;ROUTINE TO RELEASE A DEVELOPER STRING ;ACCEPTS IN T1/ ADR OF DEVELOPER BLOCK ;RETURNS +1: ALWAYS RELDEV: ASUBR LOAD T1,DVNAM,(T1) ;GET THE NAME BLOCK CALL RELFRE ;RELEASE IT MOVE T1,RELDVP ;GET ADR OF BLOCK AGAIN CALL RELFRE ;RELEASE IT RET ;DONE ;ROUTINE TO RELEASE A DEPENDENCY BLOCK ;ACCEPTS IN T1/ POINTER TO THE DEPENDENCY BLOCK ;RETURNS +1: ALWAYS RELDEP: LOAD T4,DPBTK,(T1) ;GET BLOCKED TASK ADR LOAD T2,TKBLP,(T4) ;LOOK FOR THIS BLOCK ON THE TASK LIST JUMPE T2,RELDP3 ;IF NO LIST, GO ON CAMN T1,T2 ;FOUND IT? JRST RELDP2 ;YES, GO DELETE IT RELDP1: MOVE T3,T2 ;REMEMBER THE LAST BLOCK SCANNED LOAD T2,DPBLP,(T3) ;GET ADR OF NEXT BLOCK JUMPE T2,RELDP3 ;IF NOT FOUND, GO ON CAME T1,T2 ;FOUND THE BLOCK? JRST RELDP1 ;NO, LOOP BACK TIL FOUND LOAD T2,DPBLP,(T2) ;FOUND, GET POINTER TO NEXT BLOCK STOR T2,DPBLP,(T3) ;MAKE LAST BLOCK POINT TO NEXT BLOCK JRST RELDP3 ;GO DO DEPENDENCY LIST RELDP2: LOAD T2,DPBLP,(T2) ;GET POINTER TO NEXT BLOCK STOR T2,TKBLP,(T4) ;MAKE TASK BLOCK POINT TO IT RELDP3: LOAD T4,DPTKP,(T1) ;GET POINTER TO DEPENDENT TASK LOAD T2,TKDLP,(T4) ;GET POINTER TO DEPENDENT BLOCK JUMPE T2,RELDP6 CAMN T1,T2 ;FOUND OUR BLOCK YET? JRST RELDP5 ;YES RELDP4: MOVE T3,T2 ;SAVE ADR OF LAST BLOCK LOAD T2,DPDLP,(T3) ;GET ADR OF NEXT BLOCK JUMPE T2,RELDP6 ;NOT FOUND? CAME T1,T2 ;HAVE A MATCH YET? JRST RELDP4 ;NO, CONTINUE LOOKING LOAD T2,DPDLP,(T2) ;GET POINTER TO NEXT BLOCK STOR T2,DPDLP,(T3) ;MAKE LAST BLOCK POINT TO NEXT ONE JRST RELDP6 RELDP5: LOAD T2,DPDLP,(T2) ;GET ADR OF NEXT BLOCK STOR T2,TKDLP,(T4) ;SAVE IT IN TASK BLOCK RELDP6: CALL RELFRE ;RELEASE THE BLOCK RET ;DONE ;UPDATE ALL ESTIMATED DATES IF NEEDED SCHCHK: SKIPN SKDFLG ;IS AN UPDATE NEEDED? CALL UPDEST ;YES--DO THE UPDATE RET ;OUTPUT A WARNING IF A SCHEDULE PASS IS NEEDED (BUT DON'T SCHEDULE) SCHWRN: SKIPE SKDFLG ;IS AN UPDATE NEEDED? RET ;NO--ALL DONE TMSG <% Some dates may be wrong. Use SCHEDULE command to update all dates > RET ;SCHEDULING ROUTINES ;ROUTINE TO UPDATE THE ESTIMATED START AND FINISH DATES OF ALL TASKS UPDEST: SAVEPQ STKVAR <,UPDESL,UPDESD> CALL GETLVL ;GET LOOK AHEAD LEVEL MOVEM T1,UPDESL ;SAVE THE LEVEL NUMBER MOVEM T2,UPDESD ;SAVE THE DEPTH SKIPN T1,SKDITD ;IS THERE AN INITIAL DATE SET GTAD ;NO, GET TODAY'S DATE CALL GETDAY ;GET CONVERTED DATE MOVEM T1,SKDTAD SKIPN SKDITD ;FUNNY TIME SET? JRST UPDST0 ;NO--SKIP WARNING MOVEI T1,.PRIOU TYPE T1,<[Virtual date set to > MOVE T2,SKDTAD ;GET INTERNAL FORM CALL TYPDAT ;PRINT IT TYPE T1,< by SET SCHEDULE-DATE command] > UPDST0: CALL LPCHK ;MAKE SURE THERE ARE NO LOOPS CALL CLRCP ;CLEAR THE CRITICAL PATH BITS MOVEI T1,0 ;START WITH A PASS OF 0 MOVEI T2,0 ;DEPTH 0 ALSO CALL BLDTAB ;BUILD THE TABLES CALL UPDEDT ;UPDATE THE ESTIMATED DATES CALL SETCP ;SET THE CRITICAL PATH TASKS MOVE T1,UPDESL ;GET THE LEVEL NUMBER MOVE T2,UPDESD ;GET THE DEPTH CALL BLDTAB ;GO BUILD THE SCHED TABLES MOVE T2,T1 ;GET NUMBER OF CONFLICTS ; HRROI T1,UPDESS ; MOVEI T3,^D10 ; NOUT ;GET ASCIZ STRING ; JSP ERROR ; MOVEI T1,.PRIOU ;OUTPUT THIS ON THE TTY ; TYPE T1,<&THE NUMBER OF UNRESOLVED CONFLICTS WAS > ; HRROI T2,UPDESS ; CALL TYPSTR ;OUTPUT THE NUMBER OF CONFILCTS ; TYPE T1,<&> TMSG <[> MOVEI T1,.PRIOU ;OUTPUT ON TERMINAL HLRZ T2,DEVTAB ;GET NUMBER OF DEVELOPERS MOVEI T3,^D10 ;IN DECIMAL NOUT JSP ERROR TMSG < DEVELOPERS SCHEDULED] > CALL UPDEDT ;GO UPDATE ESTIMATED DATES CALL SETCP ;GO SET THE CRITICAL PATH BITS CALL BLDSTL ;GO BUILD THE TASK LIST SETOM SKDFLG ;MARK THAT SCHEDULING IS NOT NEEDED MOVE Q1,TSKPTR ;POINTER TO TASK LIST UPDST1: HRRZ T1,Q1 ;COPY INDEX CALL CHKDAT ;CHECK DATES JRST UPDST2 ;LOOK OK TMSG <% > ;START WARNING HRRZ T1,TSKLST(Q1) ;OUTPUT TASK NAMES CALL TYPTNM ; .. TMSG < HAS QUESTIONABLE DATES > UPDST2: AOBJN Q1,UPDST1 ;LOOK AT ALL TASKS MOVE T2,TSKCNT CAIGE T2,^D100 RET TMSG <[> MOVEI T1,.PRIOU MOVEI T3,^D10 NOUT JFCL TMSG < TASKS SCHEDULED] > RET ;DONE ;SUBROUTINE TO CHECK FOR LOOPS IN DEPENDANCY LIST LPCHK: SKIPGE T1,NOLOOP ;ANY CHANGES SINCE LAST CHECK AOJE T1,R ;NO--JUST RETURN SAVEPQ MOVE T1,PRJTBL ;ADR OF PROJECT TABLE MOVEI P1,1(T1) ;POINTER TO FIRST TASK HLRZ P2,(T1) ;NUMBER OF PROJECTS JUMPN P2,LPCHK1 ;NO PROJECTS--NO LOOPS ERRMES () LPCHK1: HRRZ P3,(P1) ;ADDRESS OF NEXT PROJECT ;BLOCK LOAD T1,PJTKT,(P3) ;ADDRESS OF TASK TABLE MOVEI P4,1(T1) ;ADDRESS OF FIRST TASK HLRZ P5,(T1) ;GET NUMBER OF TASKS IN ;PROJECT JUMPN P5,LPCHK2 ;JUMP IF SOME TMSG <% NO TASKS IN PROJECT > LOAD T1,PJNAM,(P3) ;ADDRESS OF NAME HRLI T1,(POINT 7,0) ;MAKE BYTE POINTER PSOUT ;TYPE THE NAME TMSG < > JRST LPCHK3 ;SKIP TO NEXT PROJECT LPCHK2: MOVSI T1,-1 ;PRESET LIST TO FIRST TASK MOVEM T1,LVLPTR ; .. HRRZ T1,(P4) ;ADDRESS OF TASK BLOCK MOVEM T1,LVLTAB ;SAVE IN LIST CALL MKTASK ;CHECK FOR LOOPS ADDI P4,1 ;BUMP POINTER SOJG P5,LPCHK2 ;CHECK ALL TASKS IN THIS ;PROJECT LPCHK3: ADDI P1,1 ;BUMP POINTER SOJG P2,LPCHK1 ;CHECK ALL PROJECTS SETOM NOLOOP ;FLAG THAT NO LOOPS EXIST RET ;RECURSIVE ROUTINE TO CHECK FOR LOOPS IN DEPENDANCY LIST ;CALL WITH: ; T1/ TASK BLOCK ADDRESS ; LVLPTR/ AOBJN POINTER TO TASKS ALREADY FOUND ; CALL MKTASK ; RET MKTASK: SAVEQ MOVE Q1,T1 ;COPY TASK BLOCK ADDRESS LOAD Q2,TKDLP,(Q1) ;BLOCKING LIST POINTER JUMPE Q2,MKTSK5 ;TOP LEVEL TASK MKTSK1: LOAD Q3,DPBTK,(Q2) ;ADDRESS OF BLOCKING TASK MOVE T1,LVLPTR ;SEE IF IN LIST ALREADY CAME Q3,LVLTAB(T1) ;MATCH AOBJN T1,.-1 ;NO--KEEP LOOKING JUMPG T1,MKTSK4 ;IF POSITIVE THEN NO LOOP TMSG MOVE T1,Q1 ;COPY FIRST TASK CALL TYPTNM ;TYPE TASK NAME TMSG < ? BLOCKING TASK: > MOVE T1,Q3 ;COPY SECOND TASK CALL TYPTNM ;TYPE TASK NAME TMSG < ? TASKS IN LOOP: > MOVE Q1,LVLPTR ;POINTER TO LIST MKTSK2: SKIPG LVLTAB(Q1) ;VALID ENTRY? JRST MKTSK3 ;NO--SKIP IT TMSG HRRZ T1,LVLTAB(Q1) ;ADDRESS OF TASK BLOCK CALL TYPTNM ;TYPE IT OUT TMSG < > MKTSK3: AOBJN Q1,MKTSK2 ;LOOK OVER WHOLE LIST JRST REENT ;PUNT BIG MKTSK4: MOVE T1,LVLPTR ;GET POINTER SKIPL LVLTAB(T1) ;LOOK FOR FREE ENTRY AOBJN T1,.-1 ;LOOP OVER TABLE MOVEM Q3,LVLTAB(T1) ;STORE IN LIST MOVSI T2,-1 ;UPDATE POINTER SKIPL T1 ;ALLOCATE SLOT IF OFF END OF TABLE ADDM T2,LVLPTR ;SCAN UP THE LIST MOVE T1,Q3 ;CLIMB THE TREE CALL MKTASK ; .. LOAD Q2,DPDLP,(Q2) ;FOLLOW CHAIN JUMPN Q2,MKTSK1 ;CHECK ALL ABOVE MKTSK5: MOVE T1,LVLPTR ;POINTER TO LIST MKTSK6: CAMN Q1,LVLTAB(T1) ;FIND TASK IN LIST SETCMM LVLTAB(T1) ;DELETE IT AOBJN T1,MKTSK6 ;LOOP OVER WHOLE LIST RET ;ROUTINE TO COPY START AND FINISH DATES TO DATA BASE UPDEDT: SAVEQ ;SAVE REGS MOVE Q1,TSKPTR ;NOW SET UP THE ESTIMATED DATES JUMPE Q1,R ;IF NO TASKS, RETURN UPDES1: MOVE Q2,TSKLST(Q1) ;GET NEXT TASK MOVE T1,TSKSDL(Q1) ;GET THE START DATE TLNN T1,-1 ;ANYTHING THERE? MOVE T1,TSKFDL(Q1) ;IF NONE, USE THE FINISH DATE ; CAMN T1,TSKFDL(Q1) ;ONLY ONE DATE? ; JRST UPDES4 ;YES--MAKE SURE THEY STAY THE SAME ;UPDES2: CALL CHKWD ;WORKING DAY? ; JRST [MOVSI T2,1 ;NO--PUSH IT UP ; ADD T1,T2 ; .. ; JRST UPDES2] ;AND TRY AGAIN STOR T1,TKESD,(Q2) ;STORE IN THE DATA BASE STOR T1,TKLSD,(Q2) ;*** TEMP LATEST START DATE MOVE T1,TSKFDL(Q1) ;GET THE FINISH DATE ;UPDES3: CALL CHKWD ;WORKING DAY? ; JRST [MOVSI T2,1 ;NO--MOVE IT BACK ; SUB T1,T2 ; .. ; JRST UPDES3] ;AND TRY AGAIN STOR T1,TKEFD,(Q2) ;STORE IT IN THE DATA BASE STOR T1,TKLFD,(Q2) ;*** TEMP LATEST FINISH DATE ; JRST UPDES5 ;LOOP OVER ALL TASKS ;UPDES4: CALL CHKWD ;MAKE SURE WE HAVE A WEEKDAY ; JRST [MOVSI T2,1 ;ONE DAY ; SUB T1,T2 ;BACK UP DATE ; JRST UPDES4] ;KEEP TRYING ; STOR T1,TKLFD,(Q2) ;STORE ANSWER ; STOR T1,TKEFD,(Q2) ; .. ; STOR T1,TKLSD,(Q2) ; .. ; STOR T1,TKESD,(Q2) ; .. UPDES5: AOBJN Q1,UPDES1 ;LOOP BACK FOR ALL TASKS RET ;DONE ;ROUTINE TO GET THE LEVEL OF LOOK AHEAD ; CALL GETLVL ;RETURNS +1: ALWAYS, T1/ NUMBER OF LOOK AHEAD ; T2/ DEPTH OF SEARCH GETPAS: SKIPA T1,[POINT 7,[ASCIZ "NUMBER OF PLACEMENT PASSES: "]] GETLVL: HRROI T1,[ASCIZ/SCHEDULER LOOK AHEAD VALUE: /] MOVEI T2,SDATA ;GET THE ADR OF THE COMMAND TABLE MOVEI T3,ANSWER CALL PARSE ;GO GET THE VALUE FROM USER ERRMES LDB T1,[POINT 9,ANSWER,17] ;GET TYPE CODE CHKTYP (NUM) HRRZ T1,ANSWER ;GET ADR OF VALUE MOVE T1,ANSWER(T1) ;GET THE NUMBER MOVE T2,T1 ;GET DEPTH IMULI T2,NDEPTH ;CALCULATE THE DEPTH VALUE RET ;DONE ;ROUTINE TO BUILD THE SCHEDULER TABLES ;ACCEPTS IN T1/ LOOK AHEAD LEVEL NUMBER ; T2/ DEPTH ;RETURNS +1: ALWAYS, T1/ NUMBER OF CONFLICTS ENCOUNTERED BLDTAB: SAVEPQ CAILE T1,MAXTSK ;ABOVE THE MAX LEVEL? MOVEI T1,MAXTSK ;YES, LIMIT IT ASUBR SETZM BLDTBC ;ZERO THE NUMBER OF CONFLICTS SEEN MOVE T1,[SKDVAR,,SKDVAR+1] SETZM SKDVAR ;ZERO DATA BASE FIRST BLT T1,SKDVRE SKIPN T1,SKDITD ;IS THERE AN INITIAL DATE SET GTAD ;NO, GET TODAY'S DATE CALL GETDAY ;GET CONVERTED DATE MOVEM T1,SKDTAD SETOM PASCNT ;FIRST TIME THRU BLDTB0: HRLOI T1,377777 ;INIT THE BEST FINISH DATE MOVEM T1,BESTFD ;TO THE BIGGEST DATE SETZM DEPTH ;INIT DEPTH MOVE Q1,PASCNT ;GET CURRENT VALUE OF PASCNT CALL BLDTKT ;BUILD THE TASK TABLE SKIPG BLDTBL ;DOING MULTIPLE PASSES? JRST BLDTB1 ;NO MOVEI T1,.PRIOU ;PRINT OUT THE PASSES HRROI T2,[ASCIZ/REMAINING SCHEDULER PASSES: /] SKIPL Q1 ;FIRST TIME THRU? HRROI T2,[ASCIZ/, /] ;NO, TYPE A COMMA SETZ T3, SOUT MOVE T2,TSKCNT ;GET POSSIBLE PASSES SUB T2,PASCNT MOVEI T3,^D10 ;DECIMAL NOUT JFCL BLDTB1: CALL BLDTKT ;GO BUILD THE TASK TABLE MOVE P1,PASCNT ;SET UP LEVEL 0 COUNT MOVEM P1,LVL0CT SUB P1,PAS0CT ;GET COUNT MINUS INITIAL COUNT MOVNS P1 HRLZS P1 ;GET AOBJN POINTER HRR P1,PAS0CT ;STARTING AFTER THE INITIAL TASKS BLDTB2: MOVE T1,SKDCNT ;GET CURRENT COUNT OF SCHEDULED TASKS SETZM LVLCNT(T1) ;INIT LEVEL COUNT FOR THIS LEVEL CALL BLDAVL ;GO GET THE AVAILABLE TASKS JRST BLDTB5 ;NONE LEFT CALL BLDOAL ;GET OPTIMIZED AVAILABLE LIST JUMPL P1,BLDTB3 ;NEED TO SCHEDULE ANY TASKS FIRST? CALL GETMS ;GET ANY MILESTONES THAT ARE MET JRST BLDTB7 ;NONE FOUND MOVE T3,T1 ;GET INDEX INTO AVLTSK LIST INTO T3 MOVE T2,AVLSDL(T1) ;GO SCHEDULE THIS ONE NOW CALL SKDAVL ;GO SCHEDULE THE TASK JRST BLDTB2 ;LOOP BACK FOR THE OTHER TASKS BLDTB3: SKIPL T1,SKDLST(P1) ;IS THIS A GROUP OR A SINGLE TASK JRST [ CALL SKDTG ;GROUP, GO SCHEDULE IT JRST BLDTB9] TLNE T1,(1B1) ;IS THIS A TSKLST TASK? JRST [ MOVE T2,AVLSDL(T1) ;SINGLE TASK CALL SKDAVL ;GO SCHEDULE THE TASK JRST BLDTB9] ;DONE MOVE T2,TSKSDL(T1) ;GET START ADR FROM TSKLST CALL SKDTSK ;SCHEDULE THE TASK BLDTB9: AOBJN P1,.+1 ;STEP TO NEXT ITEM IN SKDLST JRST BLDTB2 ;LOOP BACK FOR OTHER TASKS BLDTB7: CALL FNDAVD ;FIND ANY AVAILABLE DEVELOPERS SKIPA T1,LEVEL ;NONE FOUND JRST BLDTB8 ;ONE FOUND, GO SCHEDULE IT AOS T1 MOVE T2,DEPTH ;GET CURRENT DEPTH CAMGE T2,BLDTBD ;REACHED THE MAX DEPTH? CAML T1,BLDTBL ;NO, AT THE MAXIMUM LEVEL? JRST [ AOS T1,NCNFLC ;AN UNRESOLVED CONFLICT WAS FOUND CAMLE T1,BLDTBC ;IS THIS A NEW HIGH FOR CONFLICTS? MOVEM T1,BLDTBC ;YES, REMEMBER IT JRST BLDTB4] ;GO CHOSE THE LONGEST TASK MOVE T2,SKDCNT ;LEVEL 0, REMEMBER THIS POINT MOVEM T2,MAXCFL ;SAVE THE MAXIMUM LEVEL ATAINED MOVE T3,OAVCNT ;GET OPTIMIZED COUNT MOVEM T3,LVLCNT(T2) ;SAVE THE COUNT FOR THIS LEVEL AOS DEPTH ;COUNT UP THE DEPTH OF THE SEARCH AOSN LEVEL ;NO, STEP TO NEXT LEVEL MOVEM T2,LVL0CT ;NEXT PASS WILL SKIP PAST THIS LEVEL MOVE T1,SKDCNT ;GET CURRENT LEVEL MOVE T1,LVLTAB(T1) ;GET THE NEXT TASK TO SCHEDULE AOS T1 ;START GROUP NUMBER ONE HIGHER SKIPN LEVEL ;LEVEL 0? MOVEM T1,LVL0TK ;REMEMBER THIS DATA CALL SKDTG ;GO SCHEDULE THE GROUP JRST BLDTB2 ;LOOP BACK FOR REST OF TASKS BLDTB4: MOVE T1,SKDTAD ;GET START DATE OF SCHEDULE PASS MOVE T2,LSTSKT ;GET LAST SCHEDULED TASK SETO T3, ;CHOSE ANY TASK CALL GETLFT ;GET LATEST COMPLETION TASK SETZ T1, ;FAILED, GO SCHEDULE THE FIRST ON THE LIST HLRZ T1,AVLTSK(T1) ;GET THE GROUP NUMBER CALL SKDTG ;SCHEDULE THE WHOLE GROUP JRST BLDTB2 ;DONE BLDTB8: MOVE T2,AVLSDL(T1) ;GET ITS START DATE CALL SKDAVL ;GO SCHEDULE THIS TASK JRST BLDTB2 ;LOOP BACK FOR OTHER TASKS BLDTB5: CALL CHKLOP ;GO SEE IF THERE IS A LOOP ERRMES () CALL CHKBST ;SEE IF THIS IS A NEW BEST BLDTB6: MOVE T1,MAXCFL ;NOW STEP THE LEVEL CHOICE AOS T2,LVLTAB(T1) CAMGE T2,LVLCNT(T1) ;REACHED END OF THE LEVEL? JRST BLDTB1 ;NO, GO BACK AND TRY THIS CHOICE SETZM LVLTAB(T1) ;YES, INIT TABLE SETZM LVLCNT(T1) SOSL MAXCFL ;GO BACK TO PREVIOUS LEVEL JRST BLDTB6 ;LOOP BACK FOR OTHER CHOICES MOVE T1,BLDTBC ;GET MAX NUMBER OF CONFLICTS SEEN SKIPLE BLDTBL ;IF LEVEL = 0, THEN ONE PASS IS ENOUGH SKIPG NCNFLC ;ANY CONFLICTS STILL? RET ;NO, DONE MOVE T1,BESTSK ;GET THE BEST LEVEL 0 TASK MOVE T2,LVL0CT ;GET COUNT MOVEM T1,SKDLST(T2) ;SAVE POINTER TO BEST TASK ADDI T2,1 ;SKIP TO HERE ON NEXT PASS CAML T2,TSKCNT ;GONE THRU ALL PASSES? RET ;YES, DONE MOVEM T2,PASCNT JRST BLDTB0 ;GO TRY AGAIN AT NEXT PASCNT ;ROUTINE TO SCHEDULE THOSE TASKS THAT HAVE A COMMON SET ; OF DEVELOPERS AND THE SAME DEPENDENT TASKS. ;ACCEPTS IN T1/ INDEX INTO AVLTSK OF TASK TO BE SCHEDULED ; CALL SKDCOM ;RETURNS +1: ALWAYS SKDCOM: SAVEQ STKVAR HRRZ Q1,T1 ;SAVE TASK INDEX MOVE Q2,AVLTSK(Q1) ;GET THE TASK ADDRESS HLRZM Q2,SKDCMC ;SAVE THE GROUP NUMBER MOVE Q2,TSKLST(Q2) LOAD Q2,TKBLP,(Q2) ;GET THE POINTER TO THE BLOCKED TASKS MOVN Q3,AVLCNT ;GET POINTER TO TABLE HRLZS Q3 MOVE T1,Q3 ;INIT TABLE MOVSI T2,(1B0) SKDCM0: ANDCAM T2,AVLTSK(T1) ;CLEAR FLAG BIT AOBJN T1,SKDCM0 ;IN EACH ENTRY SKDCM1: MOVE T1,AVLTSK(Q3) ;GET TASK ADR MOVE T1,TSKLST(T1) LOAD T1,TKBLP,(T1) ;GET BLOCKED TASK LIST CAMN Q2,T1 ;DO THEY MATCH? JRST SKDCM5 ;YES, THEN GO MARK THIS TASK JUMPE Q2,SKDCM4 ;IF NO DEPENDENCIES, THEN NO MATCH JUMPE T1,SKDCM4 ;IF NONE, MARK IT AS SUCH SKDCM2: MOVE T2,Q2 ;GET LIST POINTER FOR MAIN TASK LOAD T3,DPTKP,(T1) ;GET TASK ADR OF BLOCKED TASK SKDCM3: LOAD T4,DPTKP,(T2) ;GET NEXT TASK ADR OF BLOCKED TASK CAMN T3,T4 ;FOUND A MATCH? JRST SKDCM5 ;YES LOAD T2,DPBLP,(T2) ;NO, STEP TO NEXT ELEMENT IN LIST JUMPN T2,SKDCM3 ;LOOP BACK FOR REST OF LIST SKDCM4: JRST SKDCM6 ;GO LOOP BACK THROUGH REST OF TASKS SKDCM5: JUMPE Q2,SKDC13 ;IF THERE ARE NO DEPENDENCIES, THEN DONE LOAD T1,DPBLP,(T1) ;STEP TO NEXT TASK IN PRIMARY LIST JUMPN T1,SKDCM2 ;LOOP BACK TO CHECK ALL TASKS IN LISTS SKDC13: MOVSI T1,(1B0) ;SET THE FLAG BIT IORM T1,AVLTSK(Q3) SKDCM6: AOBJN Q3,SKDCM1 ;LOOP BACK FOR THE REST OF AVLTSK'S MOVN Q3,AVLCNT ;GET POINTER TO LIST AGAIN HRLZS Q3 MOVE Q2,AVLTSK(Q1) ;GET TASK ADR MOVE Q2,TSKLST(Q2) LOAD T1,TKPRJ,(Q2) ;GET POINTER TO PROJECT BLOCK LOAD Q2,TKDVL,(Q2) ;GET POINTER TO DEVELOPER LIST SKIPN Q2 ;IS THERE ANY? LOAD Q2,PJDVL,(T1) ;NO, GET THE PROJECT DEVELOPER LIST SKIPN Q2 ;IS THERE A LIST? MOVE Q2,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q2,SKDC11 ;IF NONE, GO CLEAN UP AND EXIT SKDCM7: MOVE T2,Q2 ;GET POINTER TO DEVELOPER LIST CAIN Q1,(Q3) ;IS THIS THE SAME AS THE MAIN TASK? JRST SKDCM8 ;YES, SKIP IT SKIPL T1,AVLTSK(Q3) ;IS THIS ONE OF THE GROUP JRST [ CALL CHKNDV ;NO, SEE IF NO DEVELOPERS MATCH JRST SKDC11 ;DEVELOPER MATCHES, CANNOT SCHEDULE JRST SKDCM8] ;GO LOOP BACK FOR OTHER TASKS CALL CHKMDV ;SEE IF ALL DEVELOPERS MATCH JRST SKDC11 ;NO, THEN CANNOT SCHEDULE ANY SKDCM8: AOBJN Q3,SKDCM7 ;LOOP BACK TO CHECK ALL TASKS MOVN Q3,AVLCNT ;NOW SET THE CODE FOR EACH TASK HRLZS Q3 MOVE T1,SKDCMC ;GET GROUP NUMBER SKDCM9: SKIPGE AVLTSK(Q3) ;IS THIS A MEMBER OF THE GROUP? HRLM T1,AVLTSK(Q3) ;YES, STORE THE GROUP NUMBER AOBJN Q3,SKDCM9 SKDC11: MOVN Q3,AVLCNT ;CLEAN UP HRLZS Q3 ;CLEAR THE FLAG BIT IN EACH WORD MOVSI T1,(1B0) SKDC12: ANDCAM T1,AVLTSK(Q3) ;CLEAR THE FLAG AOBJN Q3,SKDC12 RET ;ROUTINE TO CHECK IF ALL DEVELOPERS MATCH MAIN TASK ;ACCEPTS IN T1/ TASK INDEX ; T2/ ADR OF FIRST ITEM IN DEVELOPER LIST ; CALL CHKMDV ;RETURNS +1: NOT ALL DEVELOPERS MATCH ; +2: ALL DEVELOPERS MATCH MAIN TASK LIST CHKMDV: SAVEQ JUMPE T2,R ;IF NO LIST, THEN NO MATCH MOVE T1,TSKLST(T1) ;GET TASK ADDRESS DMOVE Q1,T1 ;SAVE ARGUMENTS LOAD T1,TKPRJ,(Q1) ;GET ADR OF PROJECT BLOCK LOAD Q3,TKDVL,(Q1) ;GET TASK DEVELOPER LIST SKIPN Q3 ;ANY THERE? LOAD Q3,PJDVL,(T1) ;NO, USE THE PROJECT LIST SKIPN Q3 ;IS THERE A LIST? MOVE Q3,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q3,R ;IF NONE, THEN NO MATCH SETZB T3,T4 ;SEE IF THERE ARE THE SAME NUMBER OF PEOPLE MOVE T1,Q3 ;COUNT UP FIRST LIST CHKMD4: AOS T3 ;COUNT DEVELOPER LOAD T1,DVLNK,(T1) ;STEP TO NEXT ITEM JUMPN T1,CHKMD4 ;IF MORE, GO COUNT THEM MOVE T1,Q2 ;NOW DO SECOND LIST CHKMD5: AOS T4 ;COUNT ITEM LOAD T1,DVLNK,(T1) ;STEP TO NEXT ITEM JUMPN T1,CHKMD5 CAME T3,T4 ;THE SAME? RET ;NO, NO MATCH CHKMD1: MOVE Q1,Q3 ;INIT POINTER TO START OF LIST CHKMD2: LOAD T1,DVNAM,(Q2) ;GET POINTER TO DEVELOPER NAME LOAD T2,DVNAM,(Q1) ;GET POINTER TO SECOND NAME CALL CHKMNM ;SEE IF THE NAMES MATCH SKIPA ;THEY DIDNT MATCH JRST CHKMD3 ;MATCHED LOAD Q1,DVLNK,(Q1) ;STEP TO NEXT DEVELOPER JUMPN Q1,CHKMD2 ;IF MORE IN LIST, LOOP BACK RET ;DID NOT FIND A MATCH FOR DEVELOPER CHKMD3: LOAD Q2,DVLNK,(Q2) ;STEP TO NEXT ITEM IN THE LIST JUMPN Q2,CHKMD1 ;LOOP BACK FOR ALL TASKS RETSKP ;ALL NAMES MATCHED ;ROUTINE TO CHECK IF NO DEVELOPERS MATCH THE MAIN TASK ;ACCEPTS IN T1/ TASK INDEX ; T2/ DEVELOPER LIST ; CALL CHKNDV ;RETURNS +1: FOUND A DEVELOPER MATCH ; +2: NO DEVELOPERS MATCH IN THE LISTS CHKNDV: SAVEQ JUMPE T2,RSKP ;IF NO LIST, THEN NO MATCH MOVE T1,TSKLST(T1) ;GET TASK ADDRESS DMOVE Q1,T1 ;SAVE ARGS LOAD T1,TKPRJ,(Q1) ;GET THE PROJECT BLOCK ADDRESS LOAD Q3,TKDVL,(Q1) ;GET POINTER TO DEVELOPER LIST SKIPN Q3 ;ANY THERE? LOAD Q3,PJDVL,(T1) ;NO, USE PROJECT LIST SKIPN Q3 ;IS THERE A LIST? MOVE Q3,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q3,RSKP ;IF NONE, THEN NO MATCH CHKND1: MOVE Q1,Q3 ;GET POINTER TO MAIN LIST CHKND2: LOAD T1,DVNAM,(Q2) ;GET POINTERS TO NAMES LOAD T2,DVNAM,(Q1) CALL CHKMNM ;SEE IF THEY MATCH SKIPA ;NO MATCH RET ;A MATCH WAS FOUND, CAN EXIT NOW LOAD Q1,DVLNK,(Q1) ;STEP TO NEXT DEVELOPER IN LIST JUMPN Q1,CHKND2 ;LOOP BACK TO CHECK THIS DEVELOPER LOAD Q2,DVLNK,(Q2) ;STEP TO NEXT ITEM IN SECOND LIST JUMPN Q2,CHKND1 ;LOOP BACK FOR ALL OF THESE NAMES RETSKP ;NO MATCHES FOUND IN BOTH LISTS ;ROUTINE TO COMPARE TWO NAMES ;ACCEPTS IN T1/ ADR OF FIRST NAME ; T2/ ADR OF SECOND NAME ; CALL CHKMNM ;RETURNS +1: NAMES DID NOT MATCH ; +2: NAMES MATCHED EXACTLY CHKMNM: MOVE T3,(T1) ;GET NEXT WORD FROM NAME 1 CAME T3,(T2) ;DOES IT MATCH NAME 2? RET ;NO, NO MATCH TRNN T3,377 ;YES, REACHED THE END OF THE STRING? RETSKP ;YES, THEN THE NAMES MATCH AOS T1 ;STEP TO NEXT WORD IN NAMES AOJA T2,CHKMNM ;LOOP BACK FOR REST OF WORDS IN NAMES ;ROUTINE TO SCHEDULE ALL TASKS THAT HAVE A START DATE ALREADY SKDSKD: SAVEQ STKVAR <,SKDSKL,SKDSKF,SKDSKS> MOVE Q1,TSKPTR ;GET AOBJN POINTER TO TASK LIST SKDSK1: MOVE Q2,TSKLST(Q1) ;GET TASK ADR MOVE T1,Q2 ;GET THE TASK ADR CALL GETSFD ;GET THE START AND FINISH DATE JRST SKDSK4 ;NONE MOVEM T1,SKDSKF ;SAVE THE FINISH DATE MOVEM T2,SKDSKS ;SAVE START DATE LOAD Q3,TKDVL,(Q2) ;SCHEDULE THIS TASK LOAD T2,TKPRJ,(Q2) ;GET POINTER TO PROJECT BLOCK SKIPN Q3 ;IS THERE A DEVELOPER LIST FOR THIS TASK LOAD Q3,PJDVL,(T2) ;NO, USE THE PROJECT LIST SKIPN Q3 ;IS THERE A LIST? MOVE Q3,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q3,SKDSK3 ;UNLESS THERE ARE NO DEVELOPERS LISTED SETZM SKDSKL ;INIT LENGTH OF TASK SKDSK2: LOAD T1,DVNAM,(Q3) ;GET DEVELOPER NAME MOVEM T1,SKDSKA ;BUILD ARG BLOCK MOVE T1,SKDSKS ;GET THE START DATE MOVE T2,SKDSKF ;GET FINISH DATE MOVEM T2,2+SKDSKA SKIPN T1 ;IS THERE A START DATE? MOVE T1,T2 ;NO, USE THE FINISH DATE MOVEM T1,1+SKDSKA CALL GETNWD ;GET THE NUMBER OF WORKING DAYS FLTR T1,T1 ;FLOAT IT LOAD T2,DVHCR,(Q3) ;GET HANDICAP LOAD T3,DVRAT,(Q3) ;GET RATE OF DEVELOPER MOVEM T3,3+SKDSKA FMPR T1,T2 ;GET ACTUAL NUMBER OF DAYS OF TASK FMPR T1,T3 ;DAYS * RATE * HANDICAP FADRM T1,SKDSKL ;ADD INTO THE SUM OF TIME SPENT MOVEM Q2,4+SKDSKA ;PUT TASK ADR IN ARG BLOCK MOVEI T1,SKDSKA ;GET ADR OF ARG BLOCK CALL SCHDEV ;GO SCHEDULE THIS DEVELOPER LOAD Q3,DVLNK,(Q3) ;STEP TO NEXT DEVELOPER JUMPN Q3,SKDSK2 ;LOOP BACK FOR ALL DEVELOPERS MOVE T1,SKDSKL ;GET PROJECT LENGTH STOR T1,TKALN,(Q2) ;STORE THE CALCULATED LENGTH ;.. ;.. SKDSK3: MOVE T1,SKDSKF ;GET THE FINISH DATE MOVEM T1,TSKFDL(Q1) ;SAVE THE FINISH DATE MOVE T2,SKDSKS ;GET THE START DATE TLNN T2,-1 ;ANY START DATE? MOVE T2,T1 ;NO, USE THE FINISH DATE MOVEM T2,TSKSDL(Q1) ;SAVE ITS START DATE AOS T2,SKDCNT ;COUNT THE NUMBER OF SCHEDULED TASKS HRRZM Q1,SKDLST-1(T2) ;SAVE THE INDEX INTO TSKLST IN SKDLST SKDSK4: AOBJN Q1,SKDSK1 ;LOOP BACK FOR ALL TASKS MOVE Q1,TSKPTR ;NOW LOOK FOR STARTED BUT NOT ENDED TASKS SKDSK5: MOVE T1,TSKLST(Q1) ;GET TASK ADR LOAD T2,TKAFD,(T1) ;GET FINISH DATE LOAD T3,TKXCD,(T1) ;GET THE COMPLETION DATE IOR T2,T3 ;MERGE IT JUMPN T2,SKDSK6 ;IF ANY DATE SET, SKIP THIS TASK LOAD T2,TKASD,(T1) ;GET THE ACTUAL START DATE LOAD T3,TKXSD,(T1) ;GET EXPECTED START DATE TLNN T2,-1 ;IS THERE AN ACTUAL START DATE? MOVE T2,T3 ;NO, USE THE EXPECTED JUMPE T2,SKDSK6 ;IF NONE, SKIP TASK MOVEM T2,TSKSDL(Q1) ;SAVE ACTUAL START DATE HRRZ T1,Q1 ;GET INDEX INTO TSKLST CALL SKDTSK ;GO SCHEDULE THIS TASK SKDSK6: AOBJN Q1,SKDSK5 ;LOOP BACK FOR ALL TASKS RET ;DONE ;ROUTINE TO INITIALIZE THE SCHEDULER DATA BASE BLDINI: SETOM LEVEL ;START AT GROUND LEVEL SETZM NCNFLC ;NO CONFILCTS YET SETZM MAXCFL ;INIT THE MAXIMUM CONFLICT LEVEL SETZM LSTSKT ;INIT LAST SCHEDULED TASK MOVEI T1,MAXDEV-1 ;SET UP THE TBLUK FORMAT MOVEM T1,DEVTAB ;NO ENTRIES YET SETZM SKDFRE ;INIT THE FREE POOL MOVEI T1,SKDFRE MOVEM T1,SKDFRP ;MAKE THE FREE POOL POINTER GOOD SETZM SKDCNT ;NONE SCHEDULED YET RET ;DONE ;ROUTINE TO GET THE START AND FINISH DATES OF A TASK ;ACCEPTS IN T1/ TASK ADR ;RETURNS +1: NO FINISH DATE SPECIFIED ; +2: T1/ FINISH DATE ; T2/ START DATE GETSFD: SAVEQ SETZB Q1,Q2 ;INIT ANSWER MOVE Q3,T1 ;SAVE THE TASK ADR LOAD T1,TKAFD,(Q3) ;IS THERE AN ACTUAL FINISH DATE SKIPN T1 LOAD T1,TKXCD,(Q3) ;NO, TRY FOR AN EXPECTED DATE SKIPN Q1,T1 ;ANY FINISH DATE? RET ;NO, RETURN LOAD T1,TKASD,(Q3) ;NOW LOOK FOR A START DATE SKIPN T1 LOAD T1,TKXSD,(Q3) ;IF NO START DATE, TRY EXPECTED START SKIPE Q2,T1 ;ANY THERE? JRST GETSF1 ;YES LOAD T1,TKDVL,(Q3) ;GET THE POINTER TO THE DEVELOPER LIST CALL GETDVR ;GET THE SUM OF THE RATES JRST GETSF2 ;NONE FOUND OR 0 LOAD T2,TKELN,(Q3) ;GET THE ESTIMATED LENGTH MOVE T3,Q1 ;GET THE FINISH DATE CALL GETSD ;GET THE START DATE GIVEN THE FINISH MOVEM T1,Q2 ;SAVE THE START DATE GETSF1: DMOVE T1,Q1 ;GET THE ANSWER DATES RETSKP ;RETURN GETSF2: MOVE T1,Q1 ;GET FINISH DATE MOVE T2,Q1 ;USE THE SAME DATE FOR START RETSKP ;ROUTINE TO SUM THE RATES IN A DEVELOPER LIST ;ACCEPTS IN T1/ DEVELOPER LIST ;RETURNS +1: NO RATE ; +2: T1/ RATE GETDVR: JUMPE T1,R ;IF NO LIST, RETURN+1 SETZ T4, ;INIT ANSWER GETDV1: LOAD T2,DVRAT,(T1) ;GET THE RATE FADR T4,T2 ;ADD IT TO THE SUM LOAD T1,DVLNK,(T1) ;STEP TO THE NEXT DEVELOPER JUMPN T1,GETDV1 ;LOOP BACK FOR ALL DEVELOPERS SKIPG T1,T4 ;ANY RATE FOUND? RET ;NO RETSKP ;YES ;ROUTINE TO GET A START DATE GIVEN FINISH AND LENGTH ;ACCEPTS IN T1/ RATE ; T2/ LENGTH OF TASK ; T3/ FINISH DATE ;RETURNS +1: T1/ START DATE GETSD: SAVEQ FDVR T2,T1 ;GET NUMBER OF DAYS FOR TASK FIXR T2,T2 DMOVE Q1,T2 ;Q1 = LENGTH, Q2 = FINISH DATE MOVE T1,Q2 ;GET FINISH DATE HRLZ T2,Q1 ;GET LENGTH SUB T1,T2 ;GET FIRST STAB AT START DATE MOVEM T1,Q3 ;STORE START DATE GETSD1: MOVE T1,Q3 ;GET START DATE MOVE T2,Q2 ;GET FINISH DATE CALL GETNWD ;GET NUMBER OF DAYS BETWEEN DATES SUB T1,Q1 ;SEE IF THE LENGTHS MATCH JUMPE T1,GETSD2 ;IF 0, THEN DONE HRLZS T1 ADDM T1,Q3 ;CORRECT THE START DATE AND TRY AGAIN JRST GETSD1 ;LOOP BACK TILL CORRECT DATE FOUND GETSD2: MOVE T1,Q3 ;GET START DATE RET ;RETURN ;ROUTINE TO BUILD THE TASK TABLE BLDTKT: SAVEPQ CALL BLDINI ;INIT THE DATA BASE SKIPL PASCNT ;FIRST TIME THRU? JRST BLDTK4 ;NO MOVSI P6,-1 ;CONSTANT SETZM TSKCNT ;INIT COUNT OF TASKS SETZM TSKPTR ;CLEAR POINTER MOVE T1,PRJTBL ;GET ADR OF PROJECT TABLE MOVSI P1,-MAXTSK ;SET UP POINTER TO TABLES MOVEI Q1,1(T1) ;GET POINTER TO FIRST PROJECT HLRZ Q2,0(T1) ;GET NUMBER OF PROJECTS IN LIST JUMPLE Q2,R ;IF NONE, THEN DONE BLDTK1: HRRZ Q3,(Q1) ;GET ADR OF NEXT PROJECT BLOCK LOAD T4,PJTKT,(Q3) ;GET ADR OF TASK TABLE HLRZ T3,0(T4) ;GET NUMBER OF TASKS IN TABLE MOVEI T4,1(T4) ;GET ADR OF FIRST ENTRY IN TASK TABLE JUMPLE T3,BLDTK3 ;IF NO TASKS, GO TO NEXT PROJECT BLDTK2: HRRZ T1,(T4) ;GET NEXT TASK BLOCK ADR AOS TSKCNT ;COUNT UP NUMBER OF TASKS ON LIST ADDM P6,TSKPTR ;KEEP AOBJN POINTER UP TO DATE STOR P1,TKTKI,(T1) ;SAVE TASK LIST INDEX IN TASK BLOCK MOVEM T1,TSKLST(P1) ;SAVE TASK ADR ON TASK LIST SETZM TSKFDL(P1) ;INIT FINISH DATE SETZM TSKSDL(P1) ;AND START DATE SETZM LVLTAB(P1) ;INIT LEVEL TABLE SETZM LVLCNT(P1) AOBJP P1,[WARN (,)] AOS T4 ;STEP TO NEXT TASK IN TABLE SOJG T3,BLDTK2 ;LOOP BACK FOR ALL TASKS BLDTK3: AOS Q1 ;STEP TO NEXT PROJECT SOJG Q2,BLDTK1 ;LOOP BACK FOR ALL PROJECTS BLDT3A: CALL SKDSKD ;GO SCHEDULE ALREADY SCHEDULED TASKS MOVE T1,SKDCNT ;INITIALIZE PASCNT TO CURRENT POSITION SKIPGE PASCNT ;ONLY DO THIS ON THE FIRST PASS MOVEM T1,PASCNT MOVEM T1,PAS0CT ;SAVE THE LEVEL 0 COUNT RET ;DONE BLDTK4: MOVE T1,TSKPTR ;INIT TABLES BLDTK5: SETZM TSKFDL(T1) SETZM TSKSDL(T1) AOBJN T1,BLDTK5 CALL SKDSKD ;GO SCHEDULE ALREADY STARTED TASKS RET ;ROUTINE TO SCHEDULE A TASK ;ACCEPTS IN T1/ INDEX INTO TSKLST TABLE ; T2/ EARLIEST START DATE ; CALL SKDTSK ;RETURNS +1: ALWAYS, T1/ FINISH DATE ; T2/ START DATE SKDAVL: MOVE T3,AVLTSK(T1) ;GET THE TASK INDEX HRROS T1 ;FLAG THAT THIS IS AN AVLTSK INDEX JRST SKDTK0 SKDTSK: MOVE T3,T1 ;SET UP TASK ADR HRLI T1,(1B0) ;FLAG THAT THIS IS A TSKLST INDEX SKDTK0: STKVAR MOVEM T1,SKDTKI ;SAVE THE INDEX VALUE MOVEM T3,SKDTKT ;SAVE THE TASK ADDRESS HRRZ T1,TSKLST(T3) ;GET THE ADR OF THE TASK MOVEM T1,LSTSKT ;SAVE THE ADR OF THE LAST TASK SCHEDULED MOVE T3,T1 ;TASK ADR INTO T3 LOAD T4,TKDVL,(T1) ;GET THE DEVELOPER LIST JUMPN T4,SKDTS1 ;IF ONE THERE, SKIP LOAD T4,TKPRJ,(T1) ;NONE, GET GENERAL PROJECT LIST LOAD T4,PJDVL,(T4) SKIPN T4 ;IS THERE A LIST? MOVE T4,DEVTBP ;NO, GET THE OVERALL LIST SKDTS1: MOVE T1,T4 ;GET ADR OF FIRST DEVELOPER BLOCK CALL SCHED ;GO SCHEDULE THE TASK AOS T4,SKDCNT ;COUNT UP THE NUMBER OF SCHEDULED TASKS MOVE T3,SKDTKI ;GET INDEX INTO TSKLST MOVEM T3,SKDLST-1(T4) ;SAVE POINTER TO THIS SCHEDULED TASK MOVE T3,SKDTKT ;GET INDEX TLNN T2,-1 ;IS THERE A START DATE? MOVE T2,T1 ;NO, USE THE FINISH DATE MOVEM T1,TSKFDL(T3) ;SAVE THE FINISH DATE MOVEM T2,TSKSDL(T3) ;SAVE THE START DATE RET ;DONE, FINISH DATE IS IN T1 ;ROUTINE TO BUILD THE AVAILABLE TASK LIST ;ACCEPTS IN T1/ 0 = FORWARD SCAN, 1 = REVERSE SCAN BLDPAV: SAVEQ MOVEI Q3,1 ;BUILD PERT AVAILABLE LIST HRL Q3,T1 ;SAVE INDEX JRST BLDAV0 BLDAVL: SAVEQ MOVEI Q3,0 ;BUILD REGULAR AVILABLE LIST BLDAV0: SETZM AVLCNT ;INIT COUNT OF AVAIL TASKS MOVSI Q1,-MAXTSK MOVN T1,TSKCNT ;SET UP AOBJN POINTER TO TSKLST HRLZ Q2,T1 BLDAV1: HRRZ T1,TSKLST(Q2) ;GET ADR OF NEXT TASK JUMPE Q3,BLDA1A ;SKIP IF NOT PERT SKIPE TSKINV(Q2) ;WANT THIS IN PERT? JRST BLDAV2 ;NO--SKIP IT BLDA1A: HRRZ T2,Q3 ;GET INDEX VALUE HLRZ T3,Q3 ;GET SCAN DIRECTION XCT [ SKIPN TSKFDL(Q2) ;HAS IT BEEN SCHEDULED? SKIPGE TSKLST(Q2)](Q3) CALL CHKAVL ;NO, SEE IF IT IS AVAILABLE JRST BLDAV2 ;NO, STEP TO NEXT TASK HRRZ T2,Q2 ;GET TASK INDEX MOVEM T2,AVLTSK(Q1) ;SAVE TASK INDEX MOVEM T1,AVLSDL(Q1) ;SAVE THE START DATE AOS AVLCNT ;COUNT UP THE NUMBER OF AVAILABLE TASKS AOBJP Q1,RSKP ;IF REACHED MAXIMUM, RETURN BLDAV2: AOBJN Q2,BLDAV1 ;LOOP BACK FOR REST OF TASKS SKIPG AVLCNT ;FOUND ANY? RET ;NO, GIVE +1 RETURN RETSKP ;YES, GIVE +2 RETURN ;ROUTINE TO OPTIMIZE THE AVAILABLE TASK LIST BLDOAL: SAVEQ MOVEI Q2,0 ;INIT THE GROUP COUNTER MOVN Q1,AVLCNT ;GET POINTER TO AVLTSK HRLZS Q1 BLDOA1: MOVE T1,Q1 ;GET INDEX MOVE T2,AVLTSK(T1) ;GET TSKLST INDEX TLNE T2,-1 ;THIS BEEN SCHEDULED YET? JRST BLDOA2 ;YES, SKIP IT AOS Q2 ;STEP COUNTER HRLM Q2,AVLTSK(T1) ;NO, STORE GROUP NUMBER CALL SKDCOM ;SCHEDULE THIS TASK BLDOA2: AOBJN Q1,BLDOA1 ;LOOP BACK FOR ALL AVAILABLE TASKS MOVEM Q2,OAVCNT ;STORE COUNT RET ;ROUTINE TO CHECK THE AVAILABILITY OF A TASK ;ACCEPTS IN T1/ ADR OF TASK BLOCK ; T2/ INDEX FOR TYPE OF CHECK TO BE MADE ; T3/ 0 = FORWARD SCAN, 1 = REVERSE SCAN ; CALL CHKAVL ;RETURNS +1: NOT AVAILABLE YET ; +2: T1/ EARLIEST START DATE CHKAVL: SAVEPQ HRRZ Q3,T2 ;SAVE THE INDEX VALUE HRRZ P1,T3 ;SAVE THE SCAN DIRECTION LOAD Q1,TKMSD,(T1) ;GET THE MINIMUM START DATE CAMGE Q1,SKDTAD ;IS IT AFTER TODAYS DATE? MOVE Q1,SKDTAD ;NO, INIT START DATE TO TODAY'S DATE XCT [ LOAD T2,TKDLP,(T1) ;GET DEPENDENCY LIST LOAD T2,TKBLP,(T1)](P1) JUMPE T2,CHKAV4 ;IF NO DEPENDENCIES, RETURN +2 CHKAV0: XCT [ LOAD T3,DPBTK,(T2) ;GET POINTER TO BLOCKING TASK LOAD T3,DPTKP,(T2)](P1) LOAD Q2,TKTKI,(T3) ;GET TASK LIST INDEX SKIPE TSKINV(Q2) ;WANT TASK IN PERT? JRST CHKAV3 ;NO--SKIP IT XCT [ SKIPN TSKFDL(Q2) ;IS THERE A FINISH DATE SKIPGE TSKLST(Q2)](Q3) RET ;IF NONE YET, THEN NOT AVAILABLE CAMGE Q1,TSKFDL(Q2) ;IS THIS A NEW LATEST FINISH DATE MOVE Q1,TSKFDL(Q2) ;YES, REMEMBER IT CHKAV3: XCT [ LOAD T2,DPDLP,(T2) ;STEP TO NEXT DEPENDENCY LOAD T2,DPBLP,(T2)](P1) JUMPN T2,CHKAV0 ;LOOP BACK FOR OTHERS CHKAV4: MOVE T1,Q1 ;RETURN THE EARLIEST START DATE RETSKP ;ROUTINE TO FIND ANY MILESTONES (0 LENGTH TASKS) ;RETURNS +1: NONE FOUND ; +2: T1/ INDEX INTO AVLTSK LIST GETMS: MOVN T1,AVLCNT ;SET UP AOBJN POINTER HRLZS T1 GETMS1: MOVE T2,AVLTSK(T1) ;GET INDEX INTO TASK TABLE MOVE T2,TSKLST(T2) ;GET TASK ADR LOAD T2,TKELN,(T2) ;GET TASK LENGTH JUMPE T2,GETMS2 ;IF 0, THEN FOUND ONE AOBJN T1,GETMS1 ;SEARCH ALL OF AVAILABLE TASKS RET ;NONE FOUND GETMS2: HRRZS T1 ;RETURN INDEX INTO AVLTSK LIST RETSKP ;ROUTINE TO LOOK FOR A FREE DEVELOPER ;RETURNS +1: ALL DEVELOPERS HAVE MORE THAN ONE PROJECT ; +2: T1/ INDEX INTO AVLTSK FNDAVD: SAVEQ MOVN Q1,AVLCNT ;GET AOBJN POINTER TO LIST HRLZS Q1 FNDAV1: MOVN Q2,AVLCNT ;GET AOBJN POINTER TO TASK LIST HRLZS Q2 FNDAV2: AOBJP Q2,FNDAV3 ;LOOK FOR A MATCH FNDAV9: CAMN Q1,Q2 ;ARE WE AT THE SAME TASK? JRST [ AOBJP Q2,FNDAV4 JRST FNDAV9] ;YES, SKIP IT MOVE T1,AVLTSK(Q1) ;GET POINTER TO DEVELOPER STRING MOVE T1,TSKLST(T1) ;GET TASK ADR LOAD T2,TKPRJ,(T1) ;GET PROJECT LIST ADDRESS LOAD Q3,TKDVL,(T1) ;GET TASK DEVELOPER LIST SKIPN Q3 ;ANY THERE? LOAD Q3,PJDVL,(T2) ;NO, GET PROJECT LIST SKIPN Q3 ;IS THERE A LIST? MOVE Q3,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q3,FNDAV3 ;IF NO LIST, GO SCHEDULE THIS ONE FNDAV8: MOVE T1,AVLTSK(Q2) ;NOW GET THE SECOND TASK'S DEVELOPER LIST MOVE T1,TSKLST(T1) ;GET TASK ADR LOAD T2,TKPRJ,(T1) ;GET ADR OF PROJECT BLOCK LOAD T4,TKDVL,(T1) ;GET TASK DEVELOPER LIST SKIPN T4 ;ANY THERE? LOAD T4,PJDVL,(T2) ;NO, GET PROJECTS LIST SKIPN T4 ;IS THERE A LIST? MOVE T4,DEVTBP ;NO, GET THE OVERALL LIST JUMPE T4,FNDAV5 ;IF NONE, THEN NO MATCH FNDAV7: LOAD T1,DVNAM,(Q3) ;GET ADR OF NAME STRING LOAD T2,DVNAM,(T4) ;GET SECOND NAME STRING FNDAV6: MOVE T3,(T1) ;GET NEXT WORD IN STRING CAME T3,(T2) ;MATCH? JRST FNDAV5 ;NO, GO ON TO NEXT DEVELOPER TRNN T3,377 ;REACHED END OF NAME STRING? JRST FNDAV4 ;YES, FOUND A MATCH AOS T1 ;NOT AT END, STEP TO NEXT WORD AOJA T2,FNDAV6 ;LOOP BACK FOR REST OF STRING COMPARE FNDAV5: LOAD T4,DVLNK,(T4) ;STEP TO NEXT DEVELOPER IN LIST JUMPN T4,FNDAV7 ;IF MORE, GO COMPARE THESE NAMES LOAD Q3,DVLNK,(Q3) ;STEP TO NEXT DEVELOPER IN OTHER LIST JUMPN Q3,FNDAV8 ;IF MORE, GO COMPARE THEM JRST FNDAV2 ;NO MATCHES HERE, GO TRY OTHER TASKS FNDAV4: AOBJN Q1,FNDAV1 ;YES, GO LOOK AT THE OTHER TASKS RET ;NO FREE DEVELOPERS FNDAV3: HRRZ T1,Q1 ;RETURN THE INDEX FOR THIS TASK RETSKP ;ROUTINE TO SCHEDULE AN ENTIRE TASK GROUP ;ACCEPTS IN T1/ GROUP NUMBER ; CALL SKDTG ;RETURNS +1: DONE SKDTG: SAVEQ STKVAR AOS T4,SKDCNT ;STEP SKDCNT HRRZM T1,SKDLST-1(T4) ;SAVE GROUP NUMBER IN SKDLST MOVE Q1,T1 ;SAVE GROUP NUMBER MOVN Q2,AVLCNT ;SET UP POINTER TO LIST HRLZS Q2 MOVE Q3,Q2 ;Q3 = AOBJN POINTER SKDTG1: MOVSI T1,(1B0) ;CLEAR SCHEDULE FLAG ANDCAM T1,AVLTSK(Q3) AOBJN Q3,SKDTG1 MOVE Q3,Q2 ;SET UP POINTER AGAIN SKDTG2: MOVE T1,SKDTAD ;GET SCHEDULER START DATE SETZ T2, ;NO LAST TASK SCHEDULED MOVE T3,Q1 ;GET GROUP NUMBER CALL GETLFT ;GET NEXT TASK TO SCHEDULE JRST SKDTG3 ;NO MORE TASKS TO DO MOVSI T2,(1B0) ;SCHEDULE THIS ONE IORM T2,AVLTSK(T1) MOVE T2,AVLSDL(T1) ;GET THE START DATE HRRZ T1,AVLTSK(T1) ;GET THE TASK ADDRESS HRRZ T3,TSKLST(T1) MOVEM T1,SKDTGI ;SAVE INDEX INTO TSKLST LOAD T1,TKDVL,(T3) ;GET POINTER TO DEVELOPER LIST LOAD T4,TKPRJ,(T3) ;GET POINTER TO PROJECT BLOCK SKIPN T1 ;IS THERE A TASK LIST LOAD T1,PJDVL,(T4) ;NO, GET THE PROJECT LIST SKIPN T1 ;ANY THERE YET? MOVE T1,DEVTBP ;NO, GET THE OVERALL LIST POINTER CALL SCHED ;GO SCHEDULE THEM MOVE T3,SKDTGI ;GET INDEX INTO TSKLST TLNN T2,-1 ;IS THERE A START DATE? MOVE T2,T1 ;NO, USE THE FINISH DATE MOVEM T1,TSKFDL(T3) ;SAVE THE FINISH DATE MOVEM T2,TSKSDL(T3) ;SAVE THE START DATE AOBJN Q3,SKDTG2 ;LOOP BACK FOR ALL TASKS SKDTG3: MOVSI T1,(1B0) ;CLEAR THE FLAGS ANDCAM T1,AVLTSK(Q2) AOBJN Q2,SKDTG3 RET ;ROUTINE TO GET THE LATEST FINISHING TASK ;ACCEPTS IN T1/ SCHEDULER START DATE ; T2/ ADR OF LAST TASK SCHEDULED ; T3/ -1 = FREE CHOICE, N = GROUP NUMBER ; CALL GETLFT ;RETURNS +1: NO MORE TASKS IN THIS GROUP ; +2: T1/ INDEX INTO AVLTSK LIST ;RULES FOR CHOOSING A FREE TASK ;1) IF THERE IS A GROUP NUMBER SPECIFIED, THEN THE ; TASK MUST BE FROM THAT GROUP. ;2) THE TASK MUST HAVE THE HIGHEST PREFERENCE VALUE ; FOUND WITHIN THE GROUP. ;3) IF THERE WAS A "LAST TASK" SPECIFIED, THEN USE A TASK ; FROM THE SAME PROJECT AS LAST TASK (IF ANY). ;4) CHOSE THE TASK THAT CAN BE STARTED AT THE EARLIEST ; POSSIBLE TIME. ;5) IF MULTIPLE CHOICE STILL REMAINS, CHOSE THE LONGEST TASK. GETLFT: SAVEPQ DMOVE Q1,T1 ;SAVE THE ARGS MOVE Q3,T3 MOVE T1,Q3 ;GET THE GROUP NUMBER CALL GETHPV ;GET THE HIGHEST PREFERENCE VALUE RET ;NONE FOUND MOVEM T1,P2 ;SAVE THE PREFERENCE VALUE MOVE T1,Q3 ;GET THE GROUP NUMBER MOVE T2,P2 ;GET THE PREFERENCE VALUE SKIPE T3,Q2 ;ANY "LAST TASK" SPECIFIED? LOAD T3,TKPRJ,(Q2) ;YES, GET THE PROJECT ADR MOVE T4,Q1 ;GET THE SCHEDULER START DATE CALL GETLTA ;GET THE LONGEST TASK SKIPA ;NOT FOUND RETSKP ;DONE MOVE T1,Q3 ;TRY AGAIN FOR ANY TASK MOVE T2,P2 ;PREFERENCE VALUE SETZ T3, ;NO "LAST TASK" THIS TIME MOVE T4,Q1 ;START DATE CALL GETLTA ;GET LONGEST TASK RET ;NONE RETSKP ;FOUND IT ;ROUTINE TO GET THE HIGHEST PREFERENCE VALUE WITHIN A GROUP ;ACCEPTS IN T1/ GROUP # OR -1 IF NONE ;RETURNS +1: NONE FOUND ; +2: T1/ PREFERENCE VALUE GETHPV: SAVEQ MOVE Q1,T1 ;SAVE THE GROUP NUMBER MOVSI Q2,(1B0) ;GET THE LOWEST NEG NUMBER MOVN Q3,AVLCNT ;SET UP TO SCAN AVLTSK LIST HRLZS Q3 GETHP1: HLRZ T1,AVLTSK(Q3) ;GET THE GROUP NUMBER CAME T1,Q1 ;A MATCH? JUMPGE Q1,GETHP2 ;NO, SKIP IT UNLESS NO GROUP NUMBER HRRZ T1,AVLTSK(Q3) ;GET TASK ADR MOVE T1,TSKLST(T1) CALL GETPRF ;GET THE PREFERENCE VALUE OF THIS TASK CAMLE T1,Q2 ;GOT A NEW HIGH? MOVEM T1,Q2 ;YES, SAVE IT GETHP2: AOBJN Q3,GETHP1 ;LOOP BACK FOR ALL TASKS IN LIST MOVE T1,Q2 ;GET THE ANSWER CAMG T1,[1B0] ;DID WE FIND ANY AT ALL? RET ;NO RETSKP ;YES ;ROUTINE TO GET THE PREFERENCE VALUE OF A TASK ;ACCEPTS IN T1/ TASK ADR ;RETURNS +1: T1/ PREFERENCE VALUE GETPRF: LOAD T2,TKPRJ,(T1) ;GET PROJECT ADR LOAD T2,PJPRF,(T2) ;GET THE PROJECT PREFERENCE VALUE LOAD T1,TKPRF,(T1) ;GET THE TASK PREFERENCE VALUE FADR T1,T2 ;SUM THEM RET ;RETURN THE ANSWER ;ROUTINE TO GET THE LONGEST TASK ;ACCEPTS IN T1/ GROUP # OR -1 IF NONE ; T2/ PREFERENCE VALUE ; T3/ PROJECT ADR OR 0 IF NONE ; T4/ SCHEDULER START DATE ;RETURNS +1: NONE FOUND ; +2: T1/ INDEX INTO AVLTSK LIST GETLTA: SAVEPQ STKVAR DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 SETOM GETLTC ;ASSUME A CRITICAL PATH TO START CALL CHKCP ;GO SEE IF THERE ARE ANY CRITICAL TASKS SETZM GETLTC ;NONE FOUND DMOVE T1,P1 ;GET ARGS DMOVE T3,P3 CALL GETETA ;GET THE EARLIEST STARTING DATE RET ;NONE FOUND CAMGE T1,P4 ;BEFORE SCHEDULER START DATE? MOVE T1,P4 ;YES, USE SCHEDULER START DATE MOVEM T1,Q1 ;SAVE THE START DATE SETO Q2, ;INIT TASK ADR SETOM GETLTT ;INIT TASK ADR BACKUP (IF OPTIMUM NOT FOUND) SETZM GETLTL ;INIT LONGEST TASK FINISH DATE MOVN Q3,AVLCNT ;SET UP POINTER TO AVLTSK HRLZS Q3 GETLT1: HLRZ T1,AVLTSK(Q3) ;GET THE GROUP NUMBER CAME T1,P1 ;A MATCH? JUMPGE P1,GETLT2 ;NO, UNLESS NO GROUP # SPECIFIED HRRZ T1,AVLTSK(Q3) ;GET TASK ADR MOVE T1,TSKLST(T1) LOAD T3,TKFLG,(T1) ;CHECK THE CRITICAL PATH TXNN T3,TK%CP ;IS THIS A CRITICAL TASK SKIPN GETLTC ;NO, DOES IT HAVE TO BE ONE? SKIPA ;NO, OK JRST GETLT2 ;NOT CRITICAL, GO TO NEXT TASK LOAD T2,TKPRJ,(T1) ;GET THE PROJECT ADR CAME T2,P3 ;FOUND A MATCH? JUMPG P3,GETLT2 ;NO, UNLESS NONE SPECIFIED CALL GETPRF ;GET PREFERENCE VALUE CAME T1,P2 ;HIGH ENOUGH? JRST GETLT2 ;NO HRRZM Q3,GETLTT ;REMEMBER THIS ONE IN CASE OPTIMUM NOT FOUND MOVE T2,AVLSDL(Q3) ;GET THE START DATE CAMLE T2,Q1 ;EARLY ENOUGH? JRST GETLT2 ;NO HRRZ T1,AVLTSK(Q3) ;GET INDEX INTO TSKLST CALL GETFD ;GET FINISH DATE CAMG T1,GETLTL ;IS THIS A NEW LONGEST? JRST GETLT2 ;NO MOVEM T1,GETLTL ;YES, SAVE IT HRRZ Q2,Q3 ;AND ALSO REMEMBER THE INDEX INTO AVLTSK GETLT2: AOBJN Q3,GETLT1 ;LOOP BACK FOR ALL TASKS IN LIST SKIPGE T1,Q2 ;FOUND ANY? SKIPL T1,GETLTT ;WAS A BACKUP ADR FOUND? RETSKP ;YES RET ;NONE AT ALL ;ROUTINE TO GET THE EARLIEST STARTING TASK ;ACCEPTS IN T1/ GROUP # OR -1 IF NONE ; T2/ PREFERENCE VALUE ; T3/ PROJECT ADR OR 0 IF NONE ;RETURNS +1: NONE FOUND ; +2: T1/ INDEX INTO AVLTSK LIST GETETA: SAVEPQ DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 HRLOI Q1,377777 ;INIT EARLIEST DATE MOVN Q3,AVLCNT ;SET UP POINTER TO AVLTSK HRLZS Q3 GETET1: HLRZ T1,AVLTSK(Q3) ;GET THE GROUP NUMBER CAME T1,P1 ;A MATCH? JUMPGE P1,GETET2 ;NO, UNLESS NO GROUP # SPECIFIED HRRZ T1,AVLTSK(Q3) ;GET TASK ADR MOVE T1,TSKLST(T1) LOAD T2,TKPRJ,(T1) ;GET THE PROJECT ADR CAME T2,P3 ;FOUND A MATCH? JUMPG P3,GETET2 ;NO, UNLESS NONE SPECIFIED CALL GETPRF ;GET PREFERENCE VALUE CAME T1,P2 ;HIGH ENOUGH? JRST GETET2 ;NO MOVE T2,AVLSDL(Q3) ;GET THE START DATE CAMGE T2,Q1 ;NEW EARLIEST DATE? MOVEM T2,Q1 ;YES, SAVE IT GETET2: AOBJN Q3,GETET1 ;LOOP BACK FOR ALL TASKS IN LIST MOVE T1,Q1 ;GET DATE CAMN T1,[377777,,777777] ;FOUND ANY? RET ;NO RETSKP ;YES ;ROUTINE TO CHECK FOR CRITICAL PATH TASKS ;ACCEPTS IN T1/ GROUP # OR -1 IF NONE ; T2/ PREFERENCE VALUE ; T3/ PROJECT ADR OR 0 IF NONE ;RETURNS +1: NONE FOUND ; +2: THERE IS AT LEAST ONE CRITICAL PATH TASK CHKCP: SAVEPQ DMOVE P1,T1 ;SAVE THE ARGS DMOVE P3,T3 MOVN Q3,AVLCNT ;SET UP POINTER TO AVLTSK HRLZS Q3 CHKCP1: HLRZ T1,AVLTSK(Q3) ;GET THE GROUP NUMBER CAME T1,P1 ;A MATCH? JUMPGE P1,CHKCP2 ;NO, UNLESS NO GROUP # SPECIFIED HRRZ T1,AVLTSK(Q3) ;GET TASK ADR MOVE T1,TSKLST(T1) LOAD T2,TKPRJ,(T1) ;GET THE PROJECT ADR CAME T2,P3 ;FOUND A MATCH? JUMPG P3,CHKCP2 ;NO, UNLESS NONE SPECIFIED CALL GETPRF ;GET PREFERENCE VALUE CAME T1,P2 ;HIGH ENOUGH? JRST CHKCP2 ;NO HRRZ T1,AVLTSK(Q3) ;GET TASK INDEX MOVE T1,TSKLST(T1) ;GET TASK ADR JN TKCP,(T1),RSKP ;IF CRITICAL PATH, RETURN IMMEDIATELY CHKCP2: AOBJN Q3,CHKCP1 ;LOOP BACK FOR ALL TASKS IN LIST RET ;NONE FOUND ;ROUTINE TO GET THE FINISHING DATE OF A TASK ;ACCEPTS IN T1/ INDEX INTO TSKLST ; T2/ START DATE ; CALL GETFD ;RETURNS +1: ALWAYS, T1/ FINISH DATE GETFD: MOVE T1,TSKLST(T1) ;GET ADR OF TASK MOVE T3,T1 ;T3 = TASK ADR LOAD T4,TKDVL,(T1) ;GET ADR OF DEVELOPER LIST JUMPN T4,GETFD1 ;ONE THERE? LOAD T4,TKPRJ,(T1) ;NO, GET PROJECT LIST LOAD T4,PJDVL,(T4) SKIPN T4 ;IS THERE A LIST? MOVE T4,DEVTBP ;NO, GET THE OVERALL LIST GETFD1: MOVE T1,T4 ;SET UP ADR OF FIRST DEVELOPER BLOCK CALL NSCHED ;GO GET FINISH DATE RET ;ROUTINE TO CHECK IF A LOOP HAS BEEN FOUND IN THE DEPENDENCY LIST CHKLOP: MOVE T1,TSKPTR ;GET POINTER TO TASK LIST CHKLP1: SKIPN TSKFDL(T1) ;BEEN SCHEDULED? RET ;NO, THEN A LOOP EXISTS AOBJN T1,CHKLP1 ;LOOP BACK FOR ALL TASKS RETSKP ;EVERY TASK HAS BEEN SCHEDULED ;ROUTINE TO CHECK IF A NEW BEST RUN WAS MADE CHKBST: MOVE T1,TSKPTR ;SET UP TO SCAN TSKLST MOVEI T2,0 ;INIT ENDING DATE CHKBS1: CAMGE T2,TSKFDL(T1) ;FOUND A NEW END DATE? MOVE T2,TSKFDL(T1) ;YES, REMEMBER IT AOBJN T1,CHKBS1 ;LOOP THRU ALL TASKS CAML T2,BESTFD ;FOUND A NEW BEST? RET ;NO MOVEM T2,BESTFD ;REMEMBER THE NEW BEST FINISH DATE MOVE T1,LVL0TK ;AND THE TASK ADR MOVEM T1,BESTSK RET ;ROUTINE TO SCHEDULE A LIST OF DEVELOPERS ;ACCEPTS IN T1/ ADR OF FIRST DEVELOPER BLOCK IN CHAIN ; T2/ START DATE ; T3/ ADR OF TASK BLOCK ; CALL SCHED OR CALL NSCHED (FOR FINISH DATE ONLY) ;RETURNS +1: ALWAYS, T1/ FINISH DATE ; T2/ START DATE NSCHED: TDZA T4,T4 ;DO NOT SCHEDULE THE DEVELOPERS SCHED: SETO T4, ;SCHEDULE SAVEPQ ;SAVE SOME AC'S ;***WARNING*** TRVAR USES P6 FOR THE FRAME POINTER TRVAR ,SCHEDF,,SCHEDT,,,SCHEDR,SCHEDP,SCHEDV,SCHEDC> DMOVE P1,T1 ;COPY ARGUMENTS DMOVE P3,T3 ; .. MOVEM T3,SCHEDR JUMPE T1,SCHEDX ;SPECIAL IF NO DEVELOPERS LOAD Q1,TKADR,(P3) ;ALL-DEVELOPERS-REQUIRED? JUMPE Q1,SCHEDX ;NO--DO STANDARD THING LOAD Q1,DVLNK,(P1) ;SEE IF ONLY ONE DEVELOPER JUMPE Q1,SCHEDX ;JUST DO THAT IF TRUE LOAD Q1,TKELN,(P3) ;ESTIMATED LENGTH JUMPE Q1,SCHEDX ;MUST BE NON-ZERO ;COPY TASK BLOCK HRL T1,P3 ;SOURCE OF BLT HRRI T1,SCHTKB ;DESTINATION MOVEI T2,-1+SCHTKB ;WHERE TO STOP ADDI T2,.TKLEN ; .. BLT T1,(T2) ;COPY THE BLOCK ;SUM ALL DEVELOPERS MOVEI P5,0 ;INITIAL SUM MOVE T2,P1 ;FIRST DEVELOPER XSCH1: LOAD T3,DVRAT,(T2) ;GET RATE FADR P5,T3 ;ADD TO SUM LOAD T2,DVLNK,(T2) ;STEP TO NEXT BLOCK JUMPN T2,XSCH1 ;LOOP OVER ALL DEVELOPERS MOVEM P4,SCHEDP ;SAVE THE SCHED/NSCHED FLAG SETZ P4, ;AND MARK AS NSCHED MOVEM P1,SCHEDV ;SAVE LIST OF DEVELOPERS XSCH2: MOVE P1,SCHEDV ;RESET TO TOP OF LIST CALL XSCH3 ;FIND LATEST STARTING DATE JRST XSCH2 ;SOMETHING GOT LATER SKIPN P4,SCHEDP ;REALY WANT TO SCHEDULE? RET ;NO--WE HAVE THE DATES MOVE P1,SCHEDV ;RESET TO TOP OF LIST CALL XSCH3 ;YES--GO DO IT AGAIN ERRMES RET ;ALL DONE ;NOW DO EACH DEVELOPER ACCORDING TO HIS ABILITY XSCH3: HRLOI Q2,377777 ;MAX START DATE MOVEI Q1,0 ;MIN END DATE XSCH4: MOVEI T2,SCHDVB ;ADDRESS OF DUMMY BLOCK LOAD T1,DVNAM,(P1) ;COPY PARAMETERS STOR T1,DVNAM,(T2) LOAD T1,DVRAT,(P1) STOR T1,DVRAT,(T2) LOAD T1,DVHCR,(P1) STOR T1,DVHCR,(T2) MOVE T1,P3 STOR T1,DVBKP,(T2) SETZRO DVLNK,(T2) ;NO LINK LOAD T1,DVRAT,(T2) ;GET THIS RATE FDVR T1,P5 ;FRACTION OF TOTAL MOVEI T4,SCHTKB LOAD T2,TKELN,(P3) ;GET ESTIMATED LENGTH FMPR T2,T1 ;SCALE FOR THIS DEVELOPER STOR T2,TKELN,(T4) ;ONLY SCHEDULE PART LOAD T2,TKTTD,(P3) ;ALSO SCALE TIME TO DATE FMPR T2,T1 STOR T2,TKTTD,(T4) MOVEI T1,SCHDVB ;FAKE DEVELOPER BLOCK MOVE T2,P2 ;START DATE MOVEI T3,SCHTKB ;FAKE TASK BLOCK MOVE T4,P4 ;FLAG CALL SCHEDX ;GO DO IT CAMLE T2,P2 ;DID START GET LATER? JRST [ MOVE P2,T2 ;YES--ADJUST START RET] ;DO WHOLE THING OVER CAMGE T2,Q2 ;EARLIER START DATE? MOVE Q2,T2 ;YES--REMEMBER THAT CAMLE T1,Q1 ;LATER END DATE? MOVE Q1,T1 ;YES--REMEMBER THAT LOAD P1,DVLNK,(P1) ;STEP TO NEXT DEVELOPER JUMPN P1,XSCH4 ;LOOP OVER ALL DEVELOPERS DMOVE T1,Q1 ;COPY DATES RETSKP ;ALL DONE ;SUBROUTINE OF SCHED. CALLED ONLY FROM ABOVE (USES SCHED TRVAR'S) SCHEDX: SAVEPQ MOVEM T1,SCHEDA ;SAVE ADR OF DEVELOPER LIST MOVEM T2,SCHEDD ;SAVE STARTING DATE SETZM SCHEDS ;INIT START DATE ANSWER MOVEM T3,SCHEDT ;SAVE TASK ADR MOVEM T3,LSTSKT ;REMEMBER THE LAST TASK SCHEDULED MOVEM T4,SCHEDF ;SAVE FLAG LOAD T2,TKAFD,(T3) ;IS THERE A FINISH DATE? LOAD T4,TKALN,(T3) ;GET THE ACTUAL LENGTH SKIPN T2 LOAD T4,TKELN,(T3) ;NOT FINISHED, USE THE ESTIMATED LENGTH JUMPE T2,SCHED0 ;IS THERE A FINISH DATE? SKIPN T3,SCHEDD ;YES, IS THERE A START DATE? MOVEM T2,SCHEDD ;NO, SAVE FINISH DATE AS START DATE SKIPN T3 ;WAS THERE A START DATE? SETZ T4, ;NO, MAKE THE TASK LENGTH BE 0 SCHED0: MOVEM T4,SCHEDL ;SAVE LENGTH MOVE T4,SCHEDT ;GET TASK BLOCK ADR LOAD T3,TKTTD,(T4) ;GET THE TIME-TO-DATE MOVNS T3 ;NEGATE IT FADRM T3,SCHEDL ;DECREMENT LENGTH BY WHAT SPENT SO FAR MOVE T3,SCHEDL ;GET REMAINING AMOUNT JUMPE T1,SCHED4 ;IF NO DEVELOPER, SPECIAL CASE SCHED1: MOVEI Q1,-1+SCHEDQ ;SET UP POINTER TO QUEUE HRLI Q1,-MAXDEV HRLOI Q2,377777 ;INIT TO LATEST DATE MOVE Q3,SCHEDA ;GET ADR OF DEVELOPER LIST SETZB P1,P4 ;INIT COUNTS SCHED2: LOAD T1,DVNAM,(Q3) ;GET DEVELOPER NAME MOVE T2,SCHEDD ;GET START DATE MOVE T3,SCHEDT ;GET THE TASK ADR CALL FNDCHG ;FIND WHEN THE NEXT CHANGE HAPPENS CAMGE T1,Q2 ;FOUND A NEW LOW? MOVE Q2,T1 ;YES LOAD T3,DVRAT,(Q3) ;GET RATE OF PROGRESS CAMLE T3,T2 ;GET MIN OF REMAINING AND ALLOWED RATES MOVE T3,T2 ;USE THE REMAINING RATE FOR THIS USER PUSH Q1,T3 ;SAVE IT AOS P4 ;REMEMBER THE COUNT LOAD T4,DVHCR,(Q3) ;GET HANDICAP FMPR T3,T4 ;GET REAL RATE OF PROGRESS FADR P1,T3 ;SUM THE RATES LOAD Q3,DVLNK,(Q3) ;STEP TO NEXT DEVELOPER JUMPN Q3,SCHED2 ;IF ANOTHER, GO GET RATE ; .. ; .. MOVE T2,Q2 ;GET DATE OF CHANGE MOVE T1,SCHEDD ;GET NUMBER OF DAYS TO BE SPENT CALL GETNWD ;GET NUMBER OF WORKING DAYS BETWEEN DATES FLTR T2,T1 ;FLOAT NUMBER OF DAYS FMPR T2,P1 ;GET NUMBER OF DAYS COMPLETED THIS PERIOD CAMLE T2,SCHEDL ;ENOUGH TO COVER THE REMAINING TIME? MOVE T2,SCHEDL ;YES MOVE T3,SCHEDL ;GET REMAINING TIME ON TASK FSBR T3,T2 ;CALCULATE THE DIFFERENCE MOVEM T3,SCHEDL ;REMEMBER THE REMAINING TIME FDVR T2,P1 ;INCLUDE THE RATE SKEW FIXR T2,T2 ;GET INTEGER DAYS MOVE P2,SCHEDD ;GET START DATE MOVE T1,SCHEDD ;GET FINISH DATE GIVEN THE NUMBER OF DAYS CALL GETNFD MOVEM T1,SCHEDD ;SAVE THE NEW FINISH DATE SKIPE T3,SCHEDL ;FINISHED YET? MOVEM Q2,SCHEDD ;NO, THEN NEW FINISH DATE IS CHANGE DATE SKIPE SCHEDL ;DONE? JUMPE P1,SCHED1 ;NO, IF RATE WAS ZERO, DONT SCHEDULE SKIPN SCHEDS ;IS THIS THE FIRST START DATE FOUND? MOVEM P2,SCHEDS ;YES, REMEMBER THIS ONE MOVEI Q1,SCHEDQ ;GET POINTER TO START OF QUEUE MOVE Q3,SCHEDA ;GET ADR OF DEVELOPER LIST AGAIN SCHED3: LOAD T1,DVNAM,(Q3) ;GET DEVELOPER NAME MOVEM T1,0+SCHEDB ;SAVE IT IN ARG BLOCK MOVEM P2,1+SCHEDB ;SAVE START DATE IN ARG BLOCK MOVE T1,SCHEDD ;GET FINISH DATE MOVEM T1,2+SCHEDB ;SAVE FINISH DATE IN ARG BLOCK MOVE T1,(Q1) ;GET RATE MOVEM T1,3+SCHEDB ;SAVE RATE MOVE T1,SCHEDR ;GET TASK ADR MOVEM T1,4+SCHEDB MOVEI T1,SCHEDB ;GET ADR OF TASK BLOCK SKIPE SCHEDF ;SCHEDULE? CALL SCHDEV ;YES, GO SCHEDULE THIS DEVELOPER LOAD Q3,DVLNK,(Q3) ;STEP TO NEXT DEVELOPER AOS Q1 SOSLE P4 ;ANY MORE TO BE DONE? JUMPN Q3,SCHED3 ;YES, LOOP BACK FOR REST SKIPLE SCHEDL ;ANY MORE MORE TO BE DONE? JRST SCHED1 ;YES, GO SCHEDULE IT SCHED5: MOVE T1,SCHEDD ;RETURN THE FINAL FINISH DATE SKIPN T2,SCHEDS ;GET START DATE MOVE T2,T1 ;IF NONE, USE THE FINISH DATE RET SCHED4: MOVE T1,SCHEDD ;GET FINISH DATE FIXR T2,T3 ;GET NUMBER OF WORK DAYS MOVE T4,SCHEDT ;GET ADDRESS OF TASK BLOCK LOAD T3,TKTTD,(T4) ;GET TIME TO DATE SKIPE T3 ;OK IF ZERO LOAD T1,TKTAD,(T4) ;ELSE ASSUME STARTED AT TIME-TO-DATE ;DATE MOVEM T1,SCHEDC ;SAVE FOR LATER CALL GETNFD ;GET THE FINISH DATE MOVE Q1,T1 ;SAVE FINISH DATE MOVEI T1,[ASCIZ/UNKNOWN/] MOVE T2,SCHEDC ;SCHEDULE TASK TO "UNKNOWN" DEVELOPER MOVE T3,Q1 ;GET FINISH DATE MOVSI T4,(1.0) ;RATE = 1.0 MOVEM T1,0+SCHEDB ;SET UP ARG BLOCK - DEV NAME MOVEM T2,1+SCHEDB ;START DATE MOVEM T3,2+SCHEDB ;FINISH DATE MOVEM T4,3+SCHEDB ;RATE MOVE T1,SCHEDR ;TASK BLOCK ADR MOVEM T1,4+SCHEDB MOVEI T1,SCHEDB ;GET ADR OF ARG BLOCK SKIPE SCHEDF ;SCHEDULE? CALL SCHDEV ;YES MOVE T1,Q1 ;RETRUN FINISH DATE MOVE T2,SCHEDD ;RETURN START DATE IN T2 RET ;ROUTINE TO FIND WHEN THE NEXT RATE CHANGE HAPPENS ;ACCEPTS IN T1/ ADR OF NAME STRING ; T2/ START DATE ; T3/ TASK ADR ; CALL FNDCHG ;RETURNS +1: ALWAYS, T1/ DATE OF NEXT CHANGE ; T2/ FRACTIONAL RATE REMAINING TO BE USED FNDCHG: SAVEQ STKVAR SETZM FNDCHF ;INIT THE FLAG LOAD T4,TKTAD,(T3) ;IS THERE AN INTERMEDIARY DATE? CAMGE T2,T4 ;THAT IS GREATER THAN THE START DATE? JRST FNDCH6 ;YES, GO USE IT LOAD T4,TKPRJ,(T3) ;GET THE PROJECT ADR MOVEM T4,FNDCHP ;SAVE IT HRLI T1,(POINT 7,0) ;GET BYTE POINTER TO NAME STRING MOVEM T1,FNDCHN ;SAVE POINTER TO NAME STRING MOVEM T2,FNDCHD ;SAVE THE START DATE MOVSI Q1,(1.0) ;GET INITIAL RATE MOVSI Q2,(1.0) ;START PROJECT ALLOTMENT AT 1.0 LOAD T4,TKDVL,(T3) ;GET POINTER TO TASK DEVELOPER LIST JUMPN T4,FNDCH0 ;IF ANY, THEN NO PROBLEM MOVE T4,FNDCHP ;GET PROJECT ADR LOAD Q3,PJDVL,(T4) ;GET POINTER TO DEV LIST FOR PROJECT MOVEM Q3,FNDCHF ;SAVE POINTER TO PROJECT LIST IF ANY SKIPN Q3 ;IS THERE A LIST? MOVE Q3,DEVTBP ;NO, GET THE OVERALL LIST JUMPE Q3,FNDCH0 ;IF NONE, THEN DONE FNDCH4: HRRZ T1,FNDCHN ;GET THE POINTER TO THE NAME STRING LOAD T2,DVNAM,(Q3) ;GET ADR OF NAME STRING FNDCH7: MOVE T3,(T1) ;GET NEXT WORD TO COMPARE MOVE T4,(T2) CAME T3,T4 ;MATCH? JRST FNDCH5 ;NO AOS T2 ;STEP TO NEXT WORD TRNE T3,377 ;AT END OF NAME AOJA T1,FNDCH7 ;NO, LOOP BACK FORREST OF WORDS LOAD Q2,DVRAT,(Q3) ;YES, GET ITS RATE JRST FNDCH0 ;DONE FNDCH5: LOAD Q3,DVLNK,(Q3) ;STEP TO NEXT DEVELOPER JUMPN Q3,FNDCH4 ;LOOP BACK IF ANY MORE TO DO FNDCH0: MOVE T1,FNDCHN ;GET POINTER TO NAME STRING HRLOI Q3,377777 ;GET LATEST DATE CALL DEVLUK ;LOOKUP THIS DEVELOPER JRST FNDCH3 ;NOT FOUND, ASSUME AVAILABLE FULL TIME HRRZ T1,(T1) ;GET POINTER TO DEVELOPER SCHEDULE FNDCH1: LOAD T2,SCHFD,(T1) ;GET FINISH DATE CAMLE T2,FNDCHD ;END AFTER START DATE? JRST FNDCH2 ;YES, FOUND FIRST POSSIBLE CONFLICT LOAD T1,SCHLN,(T1) ;STEP TO NEXT ITEM JUMPN T1,FNDCH1 ;IF MORE, LOOP BACK JRST FNDCH3 ;IF NO MORE, THEN DEVELOPER AVAILABLE FNDCH2: CAMGE T2,Q3 ;FOUND A NEW CHANGE DATE? MOVE Q3,T2 ;YES, REMEMBER IT LOAD T2,SCHSD,(T1) ;GET STARTING DATE CAMLE T2,FNDCHD ;IS START DATE AFTER OUR START DATE? JRST [ CAMGE T2,Q3 ;YES, IS THIS A NEW CHANGE DATE MOVE Q3,T2 ;YES JRST FNDCH3] ;GO RETURN ANSWER LOAD T2,SCHRT,(T1) ;GET RATE ON THIS TASK FSBR Q1,T2 ;GET REMAINDER FOR THIS DEVELOPER LOAD T3,SCHTK,(T1) ;GET THE TASK ADR LOAD T3,TKPRJ,(T3) ;GET THE PROJECT ADR SKIPE FNDCHF ;IF NO PROJECT LIST, THEN COUNT UP THIS CAMN T3,FNDCHP ;THIS BELONG TO THIS PROJECT? FSBR Q2,T2 ;YES LOAD T1,SCHLN,(T1) ;STEP TO NEXT TASK IN LIST JUMPN T1,FNDCH1 ;LOOP BACK TILL CORRECT POSITION FOUND FNDCH3: MOVE T1,Q3 ;RETURN DATE OF NEXT CHANGE MOVE T2,Q1 ;GET REMAINING RATE CAMLE Q1,Q2 ;GET THE LOWEST RATE REMAINING MOVE T2,Q2 SKIPGE T2 ;NEGATIVE RATE? MOVEI T2,0 ;YES, LEAVE IT AT ZERO RET FNDCH6: LOAD T1,TKTAD,(T3) ;CHANGE DATE IS AS SPECIFIED MOVE T2,[0.0000001] ;GIVE A VERY SMALL BUT NON-ZERO TIME FOR IT RET ;ROUTINE TO SCHEDULE A DEVELOPER ;ACCEPTS IN T1/ ADR OF ARG BLOCK ;WHERE ARG+0/ ADR OF NAME STRING ; ARG+1/ START DATE ; ARG+2/ FINISH DATE ; ARG+3/ RATE ; ARG+4/ TASK BLOCK ADR ;CALL SCHDEV ;RETURNS +1: ALWAYS SCHDEV: SAVEQ STKVAR MOVE T2,0(T1) ;GET ADR OF NAME STRING HRLI T2,(POINT 7,0) ;GET BYTE POINTER TO NAME STRING MOVEM T2,SCHDVN ;SAVE NAME STRING POINTER MOVE T2,1(T1) ;GET START DATE MOVEM T2,SCHDVS MOVE T2,2(T1) ;GET FINISH DATE MOVEM T2,SCHDVF MOVE T2,3(T1) ;GET RATE MOVEM T2,SCHDVR MOVE T2,4(T1) ;GET TASK ADR MOVEM T2,SCHDVT MOVEI T1,.SCHLN ;CREATE A BLOCK FOR THIS ENTRY CALL ASGSCH ;GET FREE SPACE FOR IT ERRMES () MOVE Q1,T1 ;SAVE ADR OF FREE SPACE BLOCK MOVE T2,SCHDVS ;GET START DATE STOR T2,SCHSD,(Q1) ;SET UP BLOCK MOVE T2,SCHDVF ;GET FINISH DATE STOR T2,SCHFD,(Q1) MOVE T2,SCHDVR ;GET RATE STOR T2,SCHRT,(Q1) MOVE T2,SCHDVT ;GET TASK BLOCK ADR STOR T2,SCHTK,(Q1) ;SAVE IT IN THE BLOCK MOVE T1,SCHDVN ;GET POINTER TO NAME STRING CALL DEVLUK ;LOOKUP NAME IN TABLE JRST SCHDV4 ;NOT THERE, GO ADD IT HRRZ T2,0(T1) ;GET POINTER TO FIRST ITEM IN LIST LOAD T3,SCHSD,(T2) ;SEARCH FOR PLACE TO PUT THIS ONE CAML T3,SCHDVS ;KEEP LIST IN CHRONOLOGICAL ORDER JRST SCHDV3 ;ENTRY BELONGS AS FIRST ONE SCHDV1: MOVE T1,T2 ;SAVE POINTER LOAD T2,SCHLN,(T1) ;GET POINTER TO NEXT ITEM JUMPE T2,SCHDV2 ;NO MORE LOAD T3,SCHSD,(T2) ;GET START DATE OF NEXT ONE CAMGE T3,SCHDVS ;FOUND THE RIGHT PLACE? JRST SCHDV1 ;NO, LOOP BACK TIL FOUND SCHDV2: STOR T2,SCHLN,(Q1) ;YES, STORE THE ITEM HERE STOR Q1,SCHLN,(T1) ;MAKE PREVIOUS ONE POINT HERE RET ;DONE SCHDV3: STOR T2,SCHLN,(Q1) ;PUT THIS ONE AT FRONT OF LIST HRRM Q1,0(T1) RET SCHDV4: MOVE T1,SCHDVN ;GET POINTER TO THE NAME STRING SETZRO SCHLN,(Q1) ;MAKE THIS BE THE ONLY ENTRY MOVE T2,Q1 ;GET SCHED ENTRY TO BE ADDED CALL ADDDEV ;GO ADD THIS DEVELOPER TO THE LIST ERRMES () RET ;DONE ;ROUTINE TO MARK THE CRITICAL PATH TASKS SETCP: SAVEQ STKVAR <> CALL CLRCP ;CLEAR THE CRITICAL PATH BITS CALL SETSLK ;SET THE SLACK VALUES MOVE Q1,TSKPTR ;SET UP AOBJN POINTER SETZ Q2, ;SCAN FOR THE LATEST FINISH DATE SETCP1: HRRZ T1,TSKLST(Q1) ;GET THE TASK ADDRESS LOAD T2,TKEFD,(T1) ;GET THE EXPECTED FINISH DATE HLLZS T2 ;ONLY NEED THE DAY CAMLE T2,Q2 ;FOUND A NEW HIGH? MOVE Q2,T2 ;YES, REMEMBER IT AOBJN Q1,SETCP1 ;LOOP BACK OVER ALL TASKS MOVE Q1,TSKPTR ;NOW GO MARK THE CRITICAL PATH SETCP2: HRRZ T1,TSKLST(Q1) ;GET TASK ADDRESS LOAD T2,TKEFD,(T1) ;GET THE FINISH DATE HLLZS T2 CAMGE T2,Q2 ;IS THIS ONE OF THE LAST FINISHING TASKS JRST SETCP5 ;NO MOVEI T1,SETCPT ;YES, ZERO THE ANSWER BLOCK ADDI T1,1 HRLI T1,SETCPT SETZM SETCPT MOVEI T2,SETCPT ADD T2,TSKCNT ;END OF BLOCK TO BE ZEROED BLT T1,-1(T2) HRRZ T1,TSKLST(Q1) ;GET TASK ADDRESS MOVEI T2,SETCPT ;GET ADR OF ANSWER BLOCK CALL FNDCP ;GO FIND CRITICAL PATH TASKS MOVE T1,TSKPTR ;NOW SET THE BIT FOR EACH TASK ON C.P. SETCP3: HRRZ T2,TSKLST(T1) ;GET TASK ADR MOVEI T3,SETCPT ;GET ADR OF ANSWER BLOCK ADDI T3,(T1) ;GET ADR OF TASK WITHIN THE BLOCK SKIPN (T3) ;IS THIS TASK ON THE CRITICAL PATH? JRST SETCP4 ;NO SETONE TKCP,(T2) ;YES, MARK IT SETCP4: AOBJN T1,SETCP3 ;LOOP BACK FOR ALL TASKS SETCP5: AOBJN Q1,SETCP2 ;LOOP BACK FOR ALL TASKS MOVE Q1,TSKPTR ;GET POINTER TO TASKS SETCP6: HRRZ T1,TSKLST(Q1) ;GET TASK ADR LOAD Q3,TKPTC,(T1) ;GET THE PATH CHAR JUMPE Q3,SETCP9 ;IF NONE, THEN SKIP THIS TASK MOVEI T1,SETCPT ;YES, ZERO THE ANSWER BLOCK ADDI T1,1 HRLI T1,SETCPT SETZM SETCPT MOVEI T2,SETCPT ADD T2,TSKCNT ;END OF BLOCK TO BE ZEROED BLT T1,-1(T2) HRRZ T1,TSKLST(Q1) ;GET TASK ADDRESS MOVEI T2,SETCPT ;GET ADR OF ANSWER BLOCK CALL FNDCP ;GO FIND CRITICAL PATH TASKS MOVE Q2,TSKPTR ;NOW LOOP THRU TO SET UP PATHS SETCP7: HRRZ T1,TSKLST(Q2) ;GET THE TASK ADR MOVE T2,Q3 ;GET THE PATH CHAR TO USE MOVEI T3,SETCPT ;GET ADR OF TABLE ADDI T3,(Q2) ;INDEX INTO THE TABLE SKIPN (T3) ;IS THIS TASK ON THE CRITICAL PATH? JRST SETCP8 ;NO CALL MRKPTH ;YES, GO MARK IT WARN (,) SETCP8: AOBJN Q2,SETCP7 ;LOOP BACK FOR ALL TASKS IN LIST SETCP9: AOBJN Q1,SETCP6 ;LOOP BACK FOR MORE PATHS TO SET UP RET ;DONE ;ROUTINE TO MARK A TASK AS BEING ON A CRITICAL PATH ;ACCEPTS IN T1/ TASK ADR ; T2/ PATH CHAR ;RETURNS +1: FAILED ; +2: OK MRKPTH: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS LOAD T1,TKPL,(Q1) ;GET POINTER TO PATH LIST JUMPN T1,MRKPT1 ;ANY THERE? MOVEI T1,.PTHLN ;NO, GET A BLOCK OF FREE SPACE MOVEI T2,.TYPTH MOVEI T3,.VNPTH CALL ASGFRE ;GET A BLOCK FOR THE PATH LIST RET ;FAILED STOR T1,TKPL,(Q1) ;SAVE THE POINTER TO THE BLOCK MRKPT1: LOAD T1,TKPL,(Q1) ;GET THE PATH LIST HRLI T1,(POINT 7,0) ;SET UP A POINTER TO IT MOVEI T4,.PTHLN*5-2 ;GET MAX COUNT OF CHARS IN LIST MRKPT2: ILDB T2,T1 ;GET THE NEXT PATH LIST ELEMENT JUMPE T2,MRKPT3 ;REACHED END OF LIST? CAMN T2,Q2 ;IS THIS THE CHAR? RETSKP ;IF YES, DONT ADD IT TWICE SOJG T4,MRKPT2 ;LOOP BACK TILL END OF LIST RET ;RAN OUT OF ROOM MRKPT3: DPB Q2,T1 ;STORE THE PATH CHAR IDPB T2,T1 ;STORE A NULL AT THE END RETSKP ;DONE ;ROUTINE TO CLEAR THE "CRITICAL PATH" BIT FOR EACH TASK CLRCP: MOVE T1,TSKPTR ;GET AOBJN POINTER TO TSKLST CLRCP1: MOVE T2,TSKLST(T1) ;GET TASK ADR SETZRO TKCP,(T2) ;ZERO THE BIT LOAD T3,TKPL,(T2) ;GET THE PATH LIST POINTER SKIPE T3 ;ANY THERE? SETZM (T3) ;YES, CLEAR THE LIST AOBJN T1,CLRCP1 ;LOOP BACK FOR ALL TASKS RET ;DONE ;ROUTINE TO FIND THE CRITICAL PATH TASKS FOR A GIVEN TASKS (RECURSIVE) ;ACCEPTS IN T1/ TASK ADR ; T2/ ANSWER BLOCK (MAXTSK IN LENGTH) ; CALL FNDCP ;RETURNS +1: 0 = NOT C.P., -1 = ON C.P. FNDCP: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS LOAD T1,TKTKI,(T1) ;GET TSKLST INDEX MOVE T2,Q2 ;GET ANSWER BLOCK MOVE T3,T2 ;GET ADR OF THIS TASK IN ANSWER BLOCK ADD T3,T1 ;ADD IN THE INDEX SETOM (T3) ;THIS TASK IS ON THE CRITICAL PATH SETZ Q2, ;INIT THE DATE LOAD Q3,TKDLP,(Q1) ;GET POINTER TO BLOCKING TASKS JUMPE Q3,R ;IF NONE, THEN DONE FNDCP1: LOAD T1,DPBTK,(Q3) ;GET ADR OF BLOCKING TASK ;T1/ ADR OF BLOCKING TASK, Q1/ ADR OF BLOCKED TASK CALL [ SAVET ;SAVE T1 TO T4 LOAD T1,TKEFD,(T1) ;GET BLOCKING FINISH DATE LOAD T2,TKESD,(Q1) ;GET BLOCKED START DATE CAML T1,T2 ;POSITIVE SLACK RET ;NO--ON CRITICAL PATH CALL GETNWD ;GET NUMBER OF DAYS BETWEEN TASKS SOJLE T1,R ;ASSUME CRITICAL PATH IF 1 OR FEWER RETSKP] ;YES--NOT OR CRITICAL PATH CALL FNDCP ;GO TRACE ITS CRITICAL PATH LOAD Q3,DPDLP,(Q3) ;STEP TO THE NEXT TASK IN THE LIST JUMPN Q3,FNDCP1 ;LOOP BACK FOR REST OF LIST RET ;DONE ;ROUTINE TO SET THE SLACK FOR ALL TASKS SETSLK: SAVEQ MOVE Q1,TSKPTR ;SET UP TO LOOP THROUGH ALL TASKS JUMPE Q1,R ;IF NONE, THEN DONE SETSL1: HRRZ T1,TSKLST(Q1) ;GET TASK ADR CALL TSKSLK ;GO SET ITS SLACK AOBJN Q1,SETSL1 ;LOOP FOR ALL TASKS RET ;DONE ;ROUTINE TO SET THE SLACK OF A TASK ;ACCEPTS IN T1/ TASK ADR ;RETURNS +1: ALWAYS TSKSLK: SAVEQ MOVE Q1,T1 ;SAVE THE TASK ADR MOVE Q3,[377777,,777777] ;INIT ANSWER LOAD Q2,TKBLP,(Q1) ;GET THE BLOCKED LIST POINTER JUMPE Q2,TSKSL2 ;IF NONE, THEN DONE TSKSL1: LOAD T1,TKEFD,(Q1) ;GET THE FINISH DATE LOAD T3,DPTKP,(Q2) ;GET ADR OF DEPENDENT TASK LOAD T2,TKESD,(T3) ;GET ITS START DATE CAMLE T1,T2 ;NEGATIVE SLACK? JRST [ EXCH T1,T2 ;YES CALL GETNWD ;GET NUMBER OF DAYS BETWEEN THEM MOVNS T1 ;NEGATE IT JRST TSKSL3] CALL GETNWD ;GET THE NUMBER OF DAYS BETWEEN THEM TSKSL3: CAMGE T1,Q3 ;NEW LOW? MOVE Q3,T1 ;YES, REMEMBER IT LOAD Q2,DPBLP,(Q2) ;STEP TO NEXT DEPENDENT TASK JUMPN Q2,TSKSL1 ;LOOP BACK FOR ALL DEPENDENT TASKS TSKSL2: CAMN Q3,[377777,,777777] ;ANY FOUND? MOVE Q3,[NOSLAK] ;NO, SIGNIFY NONE STOR Q3,TKSLK,(Q1) ;SET THE SLACK RET ;DONE ;ROUTINE TO BUILD THE SCHEDLUED TASK LIST BLDSTL: SAVEPQ SETZM SKTLST ;INIT POINTER TO LIST MOVN P1,TSKCNT ;SET UP A POINTER TO THE TASKS JUMPE P1,R ;IF NONE, THEN DONE HRLZS P1 BLDST0: MOVE P3,TSKFDL(P1) ;GET FINISH DATE OF TASK MOVE P4,TSKSDL(P1) ;GET THE START DATE TLNN P4,-1 ;ANY THERE? MOVE P4,P3 ;NO, USE FINISH DATE WHEN THERE IS NO START DATE MOVE Q1,P3 ;INITIALIZATION BLDST1: CAMGE P3,P4 ;DONE? JRST BLDST4 ;YES, GO ON TO NEXT TASKS MOVE Q2,Q1 ;REMEMBER THE FINISH DATE MOVE T1,TSKLST(P1) ;GET TASK ADDRESS MOVE T2,P3 ;GET DATE CALL GETTRT ;GET RATE FOR THIS TASK ON THIS DATE MOVEM T1,Q3 ;REMEMBER STARTING RATE BLDST2: MOVE Q1,P3 ;GET STARTING DATE OF THIS SECTION SUB P3,[1,,0] ;GO BACK TO PREVIOUS DAY CAMGE P3,P4 ;GONE PAST START DATE OF TASK? JRST BLDST3 ;YES, THEN DONE MOVE T1,TSKLST(P1) ;GET TASK ADDRESS MOVE T2,P3 ;GET DATE CALL GETTRT ;SEE IF THE RATE HAS CHANGED CAMN T1,Q3 ;DID IT CHANGE? JRST BLDST2 ;NO, KEEP MOVING BACK THRU DATES BLDST3: MOVEI T1,.SCHLN ;GET A BLOCK TO STORE THIS IN CALL ASGSCH ERRMES () MOVE T2,TSKLST(P1) ;GET TASK ADDRESS FOR BLOCK STOR T2,SCHTK,(T1) ;STORE THE TASK ADDRESS STOR Q1,SCHSD,(T1) ;STORE THE START DATE STOR Q2,SCHFD,(T1) ;STORE THE FINISH DATE STOR Q3,SCHRT,(T1) ;STORE THE RATE MOVE T2,SKTLST ;NOW ADD THIS BLOCK TO THE LIST STOR T2,SCHLN,(T1) ;MAKE THIS TASK POINT TO LAST NEXT ONE MOVEM T1,SKTLST ;MAKE THE LIST POINT TO THIS ONE JRST BLDST1 ;LOOP BACK TILL THIS TASK IS SCHEDULED BLDST4: AOBJN P1,BLDST0 ;LOOP BACK FOR ALL TASKS RET ;ALL DONE ;ROUTINE TO COUNT UP THE COMBINED RATE FOR A TASK ON A GIVEN DATE ;ACCEPTS IN T1/ TASK BLOCK ADDRESS ; T2/ DATE ; CALL GETTRT ;RETURNS +1: ALWAYS, T1/ RATE GETTRT: SAVEQ DMOVE Q1,T1 ;SAVE THE ARGS SETZ T1, ;INIT THE ANSWER HLRZ Q3,DEVTAB ;SET UP POINTER TO DEVELOPER LIST JUMPE Q3,R ;IF NONE, THEN DONE MOVNS Q3 HRLZS Q3 GETTR1: HRRZ T2,DEVTAB+1(Q3) ;GET POINTER TO LIST JUMPE T2,GETTR4 ;IF NONE, THEN DONE GETTR2: LOAD T3,SCHTK,(T2) ;GET TASK ADR CAME T3,Q1 ;FOUND THE ONE WE WANT? JRST GETTR3 ;NO LOAD T3,SCHSD,(T2) ;GET ITS START DATE LOAD T4,SCHFD,(T2) ;AND ITS FINISH DATE CAMG T3,Q2 ;IS START BEFORE THE DESIRED DATE? CAMG T4,Q2 ;AND FINISH AFTER THE DESIRED DATE? JRST GETTR3 ;NO, SKIP THIS BLOCK LOAD T3,SCHRT,(T2) ;YES, GET THE RATE FADR T1,T3 ;ADD IT TO THE ANSWER GETTR3: LOAD T2,SCHLN,(T2) ;STEP TO NEXT TASK BLOCK JUMPN T2,GETTR2 ;LOOP BACK IF MORE TO BE DONE GETTR4: AOBJN Q3,GETTR1 ;LOOP BACK FOR ALL DEVELOPERS RET ;DONE ;ROUTINE TO LOOKUP A DEVELOPER IN THE TABLE ;ACCEPTS IN T1/ POINTER TO THE NAME STRING ; CALL DEVLUK ;RETURNS +1: NOT FOUND ; +2: T1/ ADR OF TABLE ITEM DEVLUK: MOVE T2,T1 ;GET ADR OF NAME INTO T2 MOVEI T1,DEVTAB ;GET ADR OF TABLE TBLUK ERJMP R ;NOT FOUND TXNN T2,TL%EXM ;EXACT MATCH? RET ;NO RETSKP ;YES ;ROUTINE TO ADD A DEVELOPER TO THE TABLE ;ACCEPTS IN T1/ ADR OF THE NAME STRING ; T2/ ADR OF THE DEVELOPER BLOCK ; CALL ADDDEV ;RETURNS +1: FAILED ; +2: SUCCESS ADDDEV: HRL T2,T1 ;BUILD THE ENTRY MOVEI T1,DEVTAB ;GET ADR OF TABLE TBADD ERJMP R ;FAILED RETSKP ;ROUTINE TO ASSIGN SPACE IN THE SCHED POOL ;RETURNS +1: FAILED ; +2: T1/ ADR OF BLOCK ASGSCH: MOVE T1,SKDFRP ;GET POINTER TO NEXT FREE BLOCK MOVEI T2,.SCHLN ;GET LENGTH ADDB T2,SKDFRP ;UPDATE THE POINTER CAILE T2,SKDFRE+SKDFRL ;BEYOND THE END? RET ;YES, NO MORE ROOM HRLZ T2,T1 ;ZERO THE BLOCK HRRI T2,1(T1) MOVEI T3,.SCHLN-1(T1) ;GET END OF BLOCK SETZM (T1) BLT T2,(T3) RETSKP ;NO ; ROUTINE TO ASSIGN SPACE IN FREE STORAGE REGION ; CALL: T1 ;SIZE OF BLOCK NEEDED ; T2 ;TYPE CODE OF THE BLOCK ; T3 ;VERSION NUMBER OF THE DATA IN THE BLOCK ; CALL ASGFRE ; RETURNS: +1 ERROR, NOT ENOUGH SPACE ; +2 SUCCESS, T1/ LOCATION OF THE BLOCK ; CLOBBERS T1, T2, T3, AND T4 ; FREE STORAGE HEADER FORMAT: ; 0 ;LH POINTS TO FIRST FREE BLOCK ; 1 ;SPACE COUNTER ; 2 ;MOST COMMON BLOCK SIZE ; 3 ;LH HAS MAX TOP OF FREE STORAGE, ; ; RH HAS MINIMUM BOTTOM ; 4 ;TEMPORARY 2 ; 5 ;TEMPORARY 3 ASGFRE: ASUBR ADDI T1,.BLKLN ;ADD ON THE LENGTH OF THE HEADER CALL GETFRE ;GET THE BLOCK RET ;FAILED ADDI T1,.BLKLN ;POINT TO FIRST WORD BEYOND HEADER MOVE T2,ASGFRS ;GET SIZE OF BLOCK ADDI T2,.BLKLN ;PLUS HEADER STOR T2,BLKLEN,(T1) ;STORE LENGTH MOVE T2,ASGFRT ;GET TYPE OF BLOCK STOR T2,BLKTYP,(T1) MOVE T2,ASGFRV ;GET VERSION NUMBER STOR T2,BLKVER,(T1) RETSKP GETFRE: MOVE T2,T1 ;GET SIZE INTO T2 MOVEI T1,FRSHDR ;GET ADDRESS OF FREE SPACE HEADER PIOFF ;LOCK UP THE LOCKS LOCK FRELOK CALL GETFR0 ;GO GET SPACE RETBAD (,) ;NO MORE SPACE UNLOCK FRELOK ;UNLOCK THE LOCKS PION RETSKP GETFR0: CAMLE T2,1(T1) ;ANY POSSIBILITY OF SUCCESS? RET ;NO, RETURN IMMEDIATELY PUSH P,T2 ;SAVE DESIRED BLOCK SIZE PUSH P,[0] ;BIGGEST BLOCK SEEN SO FAR HRLOI T2,377777 MOVEM T2,4(T1) ;INITIAL BEST BLOCK SIZE SETZM 5(T1) ;INITIAL LOCATION OF BEST BLOCK MOVE T2,T1 ;START WITH THE HEADER WORD GETFR1: HLRZ T3,0(T2) ;GET POINTER TO NEXT FREE BLOCK JUMPE T3,GETFR2 ;NO MORE FREE BLOCKS TO EXAMINE HRRZ T4,0(T3) ;GET SIZE OF THE BLOCK CAMLE T4,0(P) MOVEM T4,0(P) CAMN T4,-1(P) ;IS IT THE RIGHT SIZE? JRST GETFR3 ;YES, USE IT CAML T4,-1(P) ;TOO SMALL? CAML T4,4(T1) ;OR BIGGER THAN THE BEST? JRST GETFR4 ;YES, IGNORE IT MOVEM T4,4(T1) ;THIS ONE IS BETTER MOVEM T2,5(T1) GETFR4: MOVE T2,T3 ;STEP TO THE NEXT BLOCK JRST GETFR1 ;AND REPEAT GETFR2: SKIPN T2,5(T1) ;DID WE FIND ANYTHING? JRST [ POP P,T2 ;NO, FLUSH TEMP POP P,T2 ;MAKE TRANSPARENT TO T2 ON ERROR RETBAD] MOVE T4,-1(P) ;GET DESIRED SIZE HLRZ T3,0(T2) ;GET POINTER TO BLOCK TO BE USED HRRM T4,0(T3) ;CONVERT TO DESIRED SIZE ADD T4,T3 ;POINTER TO REMAINDER OF BLOCK HRLM T4,0(T2) ;POINT PREVIOUS TO REMAINDER HLLZ T2,0(T3) ;GET NEXT HLLM T2,0(T4) ;POINT REMAINDER TO IT MOVE T2,4(T1) SUB T2,-1(P) ;SIZE OF REMAINDER HRRM T2,0(T4) ;TO HEADER OF REMAINDER GETFR5: SUB P,[1,,1] ;GET LOCATION BELOW TOP-OF-STACK MOVN T2,0(P) ADDM T2,1(T1) ;REDUCE COUNT OF SPACE LEFT MOVEI T1,0(T3) ;GET ORIGIN OF BLOCK HRROS (T1) ;SET LH TO ONES CAMN T2,[-1] ;IS THIS A BLOCK OF ONE WORD? JRST GETFR6 ;YES, DON'T ZERO ANYTHING THEN HRRZ T2,(T1) ;GET RH HRRZI T3,2(T1) SETZM -1(T3) ;ZERO FIRST WORD BEFORE SETTING LEFT HALF INDEX HRLI T3,1(T1) ADD T2,T1 HRRZS T2 CAILE T2,(T3) BLT T3,-1(T2) ;ZERO THE BLOCK GETFR6: POP P,T2 ;RESTORE T2 RETSKP ;RETURN GETFR3: HLL T4,0(T3) HLLM T4,0(T2) ;POINT PREDECESSOR TO SUCCESSOR JRST GETFR5 ; ROUTINE TO RELEASE FREE STORAGE BLOCK ; LIFTED FROM MONITOR MODULE FREE, ROUTINE RELFRE ; CALL: T1/ LOCATION OF THE BLOCK TO BE RETURNED ; CALL RELFRE ; RETURNS: +1 SUCCESS, BLOCK RELEASED ; CLOBBERS T2, T3, AND T4 RELFRE: JUMPE T1,R ;IF NONE, JUST RETURN MOVEI T2,-.BLKLN(T1) ;GET ADR OF BLOCK INTO T2 LOAD T1,BLKLEN,(T1) ;GET THE ACTUAL LENGTH OF THE BLOCK MOVEM T1,0(T2) ;STORE IT IN THE FIRST WORD OF THE BLOCK MOVEI T1,FRSHDR ;GET ADR OF FREE SPACE HEADER PIOFF LOCK FRELOK ;LOCK UP CALL RELFRW ;GO DO THE WORK JRST [ HRROI T1,[ASCIZ/ % PROBLEM ENCOUNTERED WHILE RELEASING A BLOCK TO THE FREE POOL /] PSOUT JRST .+1] UNLOCK FRELOK ;UNLOCK THE LOCKS PION RET RELFRW: PUSH P,T1 ;SAVE LOCATION OF FREE STG HDR HRRZ T4,0(T1) HLRZ T4,3(T1) HRRZ T1,3(T1) CAILE T4,0(T2) CAILE T1,0(T2) JRST RLFRX1 ;ERROR - OUT OF RANGE MOVE T1,0(P) RELFR0: PUSH P,T2 ;SAVE LOCATION OF BLOCK TO FREE HRLI T2,0 ;SOME FIX NEEDED HERE TO KEEP OUT OF SEC 0!!!! HLLM T2,0(P) MOVE T2,-1(P) RELFR1: HLRZ T3,0(T2) ;GET LOCATION OF NEXT BLOCK JUMPE T3,RELFR2 ;END OF LIST CAML T3,0(P) JRST RELFR2 ;OR ABOVE BLOCK BEING RETURNED MOVE T2,T3 JRST RELFR1 RLFRX1: POP P,T1 ;ERROR, BLOCK OUT OF RANGE RETBAD ;RETURN RELFR2: CAMN T3,0(P) ;RELEASING A BLOCK ALREADY RELEASED? JSP CX,RLFRX2 ;YES, ERROR CAIN T1,0(T2) ;THIS FIRST BLOCK ON FREE LIST? JRST RELFR6 ;YES HRRZ T4,0(T2) ;COMPUTE END OF PREVIOUS BLOCK ADD T4,T2 CAMLE T4,0(P) ;PREVIOUS BLOCK OVERLAPS ONE BEING RELEASED? JSP CX,RLFRX2 ;YES, ERROR RELFR6: JUMPE T3,RELFR7 ;AT END OF FREE LIST? HRRZ T4,0(P) ;COMPUTE END OF THIS BLOCK ADD T4,@0(P) CAMLE T4,T3 ;OVERLAPS NEXT BLOCK ON FREE LIST? JSP CX,RLFRX2 ;YES, ERROR RELFR7: HRRZ T4,@0(P) ADDM T4,1(T1) ;AUGMENT COUNT OF REMAINING FREE SPACE ADD T4,0(P) ;GET END OF BLOCK BEING RETURNED CAIE T4,0(T3) ;SAME AS FOLLOWING BLOCK LOCATION? JRST RELFR3 ;NO HRRZ T4,0(T3) ;GET LENGTH OF FOLLOWING BLOCK ADDM T4,@0(P) ;AUGMENT LENGTH OF BLOCK BEING RETURNED HLLZ T4,0(T3) ;GET LOC OF SUCCESSOR OF SUCCESSOR HLLM T4,@0(P) RELFR5: MOVE T3,0(P) HRLM T3,0(T2) HRRZ T4,0(T2) ;LENGTH OF PREDECESSOR ADD T4,T2 ;END OF PREDECESSOR CAME T4,T3 ;SAME AS NEW BLOCK JRST RELFR4 ;NO, DONE MOVE T3,0(T3) HLLM T3,0(T2) HRRZS T3 ADDM T3,0(T2) RELFR4: POP P,T2 POP P,T1 RETSKP ;GOOD RETURN RELFR3: HRLM T3,@0(P) ;POINT RETURNED BLOCK TO SUCCESSOR JRST RELFR5 RLFRX2: POP P,T2 ;ERROR, BAD BLOCK BEING RELEASED POP P,T1 RETBAD ;GIVE ERROR RETURN ; ROUTINE TO BUILD FREE SPACE HEADER AT INITIALIZATION ; FOR CALLS TO ASGFRE AND RELFRE ; ; CALL FSHDR ; RETURNS: +1 ALWAYS FSHDR: MOVEI T1,FSADR ;START ADR OF FREE SPACE HRLOM T1,FRSHDR MOVEI T1,FSLEN ;SET UP LENGTH OF FIRST BLOCK MOVEM T1,FSADR ;MAKE THE FIRST BLOCK CONTAIN ALL SPACE MOVEM T1,FRSHDR+1 ;SET UP LENGTH MOVE T1,[FSADR+FSLEN,,FSADR] MOVEM T1,FRSHDR+3 ;SET UP BOUNDS RET ;ROUTINE TO ENQ A JFN ;ACCEPTS IN T1/ JFN ENQJFN: STKVAR <,,> HRRZM T1,.ENQLV+ENQJFB ;SAVE THE JFN MOVE T1,[1,,5] ;SET UP ENQ BLOCK MOVEM T1,.ENQLN+ENQJFB SETZM .ENQID+ENQJFB ;ID = 0 MOVX T1,5B2 MOVEM T1,.ENQUC+ENQJFB ;UNIQUE CODE = 0 SETZM .ENQRS+ENQJFB ;EXCLUSIVE LOCK MOVEI T1,.ENQAA ;ASK FOR LOCK MOVEI T2,ENQJFB ENQ SKIPA ;NOT AVAILABLE RET ;GOT IT LOCKED CAIE T1,ENQX6 ;ALREADY IN USE? JSP ERROR ;NO, ERROR MOVEI T1,.ENQCS ;NOW GET JOB NUMBER OF OWNER MOVEI T2,ENQJFB MOVEI T3,ENQJFS ;GET ADR OF STATUS BLOCK ENQC ;GET STATUS INFO JSP ERROR ;FAILED HRRZ T1,ENQJFS ;GET JOB NUMBER OF OWNER HRROI T2,T4 ;GET USER NUMBER OF JOB MOVEI T3,.JIUNO GETJI JSP ERROR ;FAILED MOVEI T1,.PRIOU TYPE T1,<&THE DATA BASE IS IN USE BY > HRROI T1,ENQJFU ;GET USER NAME MOVE T2,T4 ;GET USER NUMBER DIRST SKIPA T2,[-1,,[ASCIZ/USER/]] HRROI T2,ENQJFU ;GET USER NAME STRING MOVEI T1,.PRIOU CALL TYPSTR ;OUTPUT THE USER NAME STRING TYPE T1,< ON JOB > HRRZ T2,ENQJFS ;NOW OUTPUT THE JOB NUMBER MOVEI T3,^D10 ;IN DECIMAL CALL TYPNUM TYPE T1,<, WAITING...> MOVEI T1,.ENQBL ;NOW DO A BLOCKING ENQ MOVEI T2,ENQJFB ENQ JSP ERROR MOVEI T1,.PRIOU TYPE T1,< OK, DATA BASE IS LOCKED.&> RET ;ROUTINE TO DEQ A JFN ;ACCEPTS IN T1/ JFN DEQJFN: STKVAR <> HRRZM T1,.ENQLV+DEQJFB ;SAVE JFN MOVE T1,[1,,5] MOVEM T1,.ENQLN+DEQJFB ;SET UP HEADER SETZM .ENQID+DEQJFB MOVX T1,5B2 MOVEM T1,.ENQUC+DEQJFB ;UNIQUE CODE = 0 SETZM .ENQRS+DEQJFB MOVEI T1,.DEQDR ;DEQ THE RESOURCE MOVEI T2,DEQJFB DEQ JSP ERROR RET ;ROUTINES TO TURN OFF AND ON THE INTERRUPT SYSTEM ;ALL ACS ARE PRESERVED PIOFF.: PUSH P,T1 ;SAVE ALL ACS MOVEI T1,.FHSLF ;THIS FORK DIR ;DISABLE INTERRUPT SYSTEM POP P,T1 ;RESTORE AC RET ;AND RETURN PION.: PUSH P,T1 ;SAVE ALL ACS MOVEI T1,.FHSLF ;THIS FORK EIR ;ENABLE INTERRUPTS AGAIN POP P,T1 ;RESTORE AC RET ;AND RETURN ;TYPE OUT ROUTINES TYPRTN: PUSH P,T1 PUSH P,T2 PUSH P,T3 PUSH P,T4 HRRZ T1,(CX) ;GET OUTPUT JFN HLRZ T4,CX ;GET ADR OF ASCIZ STRING HRLI T4,(POINT 7,0) ;TURN IT INTO A BYTE POINTER TYPRT1: ILDB T2,T4 ;GET NEXT CHAR IN STRING JUMPE T2,TYPRT3 ;IF NULL, THEN DONE CAIN T2,"&" ;CRLF? JRST TYPRT2 ;YES CALL TYPCHR ;OUTPUT THE CHAR JRST TYPRT1 ;LOOP BACK FOR REST TYPRT2: MOVEI T2,15 ;CR CALL TYPCHR MOVEI T2,12 ;LF CALL TYPCHR JRST TYPRT1 ;LOOP BACK FOR REST TYPRT3: POP P,T4 POP P,T3 POP P,T2 POP P,T1 RET ;ROUTINE TO TYPE A CHARACTER TYPCHR: CAIN T2,15 ;CR? SETZM COLUMN ;YES, ZERO COLUMN COUNTER CAIL T2," " ;PRINTING CHARACTER? AOS COLUMN ;YES, COUNT COL UP BY ONE CAIN T2,11 ;TAB? JRST [ EXCH T2,COLUMN ;YES LSH T2,-3 ;UPDATE COLUMN TO NEXT TAB STOP LSH T2,3 ADDI T2,8 EXCH T2,COLUMN JRST .+1] BOUT ;OUTPUT THE CHAR RET ;ROUTINE TO TYPE OUT SPACES TO THE SPECIFIED COLUMN ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ COLUMN POSITION TYPSPA: SAVET MOVE T3,T2 ;GET COLUMN POS INTO T3 SUB T3,COLUMN ;GET NUMBER OF SPACES TO TYPE MOVEI T2," " CALL TYPCHR ;TYPE OUT AT LEAST ONE SOJG T3,.-1 ;LOOP BACK TILL AT DESIRED COLUMN RET ;ROUTINE TO TYPE OUT A FLOATING POINT NUMBER TYPFLT: SAVET STKVAR <,TYPFLJ> MOVEM T1,TYPFLJ ;SAVE THE JFN HRROI T1,TYPFLS ;GET ADR OF STRING SETZ T3, ;NORMAL FORMAT FLOUT JRST ERROR MOVE T1,TYPFLJ ;GET JFN AGAIN HRROI T2,TYPFLS ;NOW TYPE OUT THE ANSWER CALLRET TYPSTR ;ROUTINE TO TYPE OUT AN INTEGER ;ACCEPTS IN T1/ OUTPUT JFN ; T2/ NUMBER ; T3/ RADIX TYPNUM: SAVET STKVAR <,TYPNUJ> MOVEM T1,TYPNUJ ;SAVE JFN HRROI T1,TYPNUS ;GET ADR OF STRING NOUT JRST ERROR MOVE T1,TYPNUJ ;GET JFN AGAIN HRROI T2,TYPNUS ;NOW OUTPUT THE NUMBER CALLRET TYPSTR ;ROUTINE TO TYPE OUT A STRING TYPSTR: SAVET MOVE T3,T2 ;GET BYTE POINTER TLC T3,-1 TLNE T2,-1 ;LH = 0? TLCN T3,-1 ;OR LH = -1? HRLI T3,(POINT 7,0) ;YES, SET UP BYTE POINTER TYPST1: ILDB T2,T3 ;GET NEXT CHAR TO BE OUTPUT JUMPE T2,R ;IF NULL, DONE CALL TYPCHR ;TYPE IT OUT JRST TYPST1 ;LLOP BACK FOR REST OF CHARS ;ROUTINE TO TYPE THE DATE OUTDAT: SAVET MOVX T3,OT%NTM ;OUTPUT JUST THE DATE WITHOUT THE DAY JRST TYPDT1 TYPDAT: SAVET MOVX T3,OT%NTM!OT%DAY ;OUTPUT THE DAY AND DATE TYPDT1: STKVAR <,TYPDTJ,TYPDTF> MOVEM T3,TYPDTF ;SAVE THE FLAGS FOR THE ODTIM MOVEM T1,TYPDTJ ;SAVE THE JFN SKIPN T2 ;ANY DATE SPECIFIED? JRST [ HRROI T2,[ASCIZ/NOT SPECIFIED/] CALLRET TYPSTR] MOVX T4,IC%UTZ ;CONVERT DATE TO THIS TIME ZONE ODCNV SETZ T4, ;USE DEFAULT TIMEZONE IDCNV JSP ERROR HRROI T1,TYPDTS ;GET ADR OF STRING MOVE T3,TYPDTF ;GET THE FLAGS TO BE USED ODTIM MOVE T1,TYPDTJ ;GET BACK THE JFN HRROI T2,TYPDTS ;NOW OUTPUT THE DATE CALLRET TYPSTR ;TYPE OUT THE NAME OF A TASK ; T1/ TASK BLOCK ADDRESS ; CALL TYPTNM ; RETURN HERE TYPTNM: MOVE T4,T1 ;COPY ADDRESS LOAD T1,TKPRJ,(T4) ;PROJECT BLOCK LOAD T1,PJNAM,(T1) ;NAME STRING HRLI T1,(POINT 7,0) ;MAKE BYTE POINTER PSOUT MOVEI T1,"/" PBOUT LOAD T1,TKNAM,(T4) ;TASK NAME HRLI T1,(POINT 7,0) ;MAKE BYTE POINTER PSOUT RET ;ROUTINE TO GET THE CONVERTED DATE ;ACCEPTS IN T1/ INTERNAL DATE AND TIME ;RETURNS +1: ALWAYS, T1/ DAY,,0 GETDAY: MOVE T2,T1 ;GET DATE INTO T2 MOVEI T4,0 ODCNV ;GET DAYS, MONTHS, YEARS LDB T2,[POINT 6,T4,17] ;GET TIME ZONE TRNE T2,40 ;POSITIVE? IOR T2,[777777,,777700] ;NO, EXTEND THE SIGN IMULI T2,<777777/^D24> ;GET DIFERENCE SINCE GREENWICH TIME ADD T1,T2 ;OFFSET TO GRENWICH TIME HLLZS T1 ;GET DAY,,0 RET ;ROUTINE TO GET THE # OF WORKING DAYS BETWEEN TWO DATES ;ACCEPTS IN T1/ START DATE ; T2/ FINISH DATE ; CALL GETNWD ;RETURNS +1: ALWAYS, T1/ NUMBER OF WORKING DAYS GETNWD: SAVEQ DMOVE Q1,T1 ;SAVE ARGS CALL CNTHOL ;COUNT THE DAYS THAT ARE HOLIDAYS SETZ T1, ;NONE MOVE Q3,T1 ;REMEMBER THE NUMBER DMOVE T1,Q1 ;GET BACK ARGS HLRZS T1 ;GET DAYS HLRZS T2 CAMN T1,T2 ;THE SAME? JRST [ MOVEI T1,0 ;YES, THE ANSWER IS 0 RET] ADDI T1,2 ;ADD IN OFFSET SO MONDAY IS 0 MODULO 7 ADDI T2,2 ASUBR MOVE T3,T2 ;SET UP FOR DIVIDE IDIVI T1,7 ;GET THE NUMBER OF WEEKS CAIN T2,5 ;SATURDAY? AOSA GETNWS ;YES, UPDATE START TO MONDAY CAIN T2,6 ;SUNDAY? AOS GETNWS ;YES, UPDATE START TO MONDAY IDIVI T3,7 ;GET WEEKS FOR END DATE CAIN T4,6 ;SUNDAY? SOS GETNWF ;YES, PUSH FINISH BACK TO FRIDAY MOVE T1,GETNWS ;GET START DATE IDIVI T1,7 ;GET WEEKS AGAIN MOVE T3,GETNWF ;GET FINISH DATE IDIVI T3,7 ;GET WEEKS AGAIN SUB T3,T1 ;GET WEEKS ON TASK IMULI T3,5 ;GET DAYS ON TASK SUB T3,T2 ;SUBTRACT DAYS USED IN START WEEK ADD T3,T4 ;ADD IN DAYS IN FINISH WEEK MOVE T1,T3 ;GET ANSWER INTO T1 SUB T1,Q3 ;SUBTRACT OUT THE HOLIDAYS RET REPEAT 0,< SAVEQ HLRZS T1 ;GET DAYS HLRZS T2 SUB T2,T1 ;GET NUMBER OF DAYS DMOVE Q1,T1 ;SAVE THE START DAY SETZ Q3, ;INIT COUNTER JUMPE Q2,GETNW2 ;IF NO DAYS, GO RETURN 0 GETNW1: HRLZ T1,Q1 ;GET DATE CALL CHKWD ;SEE IF IT IS A WORKING DAY SKIPA ;NO AOS Q3 ;COUNT UP ANSWER AOS Q1 ;STEP DAY SOJG Q2,GETNW1 ;LOOP BACK FOR EACH DAY GETNW2: MOVE T1,Q3 ;RETURN THE ANSWER RET > ;ROUTINE TO CHECK IF A DAY IS A WORKING DAY ;ACCEPTS IN T1/ DATE ;RETURNS +1: NOT A WORKING DAY ; +2: A WORKING DAY CHKWD: HLRZ T2,T1 ;GET DAY ADDI T2,2 ;SEE IF IT IS A WEEKEND IDIVI T2,7 CAIL T3,5 ;MON - FRI? RET ;NO CALL CHKHOL ;SEE IF IT IS A HOLIDAY RETSKP ;NO, THEN IT IS A WORKING DAY RET ;YES, NOT A WORKING DAY ;ROUTINE TO CHECK IF A DAY IS A HOLIDAY ;ACCEPTS IN T1/ DATE ;RETURNS +1: NOT A HOLIDAY ; +2: A HOLIDAY CHKHOL: HLLZS T1 MOVE T2,HOLTAB ;GET ADR OF HOLIDAY TABLE JUMPE T2,R ;IF NONE, THEN DONE LOAD T3,HOLUSE,(T2) ;GET USE COUNT JUMPE T3,R MOVNS T3 HRLZS T3 HRRI T3,1(T2) ;GET AOBJN POINTER TO TABLE CHKHO1: CAMN T1,(T3) ;FOUND A MATCH? RETSKP ;YES, THEN DONE AOBJN T3,CHKHO1 ;NO, LOOP BACK FOR OTHER ENTRIES RET ;NOT A HOLIDAY ;ROUTINE TO COUNT THE HOLIDAYS BETWEEN TWO DATES ;ACCEPTS IN T1/ START DATE ; T2/ FINISH DATE ;RETURNS +1: NONE ; +2: T1/ COUNT CNTHOL: SAVEQ HLLZS T1 HLLZS T2 CAMG T2,T1 ;FINISH DATE AFTER START DATE? RET ;NO DMOVE Q1,T1 ;SAVE THE ARGS SETZ Q3, ;INIT THE COUNT MOVE T4,HOLTAB ;GET POINTER TO THE TABLE JUMPE T4,R ;IF NONE, THEN DONE LOAD T1,HOLUSE,(T4) ;GET USE COUNT JUMPE T1,R MOVNS T1 HRLZS T1 HRRI T1,1(T4) ;GET POINTER TO TABLE CNTHO1: MOVE T2,(T1) ;GET NEXT DATE CAML T2,Q1 ;IS THIS DATE WITHIN THE RANGE CAML T2,Q2 JRST CNTHO2 ;NO ADDI T2,2 ;SEE IF DAY IS DURING THE WEEK IDIVI T2,7 CAIGE T3,5 ;SAT OR SUN? AOS Q3 ;NO, COUNT UP COUNT CNTHO2: AOBJN T4,CNTHO1 ;LOOP BACK FOR ALL DATES IN THE TABLE MOVE T1,Q3 ;GET ANSWER RETSKP ;ROUTINE TO GET FINISH DATE GIVEN START DATE AND # OF WORK DAYS ;ACCEPTS IN T1/ START DATE ; T2/ # OF WORK DAYS ; CALL GETNFD ;RETURNS +1: ALWAYS, T1/ NEW FINISH DATE GETNFD: SAVEQ JUMPLE T2,R ;IF NO WORKING DAYS, THEN DONE DMOVE Q1,T1 ;SAVE ARGS GETNF1: MOVE T1,Q1 ;GET DATE CALL CHKWD ;SEE IF IT IS A WORKING DAY SKIPA ;IT ISNT SOS Q2 ;COUNT DOWN # OF WORK DAYS LEFT ADD Q1,[1,,0] ;STEP TO NEXT DAY JUMPG Q2,GETNF1 ;IF MORE WORK DAYS LEFT, LOOP BACK MOVE T1,Q1 ;GET FINISH DAY RET JUMPLE T2,R ;IF NO DAYS, RETURN SAME DATE HLRZ T3,T1 ;GET DAYS ADDI T3,2 ;TRANSLATE SO MONDAY = 0 MODULO 7 IDIVI T3,7 ;GET REMAINDER OF DAYS IN WEEK CAIN T4,5 ;SATURDAY? ADD T1,[2,,0] ;YES, START ON MONDAY CAIN T4,6 ;SUNDAY? ADD T1,[1,,0] ;YES HLRZ T3,T1 ;GET DAY OF WEEK AFTER FIRST UPDATE ADDI T3,2 IDIVI T3,7 IDIVI T2,5 ;GET WEEKS OF WORK DONE IMULI T2,7 ;GET REAL WEEKS OF WORK DONE ADD T2,T3 ;PLUS DAYS OF WEEK ADD T4,T3 ;SEE IF THIS WRAPS AROUND ANOTHER WEEK CAIL T4,5 ;NEED TO SKIP A WEEKEND? ADDI T2,2 ;YES HRLZS T2 ;GET DAYS IN LH ADD T1,T2 ;ADD TO START DATE HLRZ T2,T1 ;SEE IF THIS ENDED ON A WEEKEND ADDI T2,2 IDIVI T2,7 ;GET DAY OF WEEK CAIN T3,5 ;SATURDAY? ADD T1,[2,,0] ;YES, MAKE IT BE THE NEXT MONDAY CAIN T3,6 ;SUNDAY? ADD T1,[1,,0] ;YES RET ;DONE ;ROUTINE TO TYPE OUT AN ERROR MESSAGE ERROR: HRROI T1,[ASCIZ/ ? FATAL ERROR: /] PSOUT MOVEI T1,.PRIOU ;GET OUTPUT JFN HRLOI T2,.FHSLF SETZ T3, ERSTR ;OUTPUT THE ERROR MESSAGE JFCL JFCL HALTF JRST PANTT ;SAVE ROUTINES SAVT: PUSH P,T1 PUSH P,T2 PUSH P,T3 PUSH P,T4 CALL 0(CX) SKIPA AOS -4(P) POP P,T4 POP P,T3 POP P,T2 POP P,T1 RET SAVQ: PUSH P,Q1 PUSH P,Q2 PUSH P,Q3 CALL (CX) SKIPA AOS -3(P) POP P,Q3 POP P,Q2 POP P,Q1 RET SAVPQ: PUSH P,Q1 PUSH P,Q2 PUSH P,Q3 PUSH P,P1 PUSH P,P2 PUSH P,P3 PUSH P,P4 PUSH P,P5 PUSH P,P6 CALL 0(CX) SKIPA AOS -11(P) POP P,P6 POP P,P5 POP P,P4 POP P,P3 POP P,P2 POP P,P1 POP P,Q3 POP P,Q2 POP P,Q1 RET SAVP: PUSH P,P1 PUSH P,P2 PUSH P,P3 PUSH P,P4 PUSH P,P5 PUSH P,P6 CALL 0(CX) SKIPA AOS -6(P) POP P,P6 POP P,P5 POP P,P4 POP P,P3 POP P,P2 POP P,P1 RET ;COMMAND TREES LEV0CT: $INIT (LEV0C1) ;LEVEL 0 COMMAND FIELD LEV0C1: $KEYDSP (LEV0TB) LEV0TB: $STAB DSPTAB (LEV0CA,ADDCMD,) DSPTAB (LEV0CD,DELETE,) DSPTAB (CRLF,EXIT,) DSPTAB (LEV0L,LSTCMD,) DSPTAB (LEV0CO,OUTPUT,) DSPTAB (LEV0CP,PLOT,) DSPTAB (LEV0RM,REMDAT,) DSPTAB (CRLF,SKDCMD,) DSPTAB (LV0ST1,SET,) DSPTAB (LEV0CU,UPDATE,) $ETAB LEV0RM: $NOISE (CRLF,) LV0ST1: $KEYDSP (LV0ST2) LV0ST2: $STAB DSPTAB (LV0SH1,SETHOL,) DSPTAB (LV0SP1,SETPPA,) DSPTAB (CRLF,SETSAF,) DSPTAB (LV0SD1,SETDAT,) DSPTAB (CRLF,SETSLB,) $ETAB LV0SH1: $NOISE (LV0SH2,) LV0SH2: $DATE (CRLF) LV0SD1: $NOISE (LV0SD2,) LV0SD2: $DATE (CRLF) LV0SP1: $NOISE (LV0SP2,) LV0SP2: $KEYDSP (LV0SP3) LV0SP3: $STAB DSPTAB (LV0SP4,0,) DSPTAB (LV0SP4,1,) $ETAB LV0SP4: $NOISE (CRLF,) LEV0CA: $KEYDSP (LEV1A) LEV1A: $STAB DSPTAB (DATDV,L0DEV,) DSPTAB (LEV1AP,ADDP,) DSPTAB (LEV1AT,ADDT,) $ETAB LEV1AP: $NOISE (LEV2P1,) LEV2P1: $FIELD (CRLF,) LEV1AT: $NOISE (LEV2T1,) LEV2T1: $FIELD (LEV2T2,) LEV2T2: $NOISE (LEV2T3,) LEV2T3: PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ) LEV0CD: $KEYDSP (LEV1D) LEV1D: $STAB DSPTAB (DATDLD,DELODV,) DSPTAB (LEV1DP,DELPRJ,) DSPTAB (CRLF,DELDAT,) DSPTAB (LEV1DT,DELTSK,) $ETAB LEV1DP: $NOISE (LEV2D1,) LEV2D1: PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ) LEV1DT: $NOISE (LEV2D2,) LEV2D2: PDBDEF (.CMKEY,,,,,,LEV2D3,,STOTSK,SETPRJ) LEV2D3: $NOISE (LEV2D4,) LEV2D4: PDBDEF (.CMKEY,,,,,,CRLF,,,SETTSK) LEV0L: $KEYDSP (LEV1L) LEV1L: $STAB DSPTAB (LEV1L1,LISTP,) $ETAB LEV1L1: PDBDEF (.CMKEY,,,,,,LEV1L2,,STOTSK,SETPRJ) LEV1L2: $NOISE (LEV1L3,) LEV1L3: PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK) LEV0CO: $KEYDSP (LEV1OT) LEV1OT: $STAB DSPTAB (LEV1O,CMPDAT,) DSPTAB (LEV1O,DUMP,) DSPTAB (LEV1CP,OUTCP,) DSPTAB (LEV1O,LSTDEV,) DSPTAB (LEVOG,GANTT,) DSPTAB (LEV1O,LPATHC,) DSPTAB (LEV1O,PERT,) DSPTAB (LEV1O,LSTSKD,) DSPTAB (LEV1O,SPERT,) DSPTAB (LV1OT1,LSTTSK,) $ETAB LV1OT1: $NOISE (LV1OT2,) LV1OT2: $KEYDSP (LV1OT3) LV1OT3: $STAB DSPTAB (LEV1O,LSTTKE,) ; DSPTAB (LEV1O,LSTTKL,) DSPTAB (LEV1O,LSTTKP,) $ETAB LEVOG: $NOISE (LEVOG1,) LEVOG1: $KEYDSP (LEVOGT) LEVOGT: $STAB DSPTAB (LEV1O,0,) DSPTAB (LEV1O,2,) DSPTAB (L1ONLY,4,) DSPTAB (LEV1O,1,) $ETAB L1ONLY: PDBDEF (.CMUSR,CM%PO,,,,,LEV1O) LEV0CP: $KEYDSP (LV0CPT) LV0CPT: $STAB DSPTAB (LEVOG,GPLOT,) DSPTAB (LEV1O,PPLOT,) DSPTAB (LEV1O,SPPLOT,) $ETAB LEV1O: $NOISE (LEV1O1,) LEV1O1: $OFILE (CRLF) LEV0CU: $NOISE (LEV0U1,) LEV0U1: PDBDEF (.CMKEY,,,,,,LEV1U,,STOTSK,SETPRJ) LEV1U: $NOISE (LEV1U1,) LEV1U1: PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK) SDATA: $INIT (SDATA1) SDATA1: $NUMBER (CRLF,<^D10>,) LEV1CP: $NOISE (LV1CP1,) LV1CP1: PDBDEF (.CMKEY,,,,,,LV1CP2,,STOTSK,SETPRJ) LV1CP2: $NOISE (LV1CP3,) LV1CP3: PDBDEF (.CMKEY,,,,,,LEV1O,,,SETTSK) ;PROJECT DATA COMMAND PDATA: $INIT (PDATA1) PDATA1: $KEYDSP (PDATAT) PDATAT: $STAB DSPTAB (PDATDL,PRJDEL,) DSPTAB (DATDV,PRJDEV,) DSPTAB (PDATAF,PRJFIN,) DSPTAB (CRLF,PRJLST,) DSPTAB (PDATP,PRJPRF,) DSPTAB (CRLF,PRJDSC,) $ETAB PDATDL: $KEYDSP (PDTDL1) PDTDL1: $STAB DSPTAB (PDTDLD,PRJDLD,) $ETAB PDTDLD: PDBDEF (.CMUSR,CM%PO,,,,,CRLF) PDATAF: $NOISE (CRLF,) PDATP: $NOISE (PDATP1,) PDATP1: $FLOAT (CRLF) DDATA: $INIT (DDATA1) DDATA1: $DATE (CRLF) ;DATA COMMAND DATA: $INIT (DATA1) ;INITIALIZATION DATA1: $KEYDSP (DATAT1) ;FIRST LEVEL KEYWORD TABLE DATAT1: DATT1L-1,,DATT1L-1 DSPTAB (CRLF,TKAR,) DSPTAB (DATAT,TKAT,) DSPTAB (DATCD,TKCD,) DSPTAB (DATDL,TKDL,) DSPTAB (DATDP,TKDP,) DSPTAB (DATDV,TKDV,) DSPTAB (DATEL,TKEL,) DSPTAB (DATXD,TKXD,) DSPTAB (DATFC,TKFC,) DSPTAB (CRLF,TKLS,) DSPTAB (DATLA,TKLA,) DSPTAB (CRLF,TKMI,) DSPTAB (DATMD,TKMD,) DSPTAB (DATPA,TKPTH,) DSPTAB (DATPF,TKPF,) DSPTAB (DATSD,TKSD,) DSPTAB (DATTD,TKTD,) DSPTAB (DATTI,TKTI,) DATT1L==.-DATAT1 DATXD: $KEYDSP (DATXD1) DATXD1: $STAB DSPTAB (DATXD2,0,) DSPTAB (DATXD2,1,) $ETAB DATXD2: $NOISE (DATXD3,) DATXD3: $DATE (CRLF) DATCD: $DATE (CRLF) ;COMPLETION-DATE DATMD: $DATE (CRLF) ;MINIMUM STARTING DATE DATPA: $NOISE (DATPA1,) DATPA1: $FIELD (CRLF,) DATDL: $KEYDSP (DATDL1) DATDL1: $STAB DSPTAB (CRLF,TKDCD,) DSPTAB (DATDP,TKDDP,) DSPTAB (DATDLD,TKDLD,) DSPTAB (CRLF,TKDEL,) DSPTAB (DATDX,TKDXD,) DSPTAB (CRLF,TKDMD,) DSPTAB (CRLF,TKDPC,) DSPTAB (CRLF,TKDPF,) DSPTAB (CRLF,TKDSD,) DSPTAB (CRLF,TKDTI,) $ETAB DATDX: $KEYDSP (DATDX1) DATDX1: $STAB DSPTAB (CRLF,0,) DSPTAB (CRLF,1,) $ETAB DATDLD: PDBDEF (.CMUSR,CM%PO,,,,,CRLF) DATDP: $NOISE (DATDP1,) ;DEPENDENCY (ON PROJECT) DATDP1: PDBDEF (.CMKEY,,,,,,DATDP2,,STOTSK,SETPRJ) DATDP2: $NOISE (DATDP3,) DATDP3: PDBDEF (.CMKEY,,,,,,DATDP4,,,SETTSK) DATDP4: $CRLF DATDV: PDBDEF (.CMUSR,CM%PO,,,,,DATDV1) ;DEVELOPER DATDV1: $NOISE (DATDV2,) DATDV2: $FLOAT (DATDV3,) DATDV3: $NOISE (DATDV4,) DATDV4: $FLOAT (DATDV5,) DATDV5: $CRLF DATEL: $NOISE (DATEL1,) ;ESTIMATED-PROJECT-LENGTH DATEL1: $NUMBER (DATEL2,<^D10>,) DATEL2: $CRLF DATFC: $NOISE (CRLF,) DATPF: $NOISE (DATPF1,) DATPF1: $FLOAT (CRLF) DATSD: $DATE (DATSD1) ;STARTING-DATE DATSD1: $CRLF DATTD: $CRLF ;TASK-DESCRIPTION DATTI: $NOISE (DATTI1,) ;TIME-TO-DATE DATTI1: $NUMBER (DATTI2,<^D10>,) DATTI2: $NOISE (DATTI3,) DATTI3: $DATE (DATTI4) DATTI4: $CRLF DATLA: $NOISE (DATLA1,) DATLA1: $FIELD (CRLF,) DATAT: $NOISE (DATATR,) DATATR: $FIELD (DATTR1,) DATTR1: $NOISE (DATTR2,) DATTR2: $FIELD (CRLF,) ;YES/NO COMMAND TABLE YNCT: $INIT (YNCT1) YNCT1: $KEY (CRLF,YNCTTB) YNCTTB: YNCTBL-1,,YNCTBL-1 KEYTAB (,0,) KEYTAB (,1,) YNCTBL==.-YNCTTB CRLF: $CRLF SEL: $INIT (SEL1) SEL1: $KEYDSP (SELT1) SELT1: $STAB DSPTAB (SELF,SELFI,) DSPTAB (SELI,SELIP,) $ETAB SELI: $KEYDSP (SELI1) SELI1: $STAB DSPTAB (SELI2,SELIPR,) $ETAB SELI2: $NOISE (LEV0U1,) SELF: $NOISE (CRLF,) XLIST ;LITERALS VAR LIT LIST ;LITERALS END <3,,ENTVEC>