home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: press.icn
- #
- # Subject: Program to archive files
- #
- # Author: Robert J. Alexander
- #
- # Date: November 14, 1991
- #
- ###########################################################################
- #
- # Besides being a useful file archiving utility, this program can be
- # used to experiment with the LZW compression process, as it contains
- # extensive tracing facilities that illustrate the process in detail.
- #
- # Compression can be turned off if faster archiving is desired.
- #
- # The LZW compression procedures in this program are general purpose
- # and suitable for reuse in other programs.
- #
- ############################################################################
- #
- # Instructions for use are summarized in "help" procedures that follow.
- #
- ############################################################################
- #
- # Links: options, colmize, wildcard
- #
- ############################################################################
-
- link options, colmize, wildcard
-
- procedure Usage(s)
- /s := ""
- stop("\nUsage:_
- \n Compress: press -c <archive file> [<options>] [<file to compress>...]_
- \n Archive: press -a <archive file> [<options>] [<file to archive>...]_
- \n Extract: press -x <archive file> [<options>] [<file to extract>...]_
- \n Print: press -p <archive file> [<options>] [<file to print>...]_
- \n List: press -l <archive file> [<options>] [<file to list>...]_
- \n Delete: press -d <archive file> [<options>] <file to delete>..._
- \n_
- \n Help: press (prints this message)_
- \n More help:press -h (prints more details)_
- \n_
- \n -c perform compression into <archive file>_
- \n -a add file(s) to <archive file> in uncompressed format_
- \n -x extract (& decompress) file(s) from <archive file>_
- \n -p extract (& decompress) from <archive file> to standard output_
- \n -l list file names in <archive file>_
- \n -d delete file(s) from <archive file>_
- \n (produces new file -- old file saved with \".bak\" suffix)_
- \n_
- \n Options:_
- \n -q work quietly_
- \n -t text file(s) (retrieves with correct line end format)_
- \n -n process all files in archive *except* specified files_
- \n_
- \n LZW Experimentor Options:_
- \n -T produce detailed compression trace info (to standard error file)_
- \n -S maximum compression string table size_
- \n (for -c only -- default = 1024)_
- \n"
- ,s)
- end
-
- procedure MoreHelp()
- return "\n _
- The archive (-a) option means to add the file without compression._
- \n_
- \n If no files are specified to extract, print, or list, then all files_
- \n in the archive are used._
- \n_
- \n UNIX-style filename wildcard conventions can be used to express_
- \n the archived file names for extract, print, list, and delete_
- \n operations. Be sure to quote names containing wildcard characters_
- \n so that they aren't expanded by the shell (if applicable)._
- \n_
- \n If a <file to compress> or <file to archive> is \"-\", or if no files_
- \n are specified, standard input is archived._
- \n_
- \n If <archive file> for extract, print, or list is \"-\", standard input_
- \n is the archive file._
- \n_
- \n If <archive file> for compress or archive is \"-\", archive is written_
- \n to standard output._
- \n_
- \n New files archived to an existing archive file are always appended,_
- \n deleting any previously archived version of the same file name._
- \n_
- \n Archive files can be simply concatenated to create their union._
- \n However, if the same file exists in both archives, only the first_
- \n in the resulting file will be able to be accessed._
- \n_
- \n If a \"compressed\" file turns out to be longer than the uncompressed_
- \n file (rare but possible, usually for very short files), the file will_
- \n automatically be archived in uncompressed format._
- \n_
- \n A default file name suffix of \".prx\" is assumed for <archive file>_
- \n names that are specified without a suffix._
- \n_
- \n_
- \n LZW \"internals\" option:_
- \n_
- \n If the specified maximum table size is positive, the string table is_
- \n discarded when the maximum size is reached and rebuilt (usually the_
- \n better choice). If negative, the original table is not discarded,_
- \n which might produce better results in some circumstances. This_
- \n option was provided primarily for experimentors._
- \n"
- end
-
- #
- # Global variables.
- #
- # Note: additional globals that contain option values are defined near
- # Options(), below.
- #
- global inchars,outchars,tinchars,toutchars,lzw_recycles,
- lzw_stringTable,rf,wf,magic,rline,wline
-
- #
- # Main procedure.
- #
- procedure main(arg)
- local arcfile
- #
- # Initialize.
- #
- Options(arg)
- inchars := outchars := tinchars := toutchars := lzw_recycles := 0
- magic := "\^p\^r\^e\^s\^s\^i\^c\^n"
- #
- # Do requested operation.
- #
- arcfile :=
- DefaultSuffix(\(compr | archive | extract | print | lister | deleter),
- "prx") | Usage()
- if \(compr | archive) then Archive(arcfile,arg)
- else if \(extract | print) then Extract(arcfile,arg)
- else if \lister then List(arcfile,arg)
- else if \deleter then Delete(arcfile,arg)
- return
- end
-
-
- #
- # Option global variables.
- #
- global lzw_trace,maxTableSpecified,maxTableSize,print,quiet,tmode,WildMatch
- global extract,compr,archive,lister,deleter
-
- #
- # Options() -- Handle command line options.
- #
- procedure Options(arg)
- local opt,n,x
- opt := options(arg,"hc:a:x:p:l:d:qtTS+n")
- if \opt["h"] then Usage(MoreHelp())
- extract := opt["x"]
- print := opt["p"]
- compr := opt["c"]
- archive := opt["a"]
- lister := opt["l"]
- deleter := opt["d"]
- quiet := opt["q"]
- tmode := if \opt["t"] then "t" else "u"
- WildMatch := if \opt["n"] then not_wild_match else whole_wild_match
- lzw_trace := opt["T"]
- maxTableSpecified := opt["S"]
- maxTableSize := \maxTableSpecified | 1024 # 10 bits default
- n := 0
- every x := compr | archive | extract | print | lister | deleter do
- if \x then n +:= 1
- if n ~= 1 then Usage()
- return
- end
-
-
- #
- # Archive() -- Do archiving.
- #
- procedure Archive(arcfile,arg)
- local fn,addr,realLen,maxT,length,addr2,deleteFiles,new_data_start
- #
- # Confirm options and open the archive file.
- #
- if *arg = 0 | WildMatch === not_wild_match then Usage()
- if ("" | "-") ~== arcfile then {
- if wf := open(arcfile,"ru") then {
- if not (reads(wf,*magic) == magic) then {
- stop("Invalid archive file ",arcfile)
- }
- close(wf)
- }
- wf := open(arcfile,"bu" | "wu") | stop("Can't open archive file ",arcfile)
- if tmode == "t" then rline := "\n"
- seek(wf,0)
- if where(wf) = 1 then writes(wf,magic)
- }
- else {
- wf := &output
- arcfile := "stdout"
- }
- new_data_start := where(wf)
- ## if /quiet then
- ## write(&errout,"New data starting at byte ",new_data_start," of ",arcfile)
- #
- # Loop to process files on command line.
- #
- if *arg = 0 then arg := ["-"]
- deleteFiles := []
- every fn := !arg do {
- if fn === arcfile then next
- if /quiet then
- writes(&errout,"File \"",fn,"\" -- ")
- rf := if fn ~== "-" then open(fn,tmode) | &null else &input
- if /rf then {
- if /quiet then
- write(&errout,"Can't open input file \"",fn,"\" -- skipped")
- next
- }
- put(deleteFiles,fn)
- WriteString(wf,Tail(fn))
- addr := where(rf)
- seek(rf,0)
- realLen := where(rf) - 1
- WriteInteger(wf,realLen)
- seek(rf,addr)
- if /quiet then
- writes(&errout,"Length: ",realLen)
- addr := where(wf)
- WriteInteger(wf,0)
- writes(wf,"\1") # write a compression version string
- if \compr then {
- WriteInteger(wf,maxTableSize)
- maxT := Compress(R,W,maxTableSize)
- length := outchars + 4
- if /quiet then
- writes(&errout," Compressed: ",length," ",
- Percent(realLen - outchars,realLen))
- }
- #
- # If compressed file is larger than original, just copy the original.
- #
- if \archive | length > realLen then {
- if /quiet then
- writes(&errout," -- Archived uncompressed")
- seek(wf,addr + 4)
- writes(wf,"\0") # write a zero version string for uncompressed
- seek(rf,1)
- CopyFile(rf,wf)
- inchars := outchars := length := realLen
- maxT := 0
- lzw_stringTable := ""
- }
- if /quiet then
- write(&errout)
- close(rf)
- addr2 := where(wf)
- seek(wf,addr)
- WriteInteger(wf,length)
- seek(wf,addr2)
- if /quiet then
- Stats(maxT)
- }
- close(wf)
- if /quiet then
- if *arg > 1 then FinalStats()
- Delete(arcfile,deleteFiles,new_data_start)
- return
- end
-
-
- #
- # Extract() -- Extract a file from the archive.
- #
- procedure Extract(arcfile,arg)
- local fileSet,wfn,realLen,cmprLen,maxT,version,theArg
- if \maxTableSpecified then Usage()
- rf := OpenReadArchive(arcfile)
- arcfile := rf[2]
- rf := rf[1]
- if *arg > 0 then fileSet := set(arg)
- #
- # Process input file.
- #
- while wfn := ReadString(rf) do {
- (realLen := ReadInteger(rf) &
- cmprLen := ReadInteger(rf) &
- version := ord(reads(rf))) |
- stop("Bad format in compressed file")
- if /quiet then
- writes(&errout,"File \"",wfn,"\" -- length: ",realLen,
- " compressed: ",cmprLen," bytes -- ")
- if /fileSet | WildMatch(theArg := !arg,wfn) then {
- delete(\fileSet,theArg)
- if not version = (0 | 1) then {
- if /quiet then
- write(&errout,"can't handle this compression type (",version,
- ") -- skipped")
- seek(rf,where(rf) + cmprLen)
- }
- else {
- if /quiet then
- write(&errout,"extracted")
- if /print then {
- wf := open(wfn,"w" || tmode) | &null
- if /wf then {
- if /quiet then
- write(&errout,"Can't open output file \"",wfn,
- "\" -- quitting")
- exit(1)
- }
- }
- else wf := &output
- if version = 1 then {
- maxT := ReadInteger(rf) |
- stop("Error in archive file format: ","table size missing")
- Decompress(R,W,maxT)
- }
- else {
- maxT := 0
- CopyFile(rf,wf,cmprLen)
- outchars := inchars := realLen
- }
- close(&output ~=== wf)
- if /quiet then
- Stats(maxT)
- }
- }
- else {
- if /quiet then
- write(&errout,"skipped")
- seek(rf,where(rf) + cmprLen)
- }
- }
- close(rf)
- FilesNotFound(fileSet)
- return
- end
-
-
- #
- # List() -- Skip through the archive, extracting info about files,
- # then list in columns.
- #
- procedure List(arcfile,arg)
- local fileSet,flist,wfn,realLen,cmprLen,version,theArg
- if \maxTableSpecified then Usage()
- rf := OpenReadArchive(arcfile)
- arcfile := rf[2]
- rf := rf[1]
- write(&errout,"Archive file ",arcfile,":")
- if *arg > 0 then fileSet := set(arg)
- #
- # Process input file.
- #
- flist := []
- while wfn := ReadString(rf) do {
- (realLen := ReadInteger(rf) &
- cmprLen := ReadInteger(rf) &
- version := ord(reads(rf))) |
- stop("Bad format in compressed file")
- if /fileSet | WildMatch(theArg := !arg,wfn) then {
- delete(\fileSet,theArg)
- put(flist,"\"" || wfn || "\" " || realLen || "->" || cmprLen)
- tinchars +:= realLen
- toutchars +:= cmprLen
- }
- seek(rf,where(rf) + cmprLen)
- }
- close(rf)
- every write(&errout,colmize(sort(flist)))
- FilesNotFound(fileSet)
- FinalStats()
- return
- end
-
-
- #
- # Delete() -- Delete a file from the archive.
- #
- procedure Delete(arcfile,arg,new_data_start)
- local workfn,workf,fileSet,wfn,realLen,cmprLen,bakfn,deletedFiles,
- head,version,hdrLen,theArg
- if *arg = 0 | (\deleter & \maxTableSpecified) then Usage()
- rf := OpenReadArchive(arcfile)
- arcfile := rf[2]
- rf := rf[1]
- workfn := Root(arcfile) || ".wrk"
- workf := open(workfn,"wu") | stop("Can't open work file ",workfn)
- writes(workf,magic)
- fileSet := set(arg)
- #
- # Process input file.
- #
- deletedFiles := 0
- head := if \deleter then "File" else "Replaced file"
- while not (\new_data_start <= where(rf)) & wfn := ReadString(rf) do {
- (realLen := ReadInteger(rf) &
- cmprLen := ReadInteger(rf) &
- version := ord(reads(rf))) |
- stop("Bad format in compressed file")
- if /quiet then
- writes(&errout,head," \"",wfn,"\" -- length: ",realLen,
- " compressed: ",cmprLen," bytes -- ")
- if WildMatch(theArg := !arg,wfn) then {
- deletedFiles +:= 1
- delete(fileSet,theArg)
- if /quiet then
- write(&errout,"deleted")
- seek(rf,where(rf) + cmprLen)
- }
- else {
- if /quiet then
- write(&errout,"kept")
- hdrLen := *wfn + 10
- seek(rf,where(rf) - hdrLen)
- CopyFile(rf,workf,cmprLen + hdrLen)
- }
- }
- if deletedFiles > 0 then {
- CopyFile(rf,workf)
- every close(workf | rf)
- if (rf ~=== &input) then {
- bakfn := Root(arcfile) || ".bak"
- remove(bakfn)
- rename(arcfile,bakfn) | stop("Couldn't rename ",arcfile," to ",bakfn)
- }
- rename(workfn,arcfile) | stop("Couldn't rename ",workfn," to ",arcfile)
- }
- else {
- every close(workf | rf)
- remove(workfn)
- }
- if \deleter then FilesNotFound(fileSet)
- return
- end
-
-
- #
- # OpenReadArchive() -- Open an archive for reading.
- #
- procedure OpenReadArchive(arcfile)
- local rf
- rf := if ("" | "-") ~== arcfile then
- open(arcfile,"ru") | stop("Can't open archive file ",arcfile)
- else {
- arcfile := "stdin"
- &input
- }
- if reads(rf,*magic) ~== magic then stop("Invalid archive file ",arcfile)
- if tmode == "t" then wline := "\x0a"
- return [rf,arcfile]
- end
-
-
- #
- # FilesNotFound() -- List the files remaining in "fileSet".
- #
- procedure FilesNotFound(fileSet)
- return if *\fileSet > 0 then {
- write(&errout,"\nFiles not found:")
- every write(&errout," ",colmize(sort(fileSet),78))
- &null
- }
- end
-
-
- #
- # Stats() -- Print stats after a file.
- #
- procedure Stats(maxTableSize)
- #
- # Write statistics
- #
- if \lzw_trace then write(&errout,
- " table size = ",*lzw_stringTable,"/",maxTableSize,
- " (recycles: ",lzw_recycles,")")
- tinchars +:= inchars
- toutchars +:= outchars
- inchars := outchars := lzw_recycles := 0
- return
- end
-
-
- #
- # FinalStats() -- Print final stats.
- #
- procedure FinalStats()
- #
- # Write final statistics
- #
- write(&errout,"\nTotals: ",
- "\n input: ",tinchars,
- "\n output: ",toutchars,
- "\n compression: ",Percent(tinchars - toutchars,tinchars) | "",
- "\n")
- return
- end
-
-
- #
- # WriteInteger() -- Write a 4-byte binary integer to "f".
- #
- procedure WriteInteger(f,i)
- local s
- s := ""
- every 1 to 4 do {
- s := char(i % 256) || s
- i /:= 256
- }
- return writes(f,s)
- end
-
-
- #
- # ReadInteger() -- Read a 4-byte binary integer from "f".
- #
- procedure ReadInteger(f)
- local s,v
- s := reads(f,4) | fail
- if *s < 4 then
- stop("Error in archive file format: ","bad integer")
- v := 0
- s ? while v := v * 256 + ord(move(1))
- return v
- end
-
-
- #
- # WriteString() -- Write a string preceded by a length byte to "f".
- #
- procedure WriteString(f,s)
- return writes(f,char(*s),s)
- end
-
-
- #
- # ReadString() -- Read a string preceded by a length byte from "f".
- #
- procedure ReadString(f)
- local len,s
- len := ord(reads(f)) | fail
- s := reads(f,len)
- if *s < len then
- stop("Error in archive file format: ","bad string")
- return s
- end
-
-
- #
- # CopyFile() -- Copy a file.
- #
- procedure CopyFile(rf,wf,len)
- local s
- if /len then {
- while writes(wf,s := reads(rf,1000))
- }
- else {
- while len > 1000 & writes(wf,s := reads(rf,1000)) do len -:= *s
- writes(wf,s := reads(rf,len)) & len -:= *s
- }
- return len
- end
-
-
- #
- # Percent() -- Format a rational number "n"/"d" as a percentage.
- #
- procedure Percent(n,d)
- local sign,whole,fraction
- n / (0.0 ~= d) ? {
- sign := ="-" | ""
- whole := tab(find("."))
- move(1)
- fraction := tab(0)
- }
- return (\sign || ("0" ~== whole | "") ||
- (if whole == "0" then integer else 1)(left(fraction,2,"0")) | "--") ||
- "%"
- end
-
-
- #
- # R() -- Read-a-character procedure.
- #
- procedure R()
- local c
-
- c := reads(rf) | fail
- inchars +:= 1
- if c === rline then c := "\x0a"
- return c
- end
-
-
- #
- # W() -- Write-characters procedure.
- #
- procedure W(s)
- local i
-
- every i := find(\wline,s) do s[i] := "\n"
- outchars +:= *s
- return writes(wf,s)
- end
-
-
- #
- # Tail() -- Return the file name portion (minus the path) of a
- # qualified file name.
- #
- procedure Tail(fn)
- local i
- i := 0
- every i := upto('/\\:',fn)
- return .fn[i + 1:0]
- end
-
-
- #
- # Root() -- Return the root portion (minus the suffix) of a file name.
- #
- procedure Root(fn)
- local i
- i := 0
- every i := find(".",fn)
- return .fn[1:i]
- end
-
-
- procedure DefaultSuffix(fn,suf)
- local i
- return fn || "." || suf
- end
-
-
- ############################################################################
- #
- # Compress() -- LZW compression
- #
- # Arguments:
- #
- # inproc a procedure that returns a single character from
- # the input stream.
- #
- # outproc a procedure that writes a single character (its
- # argument) to the output stream.
- #
- # maxTableSize the maximum size to which the string table
- # is allowed to grow before something is done about it.
- # If the size is positive, the table is discarded and
- # a new one started. If negative, it is retained, but
- # no new entries are added.
- #
-
- procedure Compress(inproc,outproc,maxTableSize)
- local EOF,c,charTable,junk1,junk2,outcode,s,t,tossTable,x
- #
- # Initialize.
- #
- /maxTableSize := 1024 # default 10 "bits"
- tossTable := maxTableSize
- /lzw_recycles := 0
- if maxTableSize < 0 then maxTableSize := -maxTableSize
- charTable := table()
- every c := !&cset do charTable[c] := ord(c)
- EOF := charTable[*charTable] := *charTable # reserve code=256 for EOF
- lzw_stringTable := copy(charTable)
- #
- # Compress the input stream.
- #
- s := inproc() | return maxTableSize
- if \lzw_trace then {
- write(&errout,"\nInput string\tOutput code\tNew table entry")
- writes(&errout,"\"",image(s)[2:-1])
- }
- while c := inproc() do {
- if \lzw_trace then
- writes(&errout,image(c)[2:-1])
- if \lzw_stringTable[t := s || c] then s := t
- else {
- Compress_output(outproc,junk2 := lzw_stringTable[s],
- junk1 := *lzw_stringTable)
- if *lzw_stringTable < maxTableSize then
- lzw_stringTable[t] := *lzw_stringTable
- else if tossTable >= 0 then {
- lzw_stringTable := copy(charTable)
- lzw_recycles +:= 1
- }
- if \lzw_trace then
- writes(&errout,"\"\t\t",
- image(char(*&cset > junk2) | junk2),
- "(",junk1,")\t\t",lzw_stringTable[t]," = ",image(t),"\n\"")
- s := c
- }
- }
- Compress_output(outproc,junk2 := lzw_stringTable[s],
- junk1 := *lzw_stringTable)
- if *lzw_stringTable < maxTableSize then
- {}
- else if tossTable >= 0 then {
- lzw_stringTable := copy(charTable)
- lzw_recycles +:= 1
- }
- if \lzw_trace then
- writes(&errout,"\"\t\t",
- image(char(*&cset > junk2) | junk2),"(",junk1,")\n")
- Compress_output(outproc,EOF,*lzw_stringTable)
- if \lzw_trace then write(&errout,"\"\t\t",EOF)
- Compress_output(outproc)
- return maxTableSize
- end
-
-
- procedure Compress_output(outproc,code,stringTableSize)
- local outcode
- static max,bits,buffer,bufferbits,lastSize
- #
- # Initialize.
- #
- initial {
- lastSize := 1000000
- buffer := bufferbits := 0
- }
- #
- # If this is "close" call, flush buffer and reinitialize.
- #
- if /code then {
- outcode := &null
- if bufferbits > 0 then
- outproc(char(outcode := ishift(buffer,8 - bufferbits)))
- lastSize := 1000000
- buffer := bufferbits := 0
- return outcode
- }
- #
- # Expand output code size if necessary.
- #
- if stringTableSize < lastSize then {
- max := 1
- bits := 0
- }
- while stringTableSize > max do {
- max *:= 2
- bits +:= 1
- }
- lastSize := stringTableSize
- #
- # Merge new code into buffer.
- #
- buffer := ior(ishift(buffer,bits),code)
- bufferbits +:= bits
- #
- # Output bits.
- #
- while bufferbits >= 8 do {
- outproc(char(outcode := ishift(buffer,8 - bufferbits)))
- buffer := ixor(buffer,ishift(outcode,bufferbits - 8))
- bufferbits -:= 8
- }
- return outcode
- end
-
-
- ############################################################################
- #
- # Decompress() -- LZW decompression of compressed stream created
- # by Compress()
- #
- # Arguments:
- #
- # inproc a procedure that returns a single character from
- # the input stream.
- #
- # outproc a procedure that writes a single character (its
- # argument) to the output stream.
- #
-
- procedure Decompress(inproc,outproc,maxTableSize)
- local EOF,c,charSize,code,i,new_code,old_strg,
- strg,tossTable
- #
- # Initialize.
- #
- /maxTableSize := 1024 # default 10 "bits"
- tossTable := maxTableSize
- /lzw_recycles := 0
- if maxTableSize < 0 then maxTableSize := -maxTableSize
- maxTableSize -:= 1
- lzw_stringTable := list(*&cset)
- every i := 1 to *lzw_stringTable do lzw_stringTable[i] := char(i - 1)
- put(lzw_stringTable,EOF := *lzw_stringTable) # reserve code=256 for EOF
- charSize := *lzw_stringTable
- if \lzw_trace then
- write(&errout,"\nInput code\tOutput string\tNew table entry")
- #
- # Decompress the input stream.
- #
- while old_strg :=
- lzw_stringTable[Decompress_read_code(inproc,
- *lzw_stringTable,EOF) + 1] do {
- if \lzw_trace then
- write(&errout,image(old_strg),"(",*lzw_stringTable,")",
- "\t",image(old_strg))
- outproc(old_strg)
- c := old_strg[1]
- (while new_code := Decompress_read_code(inproc,
- *lzw_stringTable + 1,EOF) do {
- strg := lzw_stringTable[new_code + 1] | old_strg || c
- outproc(strg)
- c := strg[1]
- if \lzw_trace then
- write(&errout,image(char(*&cset > new_code) \ 1 | new_code),
- "(",*lzw_stringTable + 1,")","\t",
- image(strg),"\t\t",
- *lzw_stringTable," = ",image(old_strg || c))
- if *lzw_stringTable < maxTableSize then
- put(lzw_stringTable,old_strg || c)
- else if tossTable >= 0 then {
- lzw_stringTable := lzw_stringTable[1:charSize + 1]
- lzw_recycles +:= 1
- break
- }
- old_strg := strg
- }) | break # exit outer loop if this loop completed
- }
- Decompress_read_code()
- return maxTableSize
- end
-
-
- procedure Decompress_read_code(inproc,stringTableSize,EOF)
- local code
- static max,bits,buffer,bufferbits,lastSize
-
- #
- # Initialize.
- #
- initial {
- lastSize := 1000000
- buffer := bufferbits := 0
- }
- #
- # Reinitialize if called with no arguments.
- #
- if /inproc then {
- lastSize := 1000000
- buffer := bufferbits := 0
- return
- }
- #
- # Expand code size if necessary.
- #
- if stringTableSize < lastSize then {
- max := 1
- bits := 0
- }
- while stringTableSize > max do {
- max *:= 2
- bits +:= 1
- }
- #
- # Read in more data if necessary.
- #
- while bufferbits < bits do {
- buffer := ior(ishift(buffer,8),ord(inproc())) |
- stop("Premature end of file")
- bufferbits +:= 8
- }
- #
- # Extract code from buffer and return.
- #
- code := ishift(buffer,bits - bufferbits)
- buffer := ixor(buffer,ishift(code,bufferbits - bits))
- bufferbits -:= bits
- return EOF ~= code
- end
-
-
- procedure whole_wild_match(p,s)
- return wild_match(p,s) > *s
- end
-
-
- procedure not_wild_match(p,s)
- return not (wild_match(p,s) > *s)
- end
-
-