Trailing-Edge
-
PDP-10 Archives
-
decuslib20-07
-
decus/20-0161/pantt.mac
There are no other files named pantt.mac in the archive.
;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==<VWHO>B2+<VMAJOR>B11+<VMINOR>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>,< INST>
JRST .+1]>
DEFINE TYPE (AC,TEXT) <
CALL [ MOVE CX,[[ASCIZ\TEXT\],,AC]
CALLRET TYPRTN]>
DEFINE CHKTYP (TYP) <
CAIE T1,.CM'TYP
ERRMES (<UNEXPECTED TYPE CODE RETURNED FROM "PARSE">)>
DEFINE RETBAD (A,B) <
IFB <B>,<
IFB <A>,< RET>
IFNB <A>,< JRST [ MOVEI T1,A
RET]>>
IFNB <B>,< 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 <LNG>,<
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==<DBPAG+NDBPAG>*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==<NROW/NGROW>*NGROW ;MODULO DATE LINES
ROWLEN==<NCOL+5>/6
ROWSTL==NROW*ROWLEN
ASG ROWOFS,1 ;OFFSET ROW NUMBER
ASG ROWSTG,ROWSTL
DEFINE BLDGST(A) <
ASG GST'A,<<NCOL+4>/5>>
ZZ==0
REPEAT GW,<BLDGST(\ZZ)
ZZ==ZZ+1>
NLVL==^D200 ;MAX NUMBER OF LEVELS IN A PERT CHART
SPCTBL==<NCOL+^D35>/^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) * <BOXLEN+^D12> 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>,<PRINTX ? RAN OUT OF STORAGE SPACE>
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 <DATA BASE FILE IS TOO LARGE TO BE MAPPED INTO CORE>
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 <ILLEGALLY FORMATTED COMMAND TABLE (LEVEL 1)>
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 <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
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 (<JRST SETHO5>,<NO ROOM FOR A HOLIDAY TABLE>)
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 (<JRST SETHO5>,<NO MORE ROOM IN HOLIDAY TABLE>)
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 <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
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 (<JRST LEVEL0>,<COULD NOT OPEN THE CONTROL FILE>)
CALL OUTCTL ;OUTPUT THE CONTROL FILE
MOVE T1,Q1 ;GET THE JFN
CLOSF ;CLOSE IT
WARN (,<COULD NOT CLOSE THE CONTROL FILE>)
JRST LEVEL0 ;DONE
;PLOT COMMAND
PLOT: HLRZ T1,(P1) ;GET FUNCTION CODE
CAIE T1,.CMKEY ;MUST BE ANOTHER KEYWORD
ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
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,<BOXLEN+^D12> ;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,<BOXLEN+^D12> ;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 (<JRST LEVEL0>,<NO TASKS FOR THAT DEVELOPER>)
HRROI Q2,-DEVTAB-1(T1) ;FAKE AOBJN POINTER
CALL FINDSD ;FIND STARTING DATE
WARN (<JRST LEVEL0>,<ALL TASKS COMPLETE>)
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 <ILLEGALLY FORMATTED COMMAND TABLE>
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 <<FSDTMP,100>>
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 <STOGTN,STOGTL,STOGTC,<STOGTS,100>,<STOGTB,GW>>
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 <GETPTC,GETPTP>
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 <GETGSC,GETGSD,GETGSL,GETGSR,GETGSF,GETGSZ>
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 <<STOFPS,10>>
DMOVE Q1,T1 ;SAVE THE ARGS
HRROI T1,STOFPS ;GET THE NUMBER TRANSLATED TO A STRING
MOVE T3,[FL%ONE+<GW>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,-<GW-1> ;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,<BLDPNT(\ZZ)
ZZ==ZZ+1>
;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 <<CHKGNS,MAXLNW>,<CHKGNN,MAXLNW>,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,<PROJECT NAME>,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,<TASK NAME>,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,<ASCII/ />
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 <<STODAS,10>,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 <STOFLC,STOFLW,STOFLP,STOFLR>
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 <STOSTC,STOSTN,STOSTP>
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 <STOCHV,STOCHC,STOCHN,STOCHF>
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 <<PRIGNS,NCOL>,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 <<PRIGCS,ROWLEN>>
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 <<PRIGDS,10>>
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 <PRISTA,PRISTB,PRISTC,PRISTD,<PRISTS,ROWLEN>>
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 <PRIPLJ,<PRIPLS,<NCOL+5/6>>>
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,<BOXLEN+^D12> ;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 <<CBOXST,2000>>
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 <DLINS,DLINL1,DLINF,DLINL2>
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,<BOXLEN+^D12> ;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 <DLST,DLL1,DLEND,DLL2>
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,<BOXLEN+^D12>
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,<BOXLEN+^D12>
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,<BOXLEN+^D12>
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,<BOXLEN+^D12> ;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,<BOXLEN+^D12> ;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 (<JRST LEVEL0>,<CAN NOT OPEN OUTPUT FILE>)
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>,<CAN NOT CLOSE REPORT FILE>)
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 <STRPTR>
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 <PRITNJ,PRITNT>
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 <PRIDTJ>
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 <STOBXC,STOBXA,STOBXI,<STOBXP,MAXLNW>,<STOBXL,MAXLNW>,<STOBXT,MAXLNW>,<STOBXD,MAXLNW>,<STOBXB,MAXLNW>,<STOBXS,MAXLNW>,<STOBXN,200>,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 <<STOB1S,MAXLNW>>
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,<BOX TEXT>,STOBX2
DMOVE Q2,T2 ;SAVE THE ARGS
STKVAR <<STOB2S,MAXLNW>>
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 <<STOB3S,MAXLNW>>
TRUNC T3,MAXLEN,<INNER BOX LINE>,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 <BLDNSP>
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,<DEVELOPER LIST>,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 <GOAL,LFTPOS> ;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 <FLTUP: LVLTAB MESSED UP>
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 <MAYFLT LIES>
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 (<TABLES ARE MESSED UP>)
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 (<SOS T2,SELCNT>,<Selection table full>)
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 (<JRST LEVEL0>,<COULD NOT ADD THIS NAME TO THE PROJECT LIST>)
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 (<JRST LEVEL0>,<COULD NOT ADD THIS TASK NAME TO THE TASK TABLE>)
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 (<JRST LEVEL0>,<COULD NOT DELETE THIS DEVELOPER FROM THE LIST>)
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 (<JRST LOGLV0>,<COULD NOT COMPLETELY DELETE PROJECT>)
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 (<RET>,<FAILED TO DELETE THIS TASK>)
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 (<JRST L0DEV2>,<L0DEV: COULD NOT ADD THIS DEVELOPER>)
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 (<ILLEGALLY FORMATTED COMMAND TABLE>)
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 (<JRST UPDPRJ>,<FAILED TO GET DESCRIPTION BLOCK>)
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 (<JRST UPDPRJ>,<COULD NOT ADD THIS DEVELOPER TO THE PROJECT>)
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 (<JRST UPDPRJ>,<COULD NOT DELETE THIS DEVELOPER>)
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 <GETDSA>
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 (<JRST UPDTSK>,<COULD NOT ADD THIS USER NAME TO TASK>)
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 (<JRST TKDP1>,<COULD NOT GET SPACE FOR DEPENDENCY BLOCK>)
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 (<JRST UPDTSK>,<FAILED TO GET A DESCRIPTION BLOCK>)
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 (,<PATH CHARACTER MUST BE A SINGLE ALPHA-NUMERIC CHARACTER>)
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 (<JRST UPDTSK>,<ATTRIBUTE NAME CAN NOT BE NULL>)
MOVE Q1,T1 ;SAVE ADDRESS OF NAME
TXNN Q3,AT%LNG ;LONG ATTRIBUTE?
AOJA P1,[CALL ATFLD ;GET ATTRIBUTE OUT OF ANSWER BLOCK
WARN (<JRST UPDTSK>,<ATTRIBUTE VALUE CAN NOT BE NULL>)
MOVE Q2,T1 ;SAVE ANSWER
JRST TKAT1] ;JOIN COMMON CODE
HRROI T1,[ASCIZ "VALUE OF ATTRIBUTE (<ESC> WHEN DONE)"]
CALL GETDSC ;GET THE TEXT
WARN (<JRST UPDTSK>,<CAN NOT CREATE BLOCK FOR ATTRIBUTE VALUE>)
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 (<JRST UPDTSK>,<CAN NOT CREATE ATTRIBUTE BLOCK>)
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 (<JRST UPDTSK>,<COULD NOT DELETE THIS DEVELOPER FROM LIST>)
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 <BLDDVF,BLDDVR,BLDDVH,BLDDVP,<BLDDVS,11>,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 (<RET>,<COULD NOT GET SPACE FOR USER NAME>)
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 (<MOVE T1,Q1 ;RETURN THE NAME BLOCK
CALL RELFRE
RET>,<COULD NOT GET SPACE FOR DEVELOPER BLOCK>)
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 <ADDPRN,ADDPRB,ADDPRT,ADDPRD,ADDPRP,ADDPPT>
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 (<RET>,<PROJECT ALREADY EXISTS>)
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 <ADDTKN,ADDTKB,ADDTKT,ADDTKD,ADDTKP,ADDTKJ>
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 (<RET>,<TASK ALREADY EXISTS>)
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 <OPNFIJ,OPNFIE,<OPNFIS,20>>
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:<DIR>NAME
JFNS
MOVEI T1,GTJBLK ;NOW GET JFN ON TRANSACTION LOG FILE
HRROI T2,OPNFIS
GTJFN
WARN (<MOVEI T1,0>,<COULD NOT OPEN TRANSACTION LOG FILE>)
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 <MAPFLJ,MAPFLC>
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 (<COULD NOT INITIALIZE THE DATA BASE FILE>)
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 <ADDNMS,ADDNMT,ADDNMD,ADDNMF>
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 <CHKTBO,CHKTBN>
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 <CRTTBS>
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 <<YNBLK,20>>
MOVEI T2,YNCT ;GET ADDRESS OF THE YESNO COMMAND TABLE
MOVEI T3,YNBLK
CALL PARSE ;GO GET THE ANSWER
ERRMES <ILLEGALLY FORMATTED YES/NO COMMAND TABLE>
CALL COPCMD ;COPY THIS TO CMDBLK
HLRZ T1,YNBLK ;GET TYPE CODE
CAIE T1,.CMKEY ;IS IT WHAT WE WANT
ERRMES <UNKNOWN TYPE CODE RECEIVED FROM "PARSE">
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 <GETSTA,GETSTB,GETSTC>
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 (<JRST LEVEL0>,<COULD NOT OPEN REPORT FILE>)
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 (,<COULD NOT CLOSE FILE>)
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 (<JRST LEVEL0>,<COULD NOT OPEN REPORT FILE>)
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>,<ERROR CLOSING REPORT FILE>)
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 (<JRST LEVEL0>,<COULD NOT OPEN OUTPUT FILE>)
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>,<FILE DID NOT GET PROPERLY CLOSED>)
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 <CPJFN,CPTSK,CPLVL>
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 <<UPDDBS,40>,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 (<JRST UPDDB2>,<COULD NOT OPEN THE TRANSACTION LOG FILE>)
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 (<JRST .+1>,<COULD NOT UPDATE THE DATA BASE>)
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 <OUTCTJ>
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 <<DELDVS,11>,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 <RELDVP>
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 <<UPDESS,20>,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 (<NO PROJECTS DEFINED>)
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 <? LOOP DETECTED IN THE TASK DEPENDENCY LIST
? BLOCKED TASK: >
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 <ILLEGALLY FORMATTED SCHEDULER COMMAND TABLE>
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 <BLDTBL,BLDTBD,BLDTBC>
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 (<LOOP DETECTED IN THE TASK DEPENDENCY LIST>)
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 <SKDCMC>
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 <<SKDSKA,5>,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 (<JRST BLDT3A>,<RAN OUT OF ROOM IN TASK LIST FOR ALL TASKS>)]
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 <SKDTKI,SKDTKT>
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 <SKDTGI>
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 <GETLTL,GETLTC,GETLTT>
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 <SCHEDA,SCHEDD,SCHEDS,SCHEDL,<SCHEDQ,MAXDEV>,SCHEDF,<SCHEDB,5>,SCHEDT,<SCHDVB,.DVLEN>,<SCHTKB,.TKLEN>,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 <BUG IN CODE AT XSCH2 -- CALL DON LEWINE>
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 <FNDCHN,FNDCHD,FNDCHP,FNDCHF>
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 <SCHDVN,SCHDVS,SCHDVF,SCHDVR,SCHDVT>
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 (<RAN OUT OF SCHEDULER FREE SPACE>)
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 (<COULD NOT ADD A DEVELOPER TO THE SCHEDULE LIST>)
RET ;DONE
;ROUTINE TO MARK THE CRITICAL PATH TASKS
SETCP: SAVEQ
STKVAR <<SETCPT,MAXTSK>>
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 (,<COULD NOT MARK THE CRITICALITY OF A TASK>)
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 (<RAN OUT OF SCHEDULER FREE SPACE>)
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 <ASGFRS,ASGFRT,ASGFRV>
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 (,<UNLOCK FRELOK
PION>) ;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 <<ENQJFB,5>,<ENQJFS,3>,<ENQJFU,10>>
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 <<DEQJFB,5>>
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 <<TYPFLS,10>,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 <<TYPNUS,10>,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 <<TYPDTS,10>,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 <GETNWS,GETNWF>
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,<ADD>)
DSPTAB (LEV0CD,DELETE,<DELETE>)
DSPTAB (CRLF,EXIT,<EXIT>)
DSPTAB (LEV0L,LSTCMD,<LIST>)
DSPTAB (LEV0CO,OUTPUT,<OUTPUT>)
DSPTAB (LEV0CP,PLOT,<PLOT>)
DSPTAB (LEV0RM,REMDAT,<REMEMBER>)
DSPTAB (CRLF,SKDCMD,<SCHEDULE>)
DSPTAB (LV0ST1,SET,<SET>)
DSPTAB (LEV0CU,UPDATE,<UPDATE>)
$ETAB
LEV0RM: $NOISE (CRLF,<ESTIMATED DATES FOR FUTURE COMPARISON>)
LV0ST1: $KEYDSP (LV0ST2)
LV0ST2: $STAB
DSPTAB (LV0SH1,SETHOL,<HOLIDAY>)
DSPTAB (LV0SP1,SETPPA,<PERT-PLACEMENT-ALGORITHM>)
DSPTAB (CRLF,SETSAF,<SAFE-UPDATE-MODE>)
DSPTAB (LV0SD1,SETDAT,<SCHEDULE-DATE>)
DSPTAB (CRLF,SETSLB,<SLOPPY-BUT-FAST-UPDATE-MODE>)
$ETAB
LV0SH1: $NOISE (LV0SH2,<DATE>)
LV0SH2: $DATE (CRLF)
LV0SD1: $NOISE (LV0SD2,<TO>)
LV0SD2: $DATE (CRLF)
LV0SP1: $NOISE (LV0SP2,<TO THE>)
LV0SP2: $KEYDSP (LV0SP3)
LV0SP3: $STAB
DSPTAB (LV0SP4,0,<DEFAULT>)
DSPTAB (LV0SP4,1,<HIGH-DENSITY>)
$ETAB
LV0SP4: $NOISE (CRLF,<PLACEMENT ALGORITHM>)
LEV0CA: $KEYDSP (LEV1A)
LEV1A: $STAB
DSPTAB (DATDV,L0DEV,<DEVELOPER>)
DSPTAB (LEV1AP,ADDP,<PROJECT>)
DSPTAB (LEV1AT,ADDT,<TASK>)
$ETAB
LEV1AP: $NOISE (LEV2P1,<PROJECT NAME>)
LEV2P1: $FIELD (CRLF,<NAME OF PROJECT TO BE ADDED TO THE PROJECT LIST>)
LEV1AT: $NOISE (LEV2T1,<TASK NAME>)
LEV2T1: $FIELD (LEV2T2,<NAME OF THE TASK TO BE ADDED TO THE TASK LIST>)
LEV2T2: $NOISE (LEV2T3,<TO PROJECT>)
LEV2T3: PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ)
LEV0CD: $KEYDSP (LEV1D)
LEV1D: $STAB
DSPTAB (DATDLD,DELODV,<DEVELOPER>)
DSPTAB (LEV1DP,DELPRJ,<PROJECT>)
DSPTAB (CRLF,DELDAT,<SCHEDULE-DATE>)
DSPTAB (LEV1DT,DELTSK,<TASK>)
$ETAB
LEV1DP: $NOISE (LEV2D1,<PROJECT NAME>)
LEV2D1: PDBDEF (.CMKEY,,,,,,CRLF,,STOTSK,SETPRJ)
LEV1DT: $NOISE (LEV2D2,<FROM PROJECT>)
LEV2D2: PDBDEF (.CMKEY,,,,,,LEV2D3,,STOTSK,SETPRJ)
LEV2D3: $NOISE (LEV2D4,<TASK NAME>)
LEV2D4: PDBDEF (.CMKEY,,,,,,CRLF,,,SETTSK)
LEV0L: $KEYDSP (LEV1L)
LEV1L: $STAB
DSPTAB (LEV1L1,LISTP,<PROJECT>)
$ETAB
LEV1L1: PDBDEF (.CMKEY,,,,,,LEV1L2,,STOTSK,SETPRJ)
LEV1L2: $NOISE (LEV1L3,<TASK>)
LEV1L3: PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK)
LEV0CO: $KEYDSP (LEV1OT)
LEV1OT: $STAB
DSPTAB (LEV1O,CMPDAT,<CHANGES-IN-ESTIMATED-DATES>)
DSPTAB (LEV1O,DUMP,<CONTROL-FILE>)
DSPTAB (LEV1CP,OUTCP,<CRITICAL-PATH>)
DSPTAB (LEV1O,LSTDEV,<DEVELOPER-LIST>)
DSPTAB (LEVOG,GANTT,<GANTT-CHART>)
DSPTAB (LEV1O,LPATHC,<PATH-CHARACTER-LIST>)
DSPTAB (LEV1O,PERT,<PERT-CHART>)
DSPTAB (LEV1O,LSTSKD,<SCHEDULE>)
DSPTAB (LEV1O,SPERT,<SELECTED-PERT-BOXES>)
DSPTAB (LV1OT1,LSTTSK,<TASK-LIST>)
$ETAB
LV1OT1: $NOISE (LV1OT2,<SORTED BY>)
LV1OT2: $KEYDSP (LV1OT3)
LV1OT3: $STAB
DSPTAB (LEV1O,LSTTKE,<EARLIEST-START-DATE>)
; DSPTAB (LEV1O,LSTTKL,<LATEST-START-DATE>)
DSPTAB (LEV1O,LSTTKP,<PROJECT>)
$ETAB
LEVOG: $NOISE (LEVOG1,<OF>)
LEVOG1: $KEYDSP (LEVOGT)
LEVOGT: $STAB
DSPTAB (LEV1O,0,<DEVELOPERS>)
DSPTAB (LEV1O,2,<MILESTONES>)
DSPTAB (L1ONLY,4,<ONLY-DEVELOPER>)
DSPTAB (LEV1O,1,<TASKS>)
$ETAB
L1ONLY: PDBDEF (.CMUSR,CM%PO,,,,,LEV1O)
LEV0CP: $KEYDSP (LV0CPT)
LV0CPT: $STAB
DSPTAB (LEVOG,GPLOT,<GANTT-CHART>)
DSPTAB (LEV1O,PPLOT,<PERT-CHART>)
DSPTAB (LEV1O,SPPLOT,<SELECTED-PERT-BOXES>)
$ETAB
LEV1O: $NOISE (LEV1O1,<TO FILE>)
LEV1O1: $OFILE (CRLF)
LEV0CU: $NOISE (LEV0U1,<PROJECT>)
LEV0U1: PDBDEF (.CMKEY,,,,,,LEV1U,,STOTSK,SETPRJ)
LEV1U: $NOISE (LEV1U1,<TASK>)
LEV1U1: PDBDEF (.CMKEY,,,,,CRLF,CRLF,,,SETTSK)
SDATA: $INIT (SDATA1)
SDATA1: $NUMBER (CRLF,<^D10>,<LOOK AHEAD LEVEL>)
LEV1CP: $NOISE (LV1CP1,<FOR PROJECT>)
LV1CP1: PDBDEF (.CMKEY,,,,,,LV1CP2,,STOTSK,SETPRJ)
LV1CP2: $NOISE (LV1CP3,<TASK>)
LV1CP3: PDBDEF (.CMKEY,,,,,,LEV1O,,,SETTSK)
;PROJECT DATA COMMAND
PDATA: $INIT (PDATA1)
PDATA1: $KEYDSP (PDATAT)
PDATAT: $STAB
DSPTAB (PDATDL,PRJDEL,<DELETE>)
DSPTAB (DATDV,PRJDEV,<DEVELOPER>)
DSPTAB (PDATAF,PRJFIN,<FINISHED>)
DSPTAB (CRLF,PRJLST,<LIST>)
DSPTAB (PDATP,PRJPRF,<PREFERENCE-VALUE>)
DSPTAB (CRLF,PRJDSC,<PROJECT-DESCRIPTION>)
$ETAB
PDATDL: $KEYDSP (PDTDL1)
PDTDL1: $STAB
DSPTAB (PDTDLD,PRJDLD,<DEVELOPER>)
$ETAB
PDTDLD: PDBDEF (.CMUSR,CM%PO,,,,,CRLF)
PDATAF: $NOISE (CRLF,<UPDATING PROJECT DATA>)
PDATP: $NOISE (PDATP1,<FOR FREE CHOICE>)
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,<ALL-DEVELOPERS-REQUIRED>)
DSPTAB (DATAT,TKAT,<ATTRIBUTE>)
DSPTAB (DATCD,TKCD,<COMPLETION-DATE>)
DSPTAB (DATDL,TKDL,<DELETE>)
DSPTAB (DATDP,TKDP,<DEPENDENCY>)
DSPTAB (DATDV,TKDV,<DEVELOPER>)
DSPTAB (DATEL,TKEL,<ESTIMATED-PROJECT-LENGTH>)
DSPTAB (DATXD,TKXD,<EXPECTED>)
DSPTAB (DATFC,TKFC,<FINISHED>)
DSPTAB (CRLF,TKLS,<LIST>)
DSPTAB (DATLA,TKLA,<LONG-ATTRIBUTE>)
DSPTAB (CRLF,TKMI,<MILESTONE>)
DSPTAB (DATMD,TKMD,<MINIMUM-STARTING-DATE>)
DSPTAB (DATPA,TKPTH,<PATH-CHARACTER>)
DSPTAB (DATPF,TKPF,<PREFERENCE-VALUE>)
DSPTAB (DATSD,TKSD,<STARTING-DATE>)
DSPTAB (DATTD,TKTD,<TASK-DESCRIPTION>)
DSPTAB (DATTI,TKTI,<TIME-TO-DATE>)
DATT1L==.-DATAT1
DATXD: $KEYDSP (DATXD1)
DATXD1: $STAB
DSPTAB (DATXD2,0,<COMPLETION-DATE>)
DSPTAB (DATXD2,1,<STARTING-DATE>)
$ETAB
DATXD2: $NOISE (DATXD3,<IS>)
DATXD3: $DATE (CRLF)
DATCD: $DATE (CRLF) ;COMPLETION-DATE
DATMD: $DATE (CRLF) ;MINIMUM STARTING DATE
DATPA: $NOISE (DATPA1,<IS>)
DATPA1: $FIELD (CRLF,<SINGLE ALPHA-NUMERIC CHARACTER TO LABEL THE CRITICAL PATH FOR THIS TASK>)
DATDL: $KEYDSP (DATDL1)
DATDL1: $STAB
DSPTAB (CRLF,TKDCD,<COMPLETION-DATE>)
DSPTAB (DATDP,TKDDP,<DEPENDENCY>)
DSPTAB (DATDLD,TKDLD,<DEVELOPER>)
DSPTAB (CRLF,TKDEL,<ESTIMATED-PROJECT-LENGTH>)
DSPTAB (DATDX,TKDXD,<EXPECTED>)
DSPTAB (CRLF,TKDMD,<MINIMUM-STARTING-DATE>)
DSPTAB (CRLF,TKDPC,<PATH-CHARACTER>)
DSPTAB (CRLF,TKDPF,<PREFERENCE-VALUE>)
DSPTAB (CRLF,TKDSD,<STARTING-DATE>)
DSPTAB (CRLF,TKDTI,<TIME-TO-DATE>)
$ETAB
DATDX: $KEYDSP (DATDX1)
DATDX1: $STAB
DSPTAB (CRLF,0,<COMPLETION-DATE>)
DSPTAB (CRLF,1,<STARTING-DATE>)
$ETAB
DATDLD: PDBDEF (.CMUSR,CM%PO,,,,,CRLF)
DATDP: $NOISE (DATDP1,<ON PROJECT>) ;DEPENDENCY (ON PROJECT)
DATDP1: PDBDEF (.CMKEY,,,,,,DATDP2,,STOTSK,SETPRJ)
DATDP2: $NOISE (DATDP3,<TASK NAME>)
DATDP3: PDBDEF (.CMKEY,,,,,,DATDP4,,,SETTSK)
DATDP4: $CRLF
DATDV: PDBDEF (.CMUSR,CM%PO,,,,,DATDV1) ;DEVELOPER
DATDV1: $NOISE (DATDV2,<RATE>)
DATDV2: $FLOAT (DATDV3,<FRACTIONAL TIME TO BE ALLOCATED ON THIS TASK>)
DATDV3: $NOISE (DATDV4,<HANDICAP>)
DATDV4: $FLOAT (DATDV5,<RELATIONSHIP OF DEVELOPERS RATE TO ESTIMATE OF PROJECT LENGTH>)
DATDV5: $CRLF
DATEL: $NOISE (DATEL1,<IN DAYS>) ;ESTIMATED-PROJECT-LENGTH
DATEL1: $NUMBER (DATEL2,<^D10>,<NUMBER OF WORK DAYS TO DO THIS TASK>)
DATEL2: $CRLF
DATFC: $NOISE (CRLF,<UPDATING TASK DATA>)
DATPF: $NOISE (DATPF1,<FOR FREE CHOICE>)
DATPF1: $FLOAT (CRLF)
DATSD: $DATE (DATSD1) ;STARTING-DATE
DATSD1: $CRLF
DATTD: $CRLF ;TASK-DESCRIPTION
DATTI: $NOISE (DATTI1,<IN DAYS>) ;TIME-TO-DATE
DATTI1: $NUMBER (DATTI2,<^D10>,<NUMBER OF DAYS ALREADY SPENT ON THIS TASK>)
DATTI2: $NOISE (DATTI3,<AT DATE>)
DATTI3: $DATE (DATTI4)
DATTI4: $CRLF
DATLA: $NOISE (DATLA1,<NAME IS>)
DATLA1: $FIELD (CRLF,<NAME OF ATTRIBUTE>)
DATAT: $NOISE (DATATR,<NAME IS>)
DATATR: $FIELD (DATTR1,<NAME OF ATTRIBUTE>)
DATTR1: $NOISE (DATTR2,<VALUE>)
DATTR2: $FIELD (CRLF,<VALUE OF ATTRIBUTE>)
;YES/NO COMMAND TABLE
YNCT: $INIT (YNCT1)
YNCT1: $KEY (CRLF,YNCTTB)
YNCTTB: YNCTBL-1,,YNCTBL-1
KEYTAB (,0,<NO>)
KEYTAB (,1,<YES>)
YNCTBL==.-YNCTTB
CRLF: $CRLF
SEL: $INIT (SEL1)
SEL1: $KEYDSP (SELT1)
SELT1: $STAB
DSPTAB (SELF,SELFI,<FINISHED>)
DSPTAB (SELI,SELIP,<INCLUDE>)
$ETAB
SELI: $KEYDSP (SELI1)
SELI1: $STAB
DSPTAB (SELI2,SELIPR,<PROJECT>)
$ETAB
SELI2: $NOISE (LEV0U1,<NAME>)
SELF: $NOISE (CRLF,<SELECTING -- START PERT>)
XLIST ;LITERALS
VAR
LIT
LIST ;LITERALS
END <3,,ENTVEC>