blob: efeb2beccb3aae6abb73000f07e6833a54d9c690 (
plain)
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
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
|
#!/bin/zsh -f
# ZSH setup {{{1
# make the $functions and $functracs variables available
zmodload -F zsh/parameter +p:functions +p:functrace
# variables gathered from the environment {{{1
# debugging
# 0 -> off (+ WINEDEBUG=-all)
# 1 -> log messages (mostly 'eval' calls) (+ WINEDEBUG=-all)
# 2 -> log messages (+ default WINEDEBUG)
# 3 -> 2 + xtrace
PLAY_DEBUG=${PLAY_DEBUG:-0}
[[ $PLAY_DEBUG == 3 ]] && setopt xtrace
# directory we are in
PLAY_DIR="${PLAY_DIR:-${0:h}}"
# directory of installed games
PLAY_GAMES="${PLAY_GAMES:-$PLAY_DIR/installed}"
# directory of templages
PLAY_TEMPLATES="${PLAY_TEMPLATES:-$PLAY_DIR/templates}"
# binary to echo
PLAY_BIN="${PLAY_BIN:-$0}"
# initialization of internal variables {{{1
# environment dictionaries
# ENV: name to value
# EENV: name to string, which is evaluated into the value
typeset -A ENV EENV
# current binary -- complete path
BIN=${0:A}
# current template -- used for EXPORT
CUR_TEMPLATE=play
# array of loaded templates
declare -a TEMPLATES
# Array of phases
PHASES=(setenv prepare setupX startX run cleanup)
declare -r PHASES
declare -A PHASE_FUNS
# global functions {{{1
# print passed arguments to stderr
# if first arg is "-n", do not append newline
out () {
zparseopts -D n=n
echo $n ">>> $*" >&2
}
# print passed arguments to stderr ONLY if PLAY_DEBUG is nonzero
log () {
(( PLAY_DEBUG > 0 )) && echo "*** $*" >&2
}
# die with a supplied error message
die () {
out "*** ERROR: $*"
exit 1
}
# exports $1=$2
exp () {
log "Setting envvar '$1' to '$2'"
export $1=$2
}
# executes the passed command including arguments
# (as individual parameters to this function)
# if first arg is "-e" use exec instead of eval
# if first arg is "-b" background the job
exc () {
local cmd="eval" bg
if [[ $1 == "-e" ]]; then
cmd="exec"
shift
elif [[ $1 == "-b" ]]; then
bg=" in background"
shift
fi
log "Executing (using '$cmd'$bg):"
log "> $*"
if [[ $cmd == exec ]]; then
exec $@
elif [[ -n $bg ]]; then
$* &
else
$*
fi
}
# exports the given key with its value in $ENV
# NB: it also exports empty values
set_env () {
local k=$1
local v=${ENV[$k]}
v=${(P)${:-PLAY_ENV_$k}:-$v}
exp $k $v
}
# exports the given key with its value in $EENV
# this implies, that the value is evaluated!
# NB: it also exports empty values
set_eenv () {
local k=$1
local v=${EENV[$k]}
v=${(P)${:-PLAY_EENV_$k}:-$v}
exp $k `eval $v`
}
# inherits a specified template
# i.e. source it :)
# if first argument is "-e", do not die if template could not be found
inherit () {
zparseopts -D e=nonfatal
for templ; do
local old_templ=$CUR_TEMPLATE
CUR_TEMPLATE=$templ
if [[ ! -e $PLAY_TEMPLATES/$templ ]]; then
if [[ -n $nonfatal ]]; then
log "Template '$templ' not found"
return
else
die "Template '$templ' not found"
fi
fi
source $PLAY_TEMPLATES/$templ
TEMPLATES+=$CUR_TEMPLATE
CUR_TEMPLATE=$old_templ
done
}
# returns true iff the given template has been loaded
loaded () {
(( $+TEMPLATES[(r)$1] ))
}
# run the chain of functions of the templates for the phase
# it gets called from
# Param: -r -> remove the phase of this template
super () {
zparseopts -D r+:=removes
local caller=$funcstack[2] funs=
if (( $+PHASES[(r)$caller] )); then
removes=(${removes/-r/})
if [[ -n $removes ]]; then
removes=(${removes/%/_$caller})
funs=(${(s.:.)PHASE_FUNS[$caller]})
funs=(${funs:|removes})
eval ${(F)funs}
else
_$caller
fi
else
log "'super' called from non-phase '$caller'"
fi
}
# function, that is used to _export_ the default phase functions
# i.e. 'EXPORT prepare' in template 'bla' will add bla_prepare to the functions being called
# on prepare()
# NB: this relies on CUR_TEMPLATE being correct -- DO NOT set CUR_TEMPLATE in a game file!
EXPORT () {
local override
local fun
for phase; do
if [[ $phase == *_override ]]; then
override=1
phase=${phase%_override}
else
override=0
fi
fun=${CUR_TEMPLATE}_${phase}
if (( $+PHASES[(r)$phase] )); then
if (( override )); then
PHASE_FUNS[$phase]=$fun
else
PHASE_FUNS[$phase]+=:$fun
fi
else
log "Invalid phase function '$phase' exported in $CUR_TEMPLATE"
fi
done
}
OVERRIDE () {
EXPORT ${argv/%/_override}
}
# default enviroment {{{1
ENV[DISPLAY]=":1"
(( PLAY_DEBUG <= 1 )) && ENV[WINEDEBUG]="-all"
# phase functions {{{1
# starts a new X
# if overridden, this MUST call `$BIN --in-X`
play_startX () {
exc startx $BIN --in-X $GAME -- $DISPLAY -ac -br -quiet ${=EXARGS}
}
# populate the environment
play_setenv () {
# set environment
# ENV is set directly -- EENV is evaluated
# it is possible to override ENV[p] by PLAY_ENV_p
# (and similar for EENV)
for e in ${(k)ENV}; do
set_env $e
done
for e in ${(k)EENV}; do
set_eenv $e
done
}
# run game
play_run () {
exc $EXE "$ARGS"
}
# manipulate the newly created X instance
play_setupX () {
# set display size
[[ -n $SIZE ]] && exc xrandr -s $SIZE
}
# prepare things for the game, e.g. mount ISOs
play_prepare () {
}
# cleanup after yourself
play_cleanup () {
}
OVERRIDE $PHASES[@]
for phase in $PHASES; do
functions[$phase]=_$phase
done
# internal functions {{{1
_load () { # {{{2
inherit -e default
source $GAME_PATH
local funs
for phase in $PHASES; do
funs=(${(s.:.)PHASE_FUNS[$phase]})
funs=(${funs/%/ \$@})
functions[_$phase]=${(F)funs}
done
}
_list () { # {{{2
out "The installed games are:"
# on -> sort alphabetically
# N -> NULL_GLOB -> no error message if no match
# .,@ -> regular files or symbolic links (, == or)
# :t -> modifier: only basename
for k in $PLAY_GAMES/*(onN.,@:t); do
echo "\t> $k"
done
}
_new () { # {{{2
local GAME=$1
local DGAME="$PLAY_GAMES/$GAME"
local EXE=$2
local PREFIX=${${3}:-$GAME}
local convpath
[[ -e $DGAME ]] && die "Game file already existing -- aborting!"
inherit -e default
set_eenv WINEPREFIX
set_env WINEDEBUG
[[ ! -e $WINEPREFIX ]] && die "Specified prefix '$PREFIX' does not exist"
convpath="$(exc winepath -u $EXE)"
[[ ! -e $convpath ]] && die "Specified executable does not exist"
[[ -n $3 ]] && GPREFIX="PREFIX=\"$3\""
# everything is fine -- write file
cat > $DGAME << EOF
inherit wine
$GPREFIX
EXE="$EXE"
# vim:ft=sh
EOF
out "New game successfully created"
out "You can play it by '$PLAY_BIN $GAME'"
out -n "Play it now? [y/n] "
if read -q; then
echo
exc -e $BIN $GAME
else
echo
fi
}
_continue_in_X () { # {{{2
_load
setupX
run
}
_run () { #{{{2
declare -xg GAME=$1
declare -xg GAME_PATH="$PLAY_GAMES/$GAME"
if [[ $GAME == new ]]; then
shift
_new "$@"
elif [[ -z $GAME || ! -e $GAME_PATH ]]; then
[[ ! -e $GAME_PATH ]] && out "Game '$GAME' not found"
_list
exit 1
else
if [[ $2 == "cleanup" ]]; then
out "Cleaning up after '$GAME'"
_load
setenv
cleanup force
else
out "Launching '$GAME'"
_load
setenv
prepare
startX
cleanup
fi
fi
}
# main {{{1
if [[ $1 == "--in-X" ]]; then
_continue_in_X
else
_run "$@"
fi
# }}}1
# vim: foldmethod=marker
|