home *** CD-ROM | disk | FTP | other *** search
- ############################################################################
- #
- # File: outbits.icn
- #
- # Subject: Procedure to write variable-length characters
- #
- # Author: Richard L. Goerwitz
- #
- # Date: November 3, 1991
- #
- ###########################################################################
- #
- # Version: 1.5
- #
- ###########################################################################
- #
- # In any number of instances (e.g. when outputting variable-length
- # characters or fixed-length encoded strings), the programmer must
- # fit variable and/or non-byte-sized blocks into standard 8-bit
- # bytes. Outbits() performs this task.
- #
- # Pass to outbits(i, len) an integer i, and a length parameter (len),
- # and outbits will suspend byte-sized chunks of i converted to
- # characters (most significant bits first) until there is not enough
- # left of i to fill up an 8-bit character. The remaining portion is
- # stored in a buffer until outbits() is called again, at which point
- # the buffer is combined with the new i and then output in the same
- # manner as before. The buffer is flushed by calling outbits() with
- # a null i argument. Note that len gives the number of bits there
- # are in i (or at least the number of bits you want preserved; those
- # that are discarded are the most significant ones).
- #
- # A trivial example of how outbits() might be used:
- #
- # outtext := open("some.file.name","w")
- # l := [1,2,3,4]
- # every writes(outtext, outbits(!l,3))
- # writes(outtext, outbits(&null,3)) # flush buffer
- #
- # List l may be reconstructed with inbits() (see inbits.icn):
- #
- # intext := open("some.file.name")
- # l := []
- # while put(l, inbits(intext, 3))
- #
- # Note that outbits() is a generator, while inbits() is not.
- #
- ############################################################################
- #
- # See also: inbits.icn
- #
- ############################################################################
-
- procedure outbits(i, len)
-
- local old_part, new_part, window, old_byte_mask
- static old_i, old_len, byte_length, byte_mask
- initial {
- old_i := old_len := 0
- byte_length := 8
- byte_mask := (2^byte_length)-1
- }
-
- old_byte_mask := (0 < 2^old_len - 1) | 0
- window := byte_length - old_len
- old_part := ishift(iand(old_i, old_byte_mask), window)
-
- # If we have a no-arg invocation, then flush buffer (old_i).
- if /i then {
- if old_len > 0 then {
- old_i := old_len := 0
- return char(old_part)
- } else {
- old_i := old_len := 0
- fail
- }
- } else {
- new_part := ishift(i, window-len)
- len -:= (len >= window) | {
- old_len +:= len
- old_i := ior(ishift(old_part, len-window), i)
- fail
- }
- # For debugging purposes.
- # write("old_byte_mask = ", old_byte_mask)
- # write("window = ", image(window))
- # write("old_part = ", image(old_part))
- # write("new_part = ", image(new_part))
- # write("outputting ", image(ior(old_part, new_part)))
- suspend char(ior(old_part, new_part))
- }
-
- until len < byte_length do {
- suspend char(iand(ishift(i, byte_length-len), byte_mask))
- len -:= byte_length
- }
-
- old_len := len
- old_i := i
- fail
-
- end
-