%%s 0/0/0 %%d D 1.1 27-Mar-82 14:32:56 v1.1 1 0 %%c Version 1.1 is the Spring 1982 Distribution of the LBL/Hughes release %%c of the Software Tools Virtual Operating System software and documentation. %%T %%I 1 #-h- defns 2085 asc 26-mar-82 18:29:13 v1.1 (sw-tools v1.1) define(DATESIZE, 10) define(NOWSIZE, 7) define(TIMESIZE, 9) ifdef(LARGE_ADDRESS_SPACE) define(MAXMEM,44000) elsedef ifdef(DO_PAGING) define(MAXMEM,32512) elsedef define(MAXMEM,11000) enddef enddef define(HIGHEND, arith(MAXMEM,+,1)) # used when counting backwards from top define(MAXINTEGER, 32687) define(COMPLEMENT, 1) define(MAXCHARS, 20) # TCS data file keys define(STATS,"%%s ") # statistics define(VERKEY,"%%d ") # key field on history-info lines define(COMMENT,"%%c ") define(ENDKEY,"%%T") # end of header define(INSERT,"%%I ") # begin "inserted in this version" define(DELETE,"%%D ") # begin "deleted in this version" define(ENDSEG,"%%E ") # end of segment define(KEYSIZ,5) # pts AFTER blank at end of key define(WEWANT,2) # positional info from PARSE define(THISVER,6) define(PREVVER,7) define(MAXVER,100) # max number of (direct) ancestors define(OFF,0) define(ON,1) # flow control during DIFF processing # values for "flag" define(INHIST, 1) define(INRVSN, 2) define(MATCHING, 3) # simulated "structure" during DIFF tree generation define(PREV, 0) define(ALINE, 1) define(BLINE, 2) define(CANDSIZ, 3) # size of a candidate "struct" # definitions to convert long names to 6 characters define(save,#) define(ancestry,anstry) define(myances,myancs) define(seekptr,seekpt) define(makdelta,makdel) define(hisfile,hisfil) define(revfile,revfil) define(newfile,newfil) define(scrfile,scrfil) define(lineget,linget) define(incvnum,incvno) define(outarray,outara) define(filename,filnam) define(passthru,psthru) define(currnest,curnst) define(aputlin,aputln) # # definitions for virtual paging routines # ifdef(DO_PAGING) define(INTS_PER_PAGE,256) define(PAGE_SIZE,512) define(PF_SIZE,arith(arith(arith(MAXMEM,+,1),/,INTS_PER_PAGE),+,1)) define(RESIDENT_PAGES,32) define(PHYMEM,arith(RESIDENT_PAGES,*,INTS_PER_PAGE)) define(get_tab,gettab) define(set_tab,{istab1=$1; istab2=$2; call settab(istab1, istab2)}) elsedef define(get_tab,tab($1)) define(set_tab,tab($1) = $2) define(PHYMEM,MAXMEM) enddef define(USE_QUICKSORT,) #-h- decls 402 asc 26-mar-82 11:45:50 v1.1 (sw-tools v1.1) common /tcs/ ancestry(MAXVER), # family lineage fdhis, fdrev, fdscr, # file descriptors flag, # flag during history-file generation insert, # flag during lineget, init'd by rstget myances, # closest ancestor's "absolute" version number maxver, # last "absolute" version number seekptr(2) # note/seek pointer integer ancestry, fdhis, fdrev, fdscr, flag, insert, myances, maxver, seekptr #-h- delta.r 30594 asc 27-mar-82 14:29:00 v1.1 (sw-tools v1.1) #-h- main 1007 asc 25-mar-82 07:36:24 v1.1 (sw-tools v1.1) # program DELTA subroutine main include "defns" include "decls" define(GET,) integer getarg, getlin character histry(FILENAMESIZE) character rvisn(FILENAMESIZE) character nwhsty(FILENAMESIZE) character reason(MAXLINE) character wanted(40) # the desired version number integer prompt integer i call query("usage: delta revision history [newhistory].") if (getarg(1, rvisn, FILENAMESIZE) == EOF | getarg(2, histry, FILENAMESIZE) == EOF) call error("? usage: delta revision history [newhistory].") if (getarg(3, nwhsty, FILENAMESIZE) == EOF) call scopy(histry, 1, nwhsty, 1) # For now, DELTAs may only be performed on the "latest" # version in the tcs file. Branches work, but no tool exists for # (auto-)insertion of branch points. # To turn this feature on, pass the branch's ancestor in 'wanted'. # It is expected that GET will stow the version number "gotten" # and that DELTA will stem from that info. wanted(1) = EOS # zap '@n' call makdelta(histry, rvisn, nwhsty, wanted) end #-h- makdelta 11656 asc 26-mar-82 18:11:20 v1.1 (sw-tools v1.1) # The DIFF algorithm from BTL Computing Science Technical Report #41, # "An Algorithm for Differential File Comparison", # by J.W. Hunt and M.D. McIlroy. # Comments on the use of the "tab" array: # # The V[] vector grows from both ends of TAB towards the middle. # The "serial" (line number) entries are at the bottom and the # corresponding "hash" entries at the top. # These are sorted... # ...and "last" members of equivalence classes have their sign # toggled to mark the end of a class. # Magic positions in the TAB array: # nnn = # of lines read from file 2 # nnn+3 -> start of data learned from file 1 # # # in order to permit a virtual array version of this routine, # all manipulations of the tab array are in terms of the # macros get_tab and set_tab # # get_tab(index) # # set_tab(index, value) # # makdelta - back up revised file in history file. subroutine makdelta(hisfile, revfile, newfile, wanted) # McI: file1=hisfile and file2=revfile include "decls" include "conds" character hisfile(FILENAMESIZE) # name of history file character revfile(FILENAMESIZE) # name of revision file character newfile(FILENAMESIZE) # name of new history file # (may be hisfile) character scrfile(FILENAMESIZE) # name of scratch file character wanted(40) character hisbuf(MAXLINE) # file input buffers character revbuf(MAXLINE) integer bmatch, create, remove, index integer equal, getlin, iabs, hash, lineget, open, prompt integer c, cand, count, junk character date(DATESIZE), time(TIMESIZE) integer from, to # line numbers of common sequences integer high, now(NOWSIZE) integer irec1, irec2 integer i, j, k integer kmid, ks, ks1 integer len1, len2, low, midpt integer key # computed hash value integer nil integer p, r, s integer mmm, nnn # length of file1 & file2 string sct "SCT" fdrev = open(revfile, READ) if (fdrev == ERR) call cant(revfile) fdscr = open( hisfile, READ) # make sure .tcs file exists if( fdscr == ERR ) call error("? Can't find TCS history file.") call close(fdscr) call scratf(sct, scrfile) fdscr = create(scrfile, WRITE) if (fdscr == ERR) call cant(scrfile) # Stick in the user's comment before all else call putlin("History?", ERROUT); call putch('@n', ERROUT) repeat { # append the reason for change i = prompt("> ", hisbuf, STDIN) if (i == EOF) break if ((i == 2) & (hisbuf(1) == '.')) break call putlin(COMMENT, fdscr) call putlin(hisbuf, fdscr) } # STEP 0. Increment the version number. call setget(hisfile, wanted) # sets up ancestry of "wanted" version call incvnum(wanted) call putlin("New Version is # ", ERROUT) call putlin(wanted, ERROUT) call putch('@n', ERROUT) maxver = maxver + 1 # next "absolute" version number # can write some stuff to scratch file here ?? ifdef(DO_PAGING) call virint enddef # STEP 1. Input new (revision) file. # McI: V[] vector, # "serial" grows UP and # "hash" grows DOWN from the top for(j = 1; j< HIGHEND-j; j = j+1) { if (getlin(revbuf, fdrev) == EOF) break set_tab(j, j) # save line number # McI: H(j) function key = hash(revbuf) # store the hash values set_tab(HIGHEND-j, key) # sequentially from the # END of the array } call close(fdrev) nnn = j - 1 # line count of revfile if (nnn == 0) call error("Revision file is empty.") # STEP 2. Sort. # Ascending order, hash as primary key and serial as secondary. call dosort(nnn) # STEP 3. Mark equivalence classes. # McI: E[] vector # "sign" of serial used as # the "last" flag for (j = 1; j < nnn; j = j + 1) # McI: f(j) if (get_tab(HIGHEND-j) != get_tab(HIGHEND-j-1)) { set_tab(j, -get_tab(j)) # toggle to true } set_tab(nnn, -get_tab(nnn)) # final entry is (of course) true # STEP 4. Input hisfile and match with revfile # McI: P[] vector for (i = nnn+3; i < HIGHEND-nnn; i = i + 1) { if (lineget(hisbuf, NO) == EOF) break key = hash(hisbuf) # hash value for this line j = 0 # initialize low = 0 high = nnn+1 while (low+1 < high) { # binary search for matching hash midpt = (low+high) / 2 # search midpoint kmid = HIGHEND-midpt # kmid points to corr. hash entry if (get_tab(kmid) < key) # compare, too high or too low low = midpt # move endpoint up else { high = midpt # move endpoint down if (get_tab(kmid) == key) # match found, save its position # continued searching finds the # highest (position) matching entry j = midpt } } set_tab(i, j) # saves zero or (highest) matching # entry number } totsiz = i-1 # hisfile + revfile + 2 mmm = totsiz - nnn - 2 # number of lines in file1 (hisfile) if (mmm == 0) call error("History file is empty.") # STEP 5. Setup for longest common subsequence. cand = totsiz+1 # candidate nil = totsiz+1 k = nnn+1 # McI: K[0] set_tab(cand+ALINE, nnn+2) set_tab(cand+BLINE, 0) set_tab(cand+PREV, nil) set_tab(k, cand) cand = cand+CANDSIZ # McI: K[1] set_tab(cand+ALINE, totsiz+1) set_tab(cand+BLINE, nnn+1) set_tab(cand+PREV, nil) set_tab(k+1, cand) cand = cand+CANDSIZ # STEP 6. Find longest common sequence. for (i = nnn+3; i <= totsiz; i = i + 1) { # This loop traverses the P[] vector # (step4) from 1 to mmm. p = get_tab(i) # P[] points to start of the class of # lines in file2 == line "i" in file1. if (p != 0) { # has 0 or line# of match in file2 # McI: procedure MERGE(K,k,i,E,p) # K[] {tab(totsiz+1:k} from step5 # "k" is the last filled index in K[] # "i" is the current index in file1 # E[] {tab(1:nnn)} from step3 # "p" is index in E of 1st element of # class of lines in file2 equivalent # to line "i" of file1. # McI: (merge.1) # Initially: r <- 0; c <- K[r] r = nnn+1 # ptr into K[] c = get_tab(r) # will always refer to LAST cand found repeat { # McI: (merge.2) j = iabs(get_tab(p)) # McI: (merge.3) j <- E[p].serial # Search K[r:k] for an element K[s] # such that K[s]->BLINE < j and # K[s+1]->BLINE >= j. Binary search. low = r high = k while (low <= high) { s = (low+high) / 2 ks = get_tab(s) if (get_tab(ks+BLINE) >= j) high = s - 1 else { ks1 = get_tab(s+1) if (get_tab(ks1+BLINE) >= j) break low = s+1 } } if (low <= high) { if (get_tab(ks1+BLINE) > j) { # McI: (merge.4) set_tab(r, c) # K[r] <- c r = s + 1 if (cand > HIGHEND-3 ) call error("Files are too big to handle.") # c <- cand(i,j,K[s]) set_tab(cand+ALINE, i) set_tab(cand+BLINE, j) set_tab(cand+PREV, ks) c = cand cand = cand+CANDSIZ } if (s == k) { # McI: (merge.5) set_tab(k+2, get_tab(k+1))# move fence k = k + 1 break } } if (get_tab(p) < 0) # McI: (merge.6) if E[p].last == true, break # then break out of step2's loop, else # otherwise increment "p". p = p + 1 } set_tab(r, c) # McI: (merge.7) K[r] <- c } } # STEP 7. Clear table. # Discard the P[] vector. # Let J[0:m] be a vector of integers. c = get_tab(k) # save for step8 for (i = nnn+3; i <= totsiz; i = i + 1) set_tab(i, 0) # zero out J[] set_tab(totsiz+1, nnn+1) # STEP 8. Build table. # For each element "c" of the chain # of candidates referred to by K[k] # and linked by "PREV" references, # set: J[c.a] <- c.b while (c != nil) { # traverse the tree i = get_tab(c+ALINE) j = get_tab(c+BLINE) set_tab(i, j) c = get_tab(c+PREV) } # The non-zero elements of J now pick out a longest common subsequence, # possibly including spurious "jackpot" sequences. The pairings between # the two files are given by: { (i,J[i]) | J[i] != 0 }. # STEP 9. Print the differences. Weed out jackpots. call rstget() # return to start of history text fdrev = open(revfile, READ) # return to top of revision if (fdrev == ERR) call cant(revfile) irec1 = 0; irec2 = 0; count = 0 # Transitions in the state signal # a change in the correspondence # between the two files. # This version is set up for the # Text Control System # and therefore develops the # "differences" in an appropriate # manner. i = nnn+2 flag = MATCHING # holds current state repeat { irec1 = irec1 + 1 if (irec1 <= mmm) len1 = lineget(hisbuf, YES) # history file i = i + 1 j = get_tab(i) if (j == 0) { # no matching line found # in revision-file if (flag != INHIST) { if (flag == INRVSN) call puttag(ENDSEG) call puttag(DELETE) flag = INHIST } call putlin(hisbuf, fdscr) # put out "old" line } else { # potential match repeat { irec2 = irec2 + 1 if (irec2 <= nnn) len2 = getlin(revbuf, fdrev) # revision file if (irec2 >= j) # MAY be a match break if (flag != INRVSN) { if (flag == INHIST) call puttag(ENDSEG) call puttag(INSERT) flag = INRVSN } call putlin(revbuf, fdscr) } if (irec2 > nnn) break if (equal(hisbuf, revbuf) == YES) { # assures equality if (flag != MATCHING) { call puttag(ENDSEG) flag = MATCHING } count = count + 1 call putlin(hisbuf, fdscr) # matching line } else { # jackpot # Jackpot! The hash results matched, but # the lines were not identical. Output the lines # with appropriate wrappers and carry onward. if (flag != INHIST) { if (flag == INRVSN) call puttag(ENDSEG) call puttag(DELETE) } call putlin(hisbuf, fdscr) call puttag(ENDSEG) call puttag(INSERT) call putlin(revbuf, fdscr) flag = INRVSN } } } if (flag != MATCHING) call puttag(ENDSEG) # copy the rest of the history to the end of the new history file while (lineget(hisbuf, YES) != EOF) # let lineget xfer the lines to the new file call putlin(hisbuf, fdscr) call close(fdhis) call close(fdrev) call close(fdscr) call putnum(nnn - count, 1, ERROUT) # print the statistics call remark(" insertions.") call putnum(mmm - count, 1, ERROUT) call remark(" deletions.") call putnum(count, 1, ERROUT) call remark(" unchanged.") # STEP 10. Move the result to the new-history file, # prepending the new family tree info. fdhis = create(newfile, WRITE) # re-use file descriptor if (fdhis == ERR) call cant(newfile) fdscr = open(scrfile, READ) if (fdscr == ERR) { call putlin("Temp file error: ", ERROUT) call cant(scrfile) } # add a "hash" value for integrity call putlin(STATS, fdhis) # statistics call putnum(nnn - count, 1, fdhis) call putch('/', fdhis) call putnum(mmm - count, 1, fdhis) call putch('/', fdhis) call putnum(count, 1, fdhis) call putch('@n', fdhis) call putlin(VERKEY, fdhis) call putlin("D ", fdhis) # signal delta call putlin(wanted, fdhis) call putch(' ', fdhis) call getnow(now) call fmtdat( date, time, now, LETTER) call putlin( date, fdhis) call putch(' ', fdhis) call putlin( time, fdhis) call putch(' ', fdhis) call mailid(revbuf) # fetch user name i = index(revbuf, ' ') # see if blank embedded in user name if (i > 0) # YES, truncate name revbuf(i) = EOS call putlin(revbuf, fdhis) call putch(' ', fdhis) call putnum(maxver, 1, fdhis) call putch(' ', fdhis) call putnum(myances, 1, fdhis) call putch('@n', fdhis) # now move the file while (getlin(hisbuf, fdscr) != EOF) call putlin(hisbuf, fdhis) # cleanup call close(fdscr) call close(fdhis) junk = remove(scrfile) ifdef(DO_PAGING) call virfin enddef return end #-h- parse 1880 asc 25-mar-82 07:36:37 v1.1 (sw-tools v1.1) #-p- #****************************************************************************** #* #* #* PARSE #* #* author: Neil P Groundwater date: 12-AUG-81 #* #* #* #* Purpose: Decompose the "Ad" lines in the history file return the #* members of the line via an array of indexes into the original text #* line. Replace the delimiter character with EOS characters. #* #* #* Calling convention: parse(inbuf, from, outarray, delim) #* #* #* Formal Parameters #* inbuf: Input string (array) #* from: Starting index in inbuf #* outarray: Returned array of member-offsets in inbuf #* delim: Delimiter character supplied by caller #* #* #* Modules which call PARSE #* main #* #* #* Description of algorithm: Move "pointer" across input line and set #* outarray with pertinent values. #* #* #****************************************************************************** #-p- # Subroutine: PARSE(INBUF, FROM, OUTARRAY, DELIMITER) # Enter the chars from the inbuf, # break it into its components # Outarray will contain pointers to the start of each memeber of inbuf # Convert the delimiters to EOS, in place. # The string is assumed to be '@n' terminated. define(NULL,0) subroutine parse(inbuf, from, outarray, delim) character inbuf(MAXLINE) integer from # start offset in inbuf integer outarray(16) # point to each "token" character delim integer ptr ptr = from while (inbuf(ptr) == delim) # skip to 1st field ptr = ptr+1 for (i=1; inbuf(ptr) != '@n'; i=i+1) { outarray(i) = ptr # skip thru field while ((inbuf(ptr) != delim) & (inbuf(ptr) != '@n')) ptr = ptr+1 # zap and skip delimiters while ((inbuf(ptr) == delim) & (inbuf(ptr) != '@n')) { inbuf(ptr) = EOS ptr = ptr+1 } } inbuf(ptr) = EOS outarray(i) = NULL return end #-h- bmatch 310 asc 25-mar-82 07:36:39 v1.1 (sw-tools v1.1) # bmatch - most basic match, Software Tools p. 140. (renamed) integer function bmatch(lin, from, pat) character lin (MAXLINE), pat(MAXLINE) integer from, i, j i = from for (j=1; pat(j) != EOS; j = j + 1) { if (lin(i)!=pat(j)) { bmatch = 0 return # with no match } i = i + 1 } bmatch = i return end #-h- bmch2 308 asc 25-mar-82 07:36:39 v1.1 (sw-tools v1.1) # bmch2 - basic match, also compares the LENGTH of the args integer function bmch2(lin, from, pat) character lin (MAXLINE), pat(MAXLINE) integer from integer equal character temp(MAXLINE) call scopy(lin, from, temp, 1) # copy string to temp return(equal(temp, pat)) # returns YES if exactly equal end #-h- ctoi2 959 asc 25-mar-82 07:36:40 v1.1 (sw-tools v1.1) #-p- #****************************************************************************** #* #* #* CTOI2 #* #* author: Neil P Groundwater date: 12-AUG-81 #* #* #* #* Purpose: Calls CTOI but allows the caller of CTOI2 to pass a #* fixed-value argument. #* #* #* Calling convention: ctoi2(buf, fixed) #* #* #* Formal Parameters #* buf: input string #* fixed: offset in buf to begin conversion. May be a FIXED NUMBER #* (like 3). #* #* #* Module Returns: An integer value. #* #* #* Modules called by CTOI2 #* ctoi #* #* #* Modules which call CTOI2 #* main #* #* #****************************************************************************** #-p- # convert character string to integer - allows "constant" index as arg integer function ctoi2(buf, fixed) character buf integer fixed integer ctoi integer ptr ptr = fixed return(ctoi(buf, ptr)) end #-h- setget 2486 asc 25-mar-82 07:36:41 v1.1 (sw-tools v1.1) # subroutine SETGET (FILENAME, WANTED) # Set up ANCESTRY of the previous version of the file. # # Used in conjunction with LINEGET which will return # the next line from the desired version and RSTGET # which puts the file pointer at the start of the # "content" portion of the file in preparation for # a new series of LINEGET calls. subroutine setget (filename, wanted) character filename(FILENAMESIZE) character wanted(FILENAMESIZE) include "decls" integer bmatch, bmch2, close, ctoi2, getlin, open, note # functions integer junk character inbuf(MAXLINE) integer array(16) # holds pointers returned by PARSE integer i integer thread, iprev, ithis # trace family tree fdhis = open(filename, READ) if (fdhis == ERR) call error("Cannot locate TCS history file.") for (i=1; i<=MAXVER; i=i+1) # initialize ancestry(i) = NO thread = -1 # follows back up tree repeat { i = getlin(inbuf, fdhis) if (i == EOF) call error("Unexpected EOF on history-info scan.") GET call putlin(inbuf, fdscr) # keep it for posterity if (bmatch(inbuf, 1, ENDKEY) != 0) call error("Nonexistant revision level requested.") # Screen for version-info lines if (bmatch(inbuf, 1, VERKEY) != 0) { call parse(inbuf, KEYSIZ, array, ' ') ithis = ctoi2(inbuf, array(THISVER)) # thread values iprev = ctoi2(inbuf, array(PREVVER)) if (thread < 0) { # When the FIRST version-info line is detected, get # the "absolute" version number so that it may be # added later to the family tree. maxver = ithis thread = 0 } if (thread == 0) { # started yet? # Was either no version specified or # is this the requested version? if ((wanted(1) == EOS) | # if none, take latest version (bmch2(inbuf, array(WEWANT), wanted) == YES)) { if (wanted(1) == EOS) { # go get latest number call scopy(inbuf, array(WEWANT), wanted, 1) call putlin("Version # ", ERROUT) call putlin(wanted, ERROUT) call putch('@n', ERROUT) } # yes, start recording ancestry ancestry(ithis) = YES GET myances = ithis # parent of new stuff thread = iprev # predecessor if (thread == 0) # reached root break } else next # not a match, go on to next info-line } else # next on the tree? if (ithis == thread) { ancestry(ithis) = YES thread = iprev if (thread == 0) break # scan thru header is complete } } } junk = note(seekptr, fdhis) # tag the start of the text portion of the file return end #-h- rstget 139 asc 25-mar-82 07:36:42 v1.1 (sw-tools v1.1) subroutine rstget() include "decls" call seek(seekptr, fdhis) # point to start of data portion insert = OFF # current mode return end #-h- lineget 1393 asc 25-mar-82 07:36:43 v1.1 (sw-tools v1.1) # Ancestry has been established. Develop the particular version. # Returns a line-at-a-time to caller. integer function lineget (inbuf, passthru) character inbuf(MAXLINE) integer passthru # send text to new-history file include "decls" integer bmatch, ctoi2, getlin integer currnest, i save currnest repeat { i = getlin(inbuf, fdhis) if (i == EOF) call error("Unexpected EOF on history-data scan.") if (bmatch(inbuf, 1, ENDSEG) != 0) { if (ctoi2(inbuf, KEYSIZ) == 1) { # done if (passthru == YES) call putlin(inbuf, fdscr) # last line break } if (insert == OFF) if (ctoi2(inbuf, KEYSIZ) == currnest) insert = ON } else if (bmatch(inbuf, 1, INSERT) != 0) if (ancestry(ctoi2(inbuf, KEYSIZ)) == YES) insert = ON else { # not in one of its ancestors, # skip to matching ENDSEG line if (insert == ON) { currnest = ctoi2(inbuf, KEYSIZ) insert = OFF } } else if (bmatch(inbuf, 1, DELETE) != 0) { if (ancestry(ctoi2(inbuf, KEYSIZ)) == YES) # skip to matching ENDSEG line if (insert == ON) { currnest = ctoi2(inbuf, KEYSIZ) insert = OFF } } else if (insert == ON) return (i) # text returned in "inbuf" # pass all other lines thru to the output file if (passthru == YES) { if (flag == INHIST) { call puttag(ENDSEG) flag = MATCHING } call putlin(inbuf, fdscr) } } return (EOF) # at EOF end #-h- hash 362 asc 25-mar-82 07:36:44 v1.1 (sw-tools v1.1) integer function hash (mcard) character mcard(MAXLINE) integer i, n hash = 0 for (i=1; mcard(i) != EOS; i= i + 1) { n = mcard(i) if (n < 0) n = (n+MAXINTEGER) + COMPLEMENT if (hash < MAXINTEGER/2 ) hash = hash + hash + 1 else hash = (hash-MAXINTEGER) + hash-1 hash = n - hash if (hash < 0) hash = (hash+MAXINTEGER) + COMPLEMENT } return end #-h- incvnum 919 asc 25-mar-82 07:36:44 v1.1 (sw-tools v1.1) # Increment version-number string. # given a string: 1.2.33.44 # change it to: 1.2.33.45 # or 1.3.4.99 --> 1.3.4.100 # or 1.2 --> 1.3 subroutine incvnum( in ) character in(MAXLINE) define (FALSE, 0) define (TRUE, 1) integer ctoi, itoc integer eflag integer i, ki, n character tmp(10) # scratch spot i = 1 # ptr into string eflag = FALSE repeat { ki = i # start of final number in string n = ctoi(in, i) # get a number, ctoi moves "i" if (n > 0) # a number was found here eflag = FALSE # reset the flag if (in(i) != '.') # stop at EOS break else { i = i+1 # skip past 'dot' if (eflag == TRUE) call error("TCS Version number corrupted!") eflag = TRUE # prohibit consecutive delimiters } } if (n == 0) call error("TCS Version Number corrupted!") n = n+1 # increment version number i = itoc(n, tmp, 10) # store the new number call scopy(tmp, 1, in, ki) in(ki+i) = EOS return end #-h- putnum 335 asc 25-mar-82 07:36:45 v1.1 (sw-tools v1.1) # putnum - print integer in field width >=w # (modeled after putdec page 61 SOFTWARE TOOLS) subroutine putnum(n, w, file) character chars(MAXCHARS) integer itoc integer i, n, nd, w nd = itoc(n, chars, MAXCHARS) for (i=nd+1; i<=w; i=i+1) call putch(' ', file) for (i=1; i<=nd; i=i+1) call putch(chars(i), file) return end #-h- aputlin 464 asc 25-mar-82 07:36:46 v1.1 (sw-tools v1.1) # aputlin - call putlin, but start at a (given) offset in the line subroutine aputlin(str, off, outfd) character str(MAXLINE) integer off, outfd character tmplin(MAXLINE) integer i, j i = off-1 j = 1 # start of buffer repeat { i = i+1 # point TO the char xferred tmplin(j) = str(i) j = j+1 # point AFTER the char just xferred } until ((str(i) == EOS) | (str(i) == '@n')) tmplin(j) = EOS # terminate the string call putlin(tmplin, outfd) return end #-h- puttag 152 asc 25-mar-82 07:36:46 v1.1 (sw-tools v1.1) subroutine puttag( tag ) character tag(20) include "decls" call putlin(tag, fdscr) call putnum(maxver, 1, fdscr) call putch('@n', fdscr) return end #-h- gettab 185 asc 26-mar-82 17:46:32 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) integer function gettab(virndx) integer virndx, phyndx, page integer virphy include ctab page = virphy(virndx, phyndx) return(tab(phyndx)) end enddef #-h- settab 222 asc 27-mar-82 09:59:31 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine settab(virndx, value) integer virndx, value, page, phyndx integer virphy include ctab page = virphy(virndx, phyndx) tab(phyndx) = value call pdirty(page) return end enddef #-h- mapphy 786 asc 25-mar-82 17:19:11 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine mapphy(i) integer i, n, j, pnd, junk integer note filedes create include cvirt include cvfile include clru string vpf "vpf" if (virunt == ERR) { call scratf(vpf, vpfile) virunt = create(vpfile, B_READWRITE) if (virunt == ERR) call error("Cannot open paging file.") junk = note(virend, virunt) } n = lrup(1) # lru header to be paged j = pfnp(n) # page frame index of outgoing page pnd = abs(phyind(j)) # save physical index of page call pagout(j) # page out, if dirty phyind(i) = pnd # physical index of incoming page call pagin(i) # page it into memory pfnp(n) = i # page 'i' is now mapped call mruset(n) # make n the most recently used page return end enddef #-h- mruset 376 asc 25-mar-82 17:19:12 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine mruset(n) integer n, i, j include clru if (n != 1) { j = lrup(n) # unlink n from list i = mrup(n) # ... mrup(j) = i # ... lrup(i) = j # ... i = mrup(1) # link n into MRU position mrup(1) = n # ... lrup(i) = n # ... lrup(n) = 1 # ... mrup(n) = i # ... } return end enddef #-h- pagin 424 asc 25-mar-82 17:19:13 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine pagin(i) integer i, n, junk integer readf, ptreq include cvirt include cvfile include ctab n = phyind(i) if (ptreq(dskadr(i), NULLPOINTER) == YES) # demand 0 page { junk = n + INTS_PER_PAGE for ( ; n < junk; n=n+1) tab(n) = 0 } else { call seek(dskadr(i), virunt) junk = readf(tab(n), PAGE_SIZE, virunt) } return end enddef #-h- pagout 638 asc 25-mar-82 17:19:14 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine pagout(j) integer j, n, junk, reset integer writef, ptreq, note include cvirt include cvfile include ctab if (phyind(j) < 0) # page is dirty, write it out { n = abs(phyind(j)) if (ptreq(dskadr(j), NULLPOINTER) == YES) # must write at end of file { call ptrcpy(virend, dskadr(j)) reset = YES # reset EOF address } else reset = NO call seek(dskadr(j), virunt) junk = writef(tab(n), PAGE_SIZE, virunt) if (reset == YES) junk = note(virend, virunt) } phyind(j) = 0 # page now non-resident return end enddef #-h- pdirty 287 asc 25-mar-82 17:19:15 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine pdirty(i) integer i, n include cvirt include clru phyind(i) = -abs(phyind(i)) # mark page as dirty for (n=1; n <= RESIDENT_PAGES; n=n+1) if (pfnp(n) == i) break call mruset(n) # put in MRU position return end enddef #-h- virint 629 asc 26-mar-82 10:57:07 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) # virint - initialize virtual array for integers subroutine virint integer i, j include cvirt include cvfile include clru for ([i=1; j=1]; i <= PF_SIZE; [i=i+1; j=j+INTS_PER_PAGE]) { virind(i) = j # starting virtual index call ptrcpy(NULLPOINTER,dskadr(i)) # initially not in paging file if (i <= RESIDENT_PAGES) phyind(i) = j else phyind(i) = 0 } virunt = ERR for (i=1; i <= RESIDENT_PAGES; i=i+1) { lrup(i) = i - 1 mrup(i) = i + 1 pfnp(i) = i } lrup(1) = RESIDENT_PAGES mrup(RESIDENT_PAGES) = 1 return end enddef #-h- virphy 271 asc 25-mar-82 17:19:17 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) integer function virphy(virtnd, physnd) integer virtnd, physnd, i include cvirt i = ((virtnd - 1) / INTS_PER_PAGE) + 1 if (phyind(i) == 0) call mapphy(i) physnd = abs(phyind(i)) + (virtnd - virind(i)) return(i) end enddef #-h- virfin 219 asc 25-mar-82 17:34:00 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) subroutine virfin include cvfile integer junk integer remove if (virunt != ERR) # paging was active { call close(virunt) junk = remove(vpfile) } return end enddef #-h- qsort 1034 asc 26-mar-82 18:28:38 v1.1 (sw-tools v1.1) ifdef(USE_QUICKSORT) subroutine dosort(nnn) integer nnn integer s, left(20), right(20), l, r, i, j, p, itemp, ki, kj integer cmpint include "conds" s = 1 left(1) = 1 right(1) = nnn repeat { l = left(s) r = right(s) s = s - 1 repeat { i = l j = r # p = (l + r) / 2 # pivot index p = r repeat { while (cmpint(i, p) < 0) i = i + 1 while (cmpint(p, j) < 0) j = j - 1 if (i <= j) { itemp = get_tab(i) set_tab(i, get_tab(j)) set_tab(j, itemp) ki = HIGHEND - i kj = HIGHEND - j itemp = get_tab(ki) set_tab(ki, get_tab(kj)) set_tab(kj, itemp) i = i + 1 j = j - 1 } } until (i > j) if (j - l < r - i) { if (i < r) { s = s + 1 left(s) = i right(s) = r } r = j } else { if (l < j) { s = s + 1 left(s) = l right(s) = j } l = i } } until (l >= r) } until (s == 0) return end enddef #-h- cmpint 376 asc 26-mar-82 18:15:02 v1.1 (sw-tools v1.1) integer function cmpint(i, j) integer i, j integer ki, kj, vi, vj, status include "conds" ki = HIGHEND - i kj = HIGHEND - j vi = get_tab(ki) vj = get_tab(kj) if (vi < vj) status = -1 else if (vi > vj) status = 1 else { vi = get_tab(i) vj = get_tab(j) if (vi < vj) status = -1 else if (vi > vj) status = 1 else status = 0 } return(status) end #-h- shsort 806 asc 26-mar-82 18:28:39 v1.1 (sw-tools v1.1) ifnotdef(USE_QUICKSORT) subroutine dosort(nnn) integer nnn integer gap, j, i, ki, ipg, kipg, itemp integer cmpint include "conds" # STEP 2. Sort. # Ascending order, hash as primary key and serial as secondary. for (gap = 1; gap <= nnn; gap = gap+gap) ; # next power of 2 after nnn for (gap = (gap-1)/2; gap > 0; gap = gap/2) for (j = 1; j <= nnn-gap; j = j + 1) for (i = j; i > 0; i = i-gap) { ipg = i + gap if (cmpint(i, ipg) <= 0) break ki = HIGHEND - i kipg = HIGHEND - ipg itemp = get_tab(ki) set_tab(ki, get_tab(kipg)) set_tab(kipg, itemp) itemp = get_tab(i) set_tab(i, get_tab(ipg)) set_tab(ipg, itemp) } return end enddef #-h- lineget.x 1435 asc 26-mar-82 11:46:05 v1.1 (sw-tools v1.1) define(GET,) # Ancestry has been established. Develop the particular version. # Returns a line-at-a-time to caller. integer function lineget (inbuf, passthru) character inbuf(MAXLINE) integer passthru # send text to new-history file include "defns" integer bmatch, ctoi2, getlin integer currnest, i save currnest repeat { i = getlin(inbuf, fdhis) if (i == EOF) call error("Unexpected EOF on history-data scan.") if (bmatch(inbuf, 1, ENDSEG) != 0) { if (ctoi2(inbuf, KEYSIZ) == 1) { # done GET if (passthru == YES) GET call putlin(inbuf, fdscr) # last line break } if (insert == OFF) if (ctoi2(inbuf, KEYSIZ) == currnest) insert = ON } else if (bmatch(inbuf, 1, INSERT) != 0) if (ancestry(ctoi2(inbuf, KEYSIZ)) == YES) insert = ON else { # not in one of its ancestors, # skip to matching ENDSEG line if (insert == ON) { currnest = ctoi2(inbuf, KEYSIZ) insert = OFF } } else if (bmatch(inbuf, 1, DELETE) != 0) { if (ancestry(ctoi2(inbuf, KEYSIZ)) == YES) # skip to matching ENDSEG line if (insert == ON) { currnest = ctoi2(inbuf, KEYSIZ) insert = OFF } } else if (insert == ON) return (i) # text returned in "inbuf" GET # pass all other lines thru to the output file GET if (passthru == YES) { GET if (flag == INHIST) { GET call puttag(ENDSEG) GET flag = MATCHING GET } GET call putlin(inbuf, fdscr) GET } } return (EOF) # at EOF end #-h- delta.fmt 2423 asc 26-mar-82 11:46:06 v1.1 (sw-tools v1.1) .so ~bin/manhdr .hd Delta (1) 14-Sep-81 make an TCS delta .sy delta revision history [newhistory] .ds Delta integrates the current "revision" of a file into its TCS "history" file or into a "newhistory" file. Differences between this version and the preceeding version are computed and the TCS file will be able to reproduce either version (or earlier versions) by means of the GET command. The user is requested to provide a reason-for-change when prompted by "History?". Multiple lines may be entered to describe changes and terminated by '.' on a line by itself. .fl A scratch file is created during processing, then copied onto the "history". If a "newhistory" is given, the result will be moved there instead. .sa admin, get .di .in +10 .ti -10 usage: delta revision history [newhistory] .br Correct calling format is provided when called without arguments. .ti -10 TCS Version Number corrupted. .ti -10 Unexpected EOF on history-info scan. .ti -10 Unexpected EOF on history-data scan. .br The TCS code seems to be present but garbled. Refer to a guru. .ti -10 Sudden death in input .br An end-of-file was detected while requesting the "reason for change". .ti -10 Revision file is empty .br Perhaps an incorrect filename was given. .ti -10 History file is empty .br The first formal version is entered by means of the ADMIN command. .ti -10 Files are too big to handle .br The DIFF algorithm table-size has been exceeded. Current version supports files of approximately 15000-lines. .ti -10 Cannot locate TCS history file. .br Unable to read filename specified as the history file. .ti -10 Temp file error: (filename) .br The tempoary file created during processing disappeared unexpectedly. .in -10 .au An Algorithm for Differential File Comparison by J.W.Hunt and M.D.McIlroy (BTL Computing Science Technical Report #41). Original code by Wil Baden; converted from MORTRAN by Dave Murray. Modifications and conversion to BTL-SCCS style by Neil Groundwater at ADI. The Source Code Control System was introduced by Marc J. Rochkind in the December, 1975, IEEE Transactions on Software Engineering. .bu File permissions are NOT manipluated to restrict users from disturbing the maintained files. Version numbering ranges from 1.1 to 1.N where N is a very large number. Provision to increment the "primary" number upon demand is scheduled. Branching capabilities are scheduled to be implemented. .br #-h- ctab 56 asc 26-mar-82 11:46:07 v1.1 (sw-tools v1.1) common / ctab / tab(PHYMEM) integer tab # table array #-h- clru 252 asc 26-mar-82 11:46:07 v1.1 (sw-tools v1.1) common / clru / lrup(RESIDENT_PAGES), mrup(RESIDENT_PAGES), pfnp(RESIDENT_PAGES) integer lrup # index to less recently used pages integer mrup # index to more recently used pages integer pfnp # index to page frame entry mapped in this physical page #-h- cvfile 210 asc 26-mar-82 11:46:08 v1.1 (sw-tools v1.1) common / cvfile / virunt, virend, vpfile(FILENAMESIZE) filedes virunt # ratfor unit to page file; init = ERR linepointer virend # address of end-of-file for paging file character vpfile # name of paging file #-h- cvirt 279 asc 26-mar-82 11:46:08 v1.1 (sw-tools v1.1) common / cvirt / virind(PF_SIZE), phyind(PF_SIZE), dskadr(PF_SIZE) integer virind # starting virtual index of this page integer phyind # starting physical index of this page # if == 0, not resident; if < 0, page is dirty linepointer dskadr # address of page in paging file #-h- conds 124 asc 26-mar-82 18:29:34 v1.1 (sw-tools v1.1) ifdef(DO_PAGING) integer gettab # function integer istab1, istab2 # temporaries for macro elsedef include ctab enddef %%E 1