summaryrefslogtreecommitdiff
path: root/ipl/packs/ibpag2/outbits.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/packs/ibpag2/outbits.icn')
-rw-r--r--ipl/packs/ibpag2/outbits.icn100
1 files changed, 100 insertions, 0 deletions
diff --git a/ipl/packs/ibpag2/outbits.icn b/ipl/packs/ibpag2/outbits.icn
new file mode 100644
index 0000000..cf3f597
--- /dev/null
+++ b/ipl/packs/ibpag2/outbits.icn
@@ -0,0 +1,100 @@
+############################################################################
+#
+# Name: outbits.icn
+#
+# Title: output variable-length characters in byte-size chunks
+#
+# Author: Richard L. Goerwitz
+#
+# 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.
+#
+############################################################################
+#
+# Links: none
+# 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