-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcalc.sh
executable file
·282 lines (273 loc) · 9.64 KB
/
calc.sh
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#! /usr/bin/env bash
coproc dc 2>&1
./pipeglade -i calc.in -o calc.out -b -u calc.ui -O calc.err -l calc.log >/dev/null
NUMKEYS=(0 1 2 3 4 5 6 7 8 9 A B C D E F)
NUMPAD=("${NUMKEYS[@]}" neg point div mul minus plus squareroot power)
STORAGEKEYS=(recall store)
OTHERKEYS=(enter edit swap clear drop cancel)
VARKEYS=(var_2 var_3 var_a var_b var_c var_d var_e var_f var_g var_h var_i \
var_j var_k var_l var_m var_n var_o var_p var_q var_r var_s \
var_t var_u var_v var_w var_x var_y var_z)
varkeys_set_visible()
# expose second keybord level
{
for i in "${VARKEYS[@]}"; do
echo "$i:set_visible $1" >calc.in
done
}
printstack()
{
echo "entry:set_placeholder_text" >calc.in
# tell dc to print its stack
echo "f"
i=0
unset DC_OUT
# read dc's response, which may include error messages
while read -t .1 DC_OUT[$i]; do (( i++ )); done
# check for specific errors
if [[ "${DC_OUT[0]}" =~ "stack" || "${DC_OUT[0]}" =~ "zero" ]]; then
echo "entry:set_placeholder_text ${DC_OUT[0]}"
echo "stack:grab_focus" # unfocussing entry
else
# display stack in a GtkTreeView
echo "stack:clear"
echo "stack:set 5 1"
ROW=4
while [[ $i -gt 0 ]]; do
(( i-- ))
(( ROW++ ))
echo "stack:set $ROW 0 $i"
echo "stack:set $ROW 1 ${DC_OUT[$i]}"
done
echo "stack:scroll $ROW 1"
fi >calc.in
}
edittop()
# put top of stack into GtkEntry
{
echo "p s!" # talking to dc,
read -t .1 DC_OUT # reading dc's response,
# and sending it to pipeglade
echo "entry:set_text $DC_OUT" >calc.in
}
# initial window dressing
echo "precision:set_value 5" >calc.in
for i in "${NUMPAD[@]}"; do
echo "$i:style border-radius:20px; border-color:darkblue; font-weight:bold; font-size:16px"
done >calc.in
for i in "${OTHERKEYS[@]}"; do
echo "$i:style border-radius:20px; font-weight:bold"
done >calc.in
for i in "${STORAGEKEYS[@]}"; do
echo "$i:style border-radius:20px; border-color:darkgreen; font-weight:bold"
done >calc.in
for i in "${VARKEYS[@]}"; do
echo "$i:style border-radius:10px; border-color:darkgreen; font-style:italic; font-size:16px"
done >calc.in
echo "off:style color:darkred; border-radius:20px; border-color:darkred; font-weight:bold" >calc.in
echo "entry:style font:monospace 12" >calc.in
echo "main:style border-radius:20px" >calc.in
{
# main loop; stdin and stdout are connected to the dc coprocess
printstack
while true; do
# receive feedback from GUI
read IN <calc.out
# if feedback came from a button, it ends ":clicked"
C="${IN%:clicked}" # remove ":clicked"
if [[ "${#C}" -eq 1 ]]; then
# our digit buttons all have one-character names
# string the digits together
NUM="$NUM$C"
# and put them into our GtkEntry
echo "entry:set_text $NUM" >calc.in
elif [[ "$IN" =~ "entry:text " ]]; then
# feedback from our GtkEntry
CURRENT_ENTRY="${IN#entry:text }"
NUM="$CURRENT_ENTRY"
# dc uses '_' as a negative sign
CURRENT_ENTRY="${CURRENT_ENTRY//-/_}"
elif [[ "$IN" =~ "var_" ]]; then
# freedback from variable buttons
VAR="${IN#var_}"
VAR="${VAR%:clicked}"
if [[ "$VARMODE" == "recall" ]]; then
echo "L$VAR"
elif [[ "$VARMODE" == "store" ]]; then
echo "S$VAR"
fi
printstack
varkeys_set_visible 0
elif [[ "$IN" =~ "radix:value " ]]; then
# feedback from the radix scale
RADIX="${IN#radix:value }"
RADIX="${RADIX/.[0-9]*}"
# telling dc what to do
echo "A i $RADIX o $RADIX i"
printstack
# graying out meaningless digit keys
for i in "${NUMKEYS[@]:2:(( $RADIX - 1 ))}"; do
echo "$i:set_sensitive 1" >calc.in
done
for i in "${NUMKEYS[@]:$RADIX}"; do
echo "$i:set_sensitive 0" >calc.in
done
elif [[ $IN =~ "precision:value " ]]; then
# feedback from the precision scale
PRECISION="${IN#precision:value }"
PRECISION="${PRECISION/.[0-9]*}"
echo "$PRECISION k"
elif [[ $IN == "main:closed" ]]; then
# exit gracefully when GUI gets killed by window manager
exit
elif [[ -n $C ]]; then
# here, $C is a multi-character button name that doesn't look like "var_x"
case "$C" in
point)
NUM="$NUM."
echo "entry:set_text $NUM" >calc.in
;;
neg)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY _1 *"
edittop
else
echo "_1 *"
unset NUM
unset CURRENT_ENTRY
printstack
fi
;;
edit)
edittop
printstack
;;
enter)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
else
echo "d"
fi
unset NUM
unset CURRENT_ENTRY
printstack
;;
div)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "/"
unset NUM
unset CURRENT_ENTRY
printstack
;;
mul)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "*"
unset NUM
unset CURRENT_ENTRY
printstack
;;
minus)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "-"
unset NUM
unset CURRENT_ENTRY
printstack
;;
plus)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "+"
unset NUM
unset CURRENT_ENTRY
printstack
;;
power)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "^"
unset NUM
unset CURRENT_ENTRY
printstack
;;
squareroot)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
echo "v"
unset NUM
unset CURRENT_ENTRY
printstack
;;
swap)
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
fi
# portability kludge. The parentheses are dc variable names
echo "s(s)L(L)"
unset NUM
unset CURRENT_ENTRY
printstack
;;
drop)
if [[ -z "$CURRENT_ENTRY" ]]; then
# portabilty kludge (and memory leak)
echo "s!"
fi
echo "entry:set_text" >calc.in
unset NUM
unset CURRENT_ENTRY
printstack
;;
clear)
echo "c"
echo "entry:set_text" >calc.in
unset NUM
unset CURRENT_ENTRY
printstack
;;
cancel)
varkeys_set_visible 0
echo "entry:set_text" >calc.in
unset NUM
unset CURRENT_ENTRY
printstack
;;
recall)
VARMODE="recall"
varkeys_set_visible 1
;;
store)
VARMODE="store"
if [[ -n "$CURRENT_ENTRY" ]]; then
echo "LE: $CURRENT_ENTRY" >>ttt
echo "$CURRENT_ENTRY"
echo "entry:set_text" >calc.in
unset NUM
unset CURRENT_ENTRY
fi
varkeys_set_visible 1
;;
off)
echo "_:main_quit" >calc.in
exit
;;
esac
fi
done
} <&"${COPROC[0]}" >&"${COPROC[1]}"