Skip to content

Commit 7625ea0

Browse files
committed
shell-bitwise: Add functions to operate with bits
This is a set of functions for manipulating individual bits in a number. In most cases, shell implementations work similarly if the number is small. However, if the value approaches the maximum int32 or int64, differences in behavior arise depending on the implementation. Signed-off-by: Alexey Gladkov <legion@kernel.org>
1 parent 213dad9 commit 7625ea0

File tree

7 files changed

+684
-0
lines changed

7 files changed

+684
-0
lines changed

mans/shell-bitwise.scd

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
shell-bitwise(3)
2+
3+
# NAME
4+
5+
is_bit_set, clear_bit, clear_bits, get_bit, set_bit, set_bit_value,
6+
set_bits, toggle_bit, toggle_bits - functions for obtaining, setting, and
7+
clearing individual bits in a number.
8+
9+
# SYNOPSIS
10+
11+
- is_bit_set number bit_pos
12+
- get_bit result_var number bit_pos
13+
- set_bit_value result_var number bit value
14+
- set_bit result_var number bit
15+
- clear_bit result_var number bit
16+
- toggle_bit result_var number bit
17+
18+
# DESCRIPTION
19+
20+
## is_bit_set
21+
22+
Checks whether the bit at position bit_pos is set.
23+
24+
Arguments:
25+
- number - integer value to extract the bit from
26+
- bit_pos - bit position (0 = least significant bit)
27+
28+
Result:
29+
The return 0 (true) if bit is set, 1 (false) if not.
30+
31+
## get_bit
32+
33+
Extract the value of the specified bit from a number.
34+
35+
Arguments:
36+
- result_var - name of the variable to store the result
37+
- number - integer value to extract the bit from
38+
- bit_pos - bit position (0 = least significant bit)
39+
40+
Result:
41+
The value of the specified bit (0 or 1) is stored in result_var.
42+
43+
## set_bit_value
44+
45+
Sets the specified bit in a number to a given value (0 or 1).
46+
47+
Arguments:
48+
- result_var - name of the variable to store the result
49+
- number - integer value to modify
50+
- bit - bit position (0 = least significant bit)
51+
- value - desired bit value (0 or 1)
52+
53+
Result:
54+
The modified number with the updated bit is stored in result_var.
55+
56+
## set_bit
57+
58+
Sets the specified bit to 1.
59+
60+
Arguments:
61+
- result_var - name of the variable to store the result
62+
- number - integer value to modify
63+
- bit - bit position (0 = least significant bit)
64+
65+
Result:
66+
The modified number with the bit set to 1 is stored in result_var.
67+
68+
## clear_bit
69+
70+
Clears (sets to 0) the specified bit.
71+
72+
Arguments:
73+
- result_var - name of the variable to store the result
74+
- number - integer value to modify
75+
- bit - bit position (0 = least significant bit)
76+
77+
Result:
78+
The modified number with the bit cleared is stored in result_var.
79+
80+
## toggle_bit
81+
82+
Toggles (inverts) the specified bit.
83+
84+
Arguments:
85+
- result_var - name of the variable to store the result
86+
- number - integer value to modify
87+
- bit - bit position (0 = least significant bit)
88+
89+
Result:
90+
The modified number with the bit inverted is stored in result_var.
91+
92+
## set_bits
93+
94+
Sets multiple bits to 1 in a number.
95+
96+
Arguments:
97+
- result_var - name of the variable to store the result
98+
- number - integer value to modify
99+
- bit1...N - list of bit positions to set
100+
101+
Result:
102+
The modified number with all specified bits set to 1 is stored in result_var.
103+
104+
## clear_bits
105+
106+
Clears (sets to 0) multiple bits in a number.
107+
108+
Arguments:
109+
- result_var - name of the variable to store the result
110+
- number - integer value to modify
111+
- bit1...N - list of bit positions to clear
112+
113+
Result:
114+
The modified number with all specified bits cleared is stored in result_var.
115+
116+
## toggle_bits
117+
118+
Toggles (inverts) multiple bits in a number.
119+
120+
Arguments:
121+
- result_var - name of the variable to store the result
122+
- number - integer value to modify
123+
- bit1...N - list of bit positions to toggle
124+
125+
Result:
126+
The modified number with all specified bits inverted is stored in result_var.
127+
128+
# AUTHOR
129+
Authors and contributors of the programs included in the *libshell* package are listed
130+
in the COPYING file.
131+
132+
# BUGS
133+
Report bugs to the authors.
134+

shell-bitwise

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#!/bin/sh -efu
2+
### This file is covered by the GNU General Public License,
3+
### which should be included with libshell as the file LICENSE.
4+
### All copyright information are listed in the COPYING.
5+
6+
if [ -z "${__included_shell_bits-}" ]; then
7+
__included_shell_bits=1
8+
9+
__shell_prepare_integer()
10+
{
11+
case "$2" in
12+
9223372036854775808|-9223372036854775808|0[xX]8000000000000000|-0[xX]8000000000000000)
13+
set -- "$1" "(0x7fffffffffffffff + 1)"
14+
;;
15+
0[xX][0-9A-Fa-f]*|[1-9]*|-[1-9]*)
16+
;;
17+
-0[xX]*)
18+
return 1
19+
;;
20+
0*|-0*)
21+
set -- "$1" "$(printf '%d' "$2")"
22+
;;
23+
*)
24+
return 1
25+
;;
26+
esac
27+
eval "$1=\"\$2\""
28+
}
29+
30+
### Usage: is_bit_set number bit_pos
31+
###
32+
### Checks whether the bit at position bit_pos is set.
33+
###
34+
### Arguments:
35+
### number - integer value to extract the bit from
36+
### bit_pos - bit position (0 = least significant bit)
37+
###
38+
### Result:
39+
### The return 0 (true) if bit is set, 1 (false) if not.
40+
###
41+
is_bit_set()
42+
{
43+
return $(( !(($1 >> $2) & 1) ))
44+
}
45+
46+
### Usage: get_bit result_var number bit_pos
47+
###
48+
### Extract the value of the specified bit from a number.
49+
###
50+
### Arguments:
51+
### result_var - name of the variable to store the result
52+
### number - integer value to extract the bit from
53+
### bit_pos - bit position (0 = least significant bit)
54+
###
55+
### Result:
56+
### The value of the specified bit (0 or 1) is stored in result_var.
57+
###
58+
get_bit()
59+
{
60+
is_bit_set "$2" "$3" &&
61+
eval "$1=1" ||
62+
eval "$1=0"
63+
}
64+
65+
### Usage: set_bit_value result_var number bit value
66+
###
67+
### Sets the specified bit in a number to a given value (0 or 1).
68+
###
69+
### Arguments:
70+
### result_var - name of the variable to store the result
71+
### number - integer value to modify
72+
### bit - bit position (0 = least significant bit)
73+
### value - desired bit value (0 or 1)
74+
###
75+
### Result:
76+
### The modified number with the updated bit is stored in result_var.
77+
###
78+
set_bit_value()
79+
{
80+
local set_bit_value=''
81+
__set_bit_value() {
82+
local v
83+
__shell_prepare_integer v "$1"
84+
if [ "$3" -eq 0 ]; then
85+
set_bit_value=$(( $v & ~(1 << $2) ))
86+
else
87+
set_bit_value=$(( $v | (1 << $2) ))
88+
fi
89+
}
90+
__set_bit_value "$2" "$3" "$4"
91+
unset -f __set_bit_value
92+
eval "$1=\"\$set_bit_value\""
93+
}
94+
95+
### Usage: set_bit result_var number bit
96+
###
97+
### Sets the specified bit to 1.
98+
###
99+
### Arguments:
100+
### result_var - name of the variable to store the result
101+
### number - integer value to modify
102+
### bit - bit position (0 = least significant bit)
103+
###
104+
### Result:
105+
### The modified number with the bit set to 1 is stored in result_var.
106+
###
107+
set_bit()
108+
{
109+
set_bit_value "$1" "$2" "$3" 1
110+
}
111+
112+
### Usage: clear_bit result_var number bit
113+
###
114+
### Clears (sets to 0) the specified bit.
115+
###
116+
### Arguments:
117+
### result_var - name of the variable to store the result
118+
### number - integer value to modify
119+
### bit - bit position (0 = least significant bit)
120+
###
121+
### Result:
122+
### The modified number with the bit cleared is stored in result_var.
123+
###
124+
clear_bit()
125+
{
126+
set_bit_value "$1" "$2" "$3" 0
127+
}
128+
129+
### Usage: toggle_bit result_var number bit
130+
###
131+
### Toggles (inverts) the specified bit.
132+
###
133+
### Arguments:
134+
### result_var - name of the variable to store the result
135+
### number - integer value to modify
136+
### bit - bit position (0 = least significant bit)
137+
###
138+
### Result:
139+
### The modified number with the bit inverted is stored in result_var.
140+
###
141+
toggle_bit()
142+
{
143+
if is_bit_set "$2" "$3"; then
144+
set_bit_value "$1" "$2" "$3" 0
145+
else
146+
set_bit_value "$1" "$2" "$3" 1
147+
fi
148+
}
149+
150+
### Usage: set_bits result_var number bit1 bit2 ...
151+
###
152+
### Sets multiple bits to 1 in a number.
153+
###
154+
### Arguments:
155+
### result_var - name of the variable to store the result
156+
### number - integer value to modify
157+
### bit1...N - list of bit positions to set
158+
###
159+
### Result:
160+
### The modified number with all specified bits set to 1 is stored in result_var.
161+
###
162+
set_bits()
163+
{
164+
local __res="$1" number="$2"
165+
shift 2
166+
while [ "$#" -gt 0 ]; do
167+
set_bit_value number "$number" "$1" 1
168+
shift
169+
done
170+
eval "$__res=\"\$number\""
171+
}
172+
173+
### Usage: clear_bits result_var number bit1 bit2 ...
174+
###
175+
### Clears (sets to 0) multiple bits in a number.
176+
###
177+
### Arguments:
178+
### result_var - name of the variable to store the result
179+
### number - integer value to modify
180+
### bit1...N - list of bit positions to clear
181+
###
182+
### Result:
183+
### The modified number with all specified bits cleared is stored in result_var.
184+
###
185+
clear_bits()
186+
{
187+
local __res="$1" number="$2"
188+
shift 2
189+
while [ "$#" -gt 0 ]; do
190+
set_bit_value number "$number" "$1" 0
191+
shift
192+
done
193+
eval "$__res=\"\$number\""
194+
}
195+
196+
### Usage: toggle_bits result_var number bit1 bit2 ...
197+
###
198+
### Toggles (inverts) multiple bits in a number.
199+
###
200+
### Arguments:
201+
### result_var - name of the variable to store the result
202+
### number - integer value to modify
203+
### bit1...N - list of bit positions to toggle
204+
###
205+
### Result:
206+
### The modified number with all specified bits inverted is stored in result_var.
207+
###
208+
toggle_bits()
209+
{
210+
printf -v "$__res" '%d' "$number"
211+
local __res="$1" number="$2"
212+
shift 2
213+
while [ "$#" -gt 0 ]; do
214+
toggle_bit number "$number" "$1"
215+
shift
216+
done
217+
eval "$__res=\"\$number\""
218+
}
219+
220+
integer_to_binary()
221+
{
222+
local arg
223+
224+
__shell_prepare_integer arg "$1" ||
225+
return 1
226+
227+
set -- "$arg" "$(( ${2:-8} - 1 ))" ""
228+
229+
while [ $2 -ge 0 ]; do
230+
set -- "$1" "$(( $2 - 1 ))" "$3$(( ($1 >> $2) & 1 ))"
231+
done
232+
233+
printf '%s\n' "$3"
234+
}
235+
236+
fi #__included_shell_bits

0 commit comments

Comments
 (0)