# this is the sort for subsystem command "link" subroutine sort (ifd, outfd) integer ifd, outfd define(MERGEORDER,6) define(MERGETEXT,900) define(NAMESIZE,30) define(MAXTEXT,16384) define(MAXPTR,2048) define(LOGPTR,20) character linbuf (MAXTEXT), name (NAMESIZE) integer gtext, makfil, open integer infil (MERGEORDER), linptr (MAXPTR), nlines integer high, lim, low, t high = 0 repeat { # initial formation of runs t = gtext (linptr, nlines, linbuf, ifd) call quick (linptr, nlines, linbuf) high = high + 1 outfd = makfil (high) call ptext (linptr, nlines, linbuf, outfd) call close (outfd) } until (t == EOF) for (low = 1; low < high; low = low + MERGEORDER) { # merge lim = min0 (low + MERGEORDER - 1, high) call gopen (infil, low, lim) high = high + 1 outfd = makfil (high) call merge (infil, lim - low + 1, outfd) call close (outfd) call gremov (infil, low, lim) } call gname (high, name) # final cleanup outfd = open (name, READ) return end # gname --- make unique name for file id n subroutine gname (n, name) character name (NAMESIZE) integer itoc, scopy integer i, junk, n i = 1 + scopy ("=temp=/xt=pid="s, 1, name, 1) junk = itoc (n, name (i), NAMESIZE - i) return end # makfil --- make new file for number n integer function makfil (n) character name (NAMESIZE) integer create integer n call gname (n, name) makfil = create (name, READWRITE) if (makfil == ERR) call cant (name) return end # gopen --- open group of files low ... lim subroutine gopen (infil, low, lim) character name (NAMESIZE) integer i, infil (MERGEORDER), lim, low integer open for (i = 1; i <= lim-low+1; i = i + 1) { call gname (low+i-1, name) infil (i) = open (name, READ) if (infil (i) == ERR) call cant (name) } return end # gremov --- remove group of files low ... lim subroutine gremov (infil, low, lim) character name (NAMESIZE) integer i, infil (MERGEORDER), lim, low for (i = 1; i <= lim - low + 1; i = i + 1) { call close (infil (i)) call gname (low + i - 1, name) call remove (name) } return end # merge --- merge infil (1) ... infil (nfiles) onto outfil subroutine merge (infil, nfiles, outfil) character linbuf (MERGETEXT) integer getlin integer i, inf, lbp, lp1, nf, nfiles, outfil integer infil (MERGEORDER), linptr (MERGEORDER) lbp = 1 nf = 0 for (i = 1; i <= nfiles; i = i + 1) # get one line from each file if (getlin (linbuf (lbp), infil (i)) ~= EOF) { nf = nf + 1 linptr (nf) = lbp lbp = lbp + MAXLINE # room for largest line } call quick (linptr, nf, linbuf) # make initial heap while (nf > 0) { lp1 = linptr (1) call putlin (linbuf (lp1), outfil) inf = lp1 / MAXLINE + 1 # compute file index if (getlin (linbuf (lp1), infil (inf)) == EOF) { linptr (1) = linptr (nf) nf = nf - 1 } call reheap (linptr, nf, linbuf) } return end # reheap --- propagate linbuf (linptr (1)) to proper place in heap subroutine reheap (linptr, nf, linbuf) character linbuf (MAXTEXT) integer compare integer i, j, nf, linptr (nf) for (i = 1; 2 * i <= nf; i = j) { j = 2 * i if (j < nf) # find smaller child if (compare (linptr (j), linptr (j+1), linbuf) > 0) j = j + 1 if (compare (linptr (i), linptr (j), linbuf) <= 0) break # proper position found call exchan (linptr (i), linptr (j), linbuf) # percolate } return end # gtext --- get text lines into linbuf integer function gtext (linptr, nlines, linbuf, infile) character linbuf (MAXTEXT) integer getlin integer infile, lbp, len, linptr (MAXPTR), nlines nlines = 0 lbp = 1 repeat { len = getlin (linbuf (lbp), infile) if (len == EOF) break nlines = nlines + 1 linptr (nlines) = lbp lbp = lbp + len + 1 # "1" = room for EOS } until (lbp >= MAXTEXT - MAXLINE | nlines >= MAXPTR) gtext = len return end # ptext --- output text lines from linbuf subroutine ptext (linptr, nlines, linbuf, outfil) character linbuf (MAXTEXT) integer i, j, linptr (MAXPTR), nlines, outfil for (i = 1; i <= nlines; i = i + 1) { j = linptr (i) call putlin (linbuf (j), outfil) } return end # compare --- compare linbuf (lp1) with linbuf (lp2) integer function compare (lp1, lp2, linbuf) character linbuf (ARB) integer i, j, lp1, lp2 i = lp1 j = lp2 while (linbuf (i) == linbuf (j)) { if (linbuf (i) == EOS) { compare = 0 return } i = i + 1 j = j + 1 } if (linbuf (i) < linbuf (j)) compare = -1 else compare = 1 return end # exchan --- exchange linbuf (lp1) with linbuf (lp2) subroutine exchan (lp1, lp2, linbuf) character linbuf (ARB) integer k, lp1, lp2 k = lp1 lp1 = lp2 lp2 = k return end # quick --- quicksort for character lines subroutine quick (linptr, nlines, linbuf) character linbuf (ARB) integer compare integer i, j, linptr (ARB), lv (LOGPTR), nlines, p, pivlin, uv (LOGPTR) lv (1) = 1 uv (1) = nlines p = 1 while (p > 0) if (lv (p) >= uv (p)) # only one element in this subset p = p - 1 # pop stack else { i = lv (p) - 1 j = uv (p) pivlin = linptr (j) # pivot line while (i < j) { for (i=i+1; compare (linptr (i), pivlin, linbuf) < 0; i=i+1) ; for (j = j - 1; j > i; j = j - 1) if (compare (linptr (j), pivlin, linbuf) <= 0) break if (i < j) # out of order pair call exchan (linptr (i), linptr (j), linbuf) } j = uv (p) # move pivot to position i call exchan (linptr (i), linptr (j), linbuf) if (i-lv (p) < uv (p)-i) { # stack so shorter done first lv (p+1) = lv (p) uv (p+1) = i - 1 lv (p) = i + 1 } else { lv (p+1) = i + 1 uv (p+1) = uv (p) uv (p) = i - 1 } p = p + 1 # push onto stack } return end