1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
############################################################################
#
# File: packunpk.icn
#
# Subject: Procedures to pack and unpack decimal strings
#
# Author: C. Tenaglia (modified by Richard L. Goerwitz)
#
# Date: May 2, 2001
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# Version: 1.2
#
############################################################################
#
# Integers written directly as strings occupy much more space
# than they need to. One easy way to shrink them a bit is to "pack"
# them, i.e. convert each decimal digit into a four-byte binary
# code, and pack these four-bit chunks into eight-bit characters,
# which can be written to a file.
#
# Interestingly, packing decimal strings in this manner lends
# itself to unpacking by treating each character as a base-10
# integer, and then converting it to base-16. Say we have an input
# string "99." Pack() would convert it to an internal representation
# of char(16*9 + 9), i.e. char(153). Unpack would treat this
# char(153) representation as a base-10 integer, and convert it to
# base 16 (i.e. 10r153 -> 16r99). The 99 is, of course, what we
# started with.
#
# Note that two unpack routines are provided here: The first, by
# Tanaglia, utilizes convert.icn from the IPL. The second, by
# Goerwitz, does not. They utilize very different methods, but both
# amount to basically the same thing. Goerwitz's routine returns an
# integer, though, and has no "width" argument.
#
############################################################################
#
# Links: convert
#
############################################################################
link convert
procedure pack(num,width)
local int, sign, prep, packed, word
int := integer(num) | fail
# There's really no need to store the sign if it's positive, UNLESS
# you are using this program to store packed decimal integers for
# access by other programs on certain mainframes that always store
# the sign.
# if int < 0 then sign := "=" else sign := "<"
if int < 0 then sign := "=" else sign := ""
prep := string(abs(int)) || sign
packed := ""
if (*prep % 2) ~= 0 then prep := "0" || prep
prep ? {
while word := move(2) do {
if pos(0)
then packed ||:= char(integer(word[1])*16 + ord(word[2])-48)
else packed ||:= char(integer(word[1])*16 + integer(word[2]))
}
}
/width := *packed
return right(packed, width, "\0")
end
procedure unpack(val,width)
# THIS PROCEDURE UNPACKS A VALUE INTO A STRING-INTEGER. USING THIS
# CODE SEGMENT REQUIRES LINKING WITH RADCON FROM THE IPL.
local tmp, number, tens, ones, sign
tmp := ""
sign := 1
every number := ord(!val) do
tmp ||:= right(map(radcon(number,10,16),&lcase,&ucase),2,"0")
if tmp[-1] == ("B" | "D") then {
sign := -1
# In this configuration, the sign field is only present if the
# integer is negative. If you have set up pack to register posi-
# tive values in the sign field, place the following line after
# the "if-then" expression.
tmp[-1] := ""
}
tmp *:= sign
/width := *string(tmp)
return right(string(tmp), width)
end
procedure unpack2(val)
# THIS PROCEDURE UNPACKS A VALUE INTO AN STRING-INTEGER.
# Note: Unpack2 assumes that pack is not recording positive
# sign values.
local unpacked, int
unpacked := ""
val ? {
while int := ord(move(1)) do {
unpacked ||:= string(iand(2r11110000,int) / 16)
if pos(0) then {
if iand(2r00001111,int) = 13 then {
unpacked := "-" || unpacked
break
}
}
unpacked ||:= string(iand(2r00001111,int))
}
}
return integer(unpacked)
end
|