wwine 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +676 -0
- data/README +11 -0
- data/wwine +970 -0
- data/wwine.1 +198 -0
- metadata +64 -0
data/README
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
wwine (wrapped wine) is a a wine wrapper. It wraps various flavours of wine
|
|
2
|
+
(including vanilla wine and crossover office/games) into a single
|
|
3
|
+
unified interface, complete with full bottle support for all
|
|
4
|
+
of them (including vanilla wine).
|
|
5
|
+
|
|
6
|
+
It integrates well with all flavours, so for instance applications
|
|
7
|
+
installed using crossover will be managable through the usual crossover
|
|
8
|
+
interface.
|
|
9
|
+
|
|
10
|
+
For vanilla wine it uses WINEPREFIX to achieve bottle support,
|
|
11
|
+
creating bottles as ~/.wwinebottles/[BOTTLE_NAME]
|
data/wwine
ADDED
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
# wwine
|
|
3
|
+
# Copyright (C) Eskild Hustvedt 2009, 2010
|
|
4
|
+
#
|
|
5
|
+
# This program is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
# Command-line parsing
|
|
19
|
+
require 'getoptlong'
|
|
20
|
+
# To read info for --debuginfo
|
|
21
|
+
require 'open3'
|
|
22
|
+
# Application version
|
|
23
|
+
$version = 0.1
|
|
24
|
+
# The wine flavour to use
|
|
25
|
+
$wine = nil
|
|
26
|
+
# The bottle to use
|
|
27
|
+
$bottle = nil
|
|
28
|
+
# Verbose mode (true/false)
|
|
29
|
+
$verbose = false
|
|
30
|
+
# CX path
|
|
31
|
+
$cxPath = nil
|
|
32
|
+
# Path to write wrapper to
|
|
33
|
+
$wrapperPath = nil
|
|
34
|
+
# Directory to cd to in a wrapper
|
|
35
|
+
$wrapperCwd = nil
|
|
36
|
+
# File to load wwine data from
|
|
37
|
+
$wwineDataFrom = nil
|
|
38
|
+
|
|
39
|
+
# Purpose: Attempt to kill all running wine processes
|
|
40
|
+
def killWine (dryRun = false, signal = 15)
|
|
41
|
+
# Open a pipe to ps to read processes
|
|
42
|
+
wines = IO.popen('ps uxw')
|
|
43
|
+
# True if we have killed something
|
|
44
|
+
killed = false
|
|
45
|
+
# The name of the signal being sent
|
|
46
|
+
sigName = 'SIGTERM'
|
|
47
|
+
# Get an integer version of signal parameter
|
|
48
|
+
begin
|
|
49
|
+
signal = Integer(signal)
|
|
50
|
+
rescue
|
|
51
|
+
signal = nil
|
|
52
|
+
end
|
|
53
|
+
# If the signal parameter is invalid, error out
|
|
54
|
+
if signal == nil
|
|
55
|
+
signal = 15
|
|
56
|
+
elsif signal > 15 || signal < 0
|
|
57
|
+
puts('Argument to --kill must be an integer between 0-15 (or none at all)')
|
|
58
|
+
exit(1)
|
|
59
|
+
end
|
|
60
|
+
# Map of number => name
|
|
61
|
+
sigNames = { 9 => 'SIGKILL', 15 => 'SIGTERM', 2 => 'SIGINT' }
|
|
62
|
+
if sigNames[signal] != nil
|
|
63
|
+
sigName = sigNames[signal]
|
|
64
|
+
else
|
|
65
|
+
sigName = 'signal '+signal
|
|
66
|
+
end
|
|
67
|
+
# Go through each line in the 'ps' output
|
|
68
|
+
wines.each do |line|
|
|
69
|
+
line.chomp!
|
|
70
|
+
# Ignore the header
|
|
71
|
+
if line =~ /USER\s*PID/
|
|
72
|
+
next
|
|
73
|
+
end
|
|
74
|
+
pid = String.new(line)
|
|
75
|
+
name = String.new(line)
|
|
76
|
+
# Parse the PID
|
|
77
|
+
pid.sub!(/^\S+\s*(\d+)\s+.*/,'\1')
|
|
78
|
+
# Parse the name
|
|
79
|
+
name.sub!(/^\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+/,'')
|
|
80
|
+
# If either of these are true some part of the parsing failed, and we
|
|
81
|
+
# should thus simply skip this line
|
|
82
|
+
if pid == name || pid == line || name == line
|
|
83
|
+
next
|
|
84
|
+
end
|
|
85
|
+
# Ignore processes that are not wine-related
|
|
86
|
+
if name =~ /(wine|windows|[a-z]:\\|\.(exe|dll))/i
|
|
87
|
+
# If wine is not a part of the process name, check if the
|
|
88
|
+
# name either includes a \ (which most likely means it is a windows
|
|
89
|
+
# path because it has already matched one of the above) or exe/dll.
|
|
90
|
+
if ! name =~ /wine/i && ( name =~ /\// || ! name =~ /\.(exe|dll)/i )
|
|
91
|
+
next
|
|
92
|
+
end
|
|
93
|
+
else
|
|
94
|
+
next
|
|
95
|
+
end
|
|
96
|
+
# At least on Linux kernels, /proc/ will include useful info, we use it to
|
|
97
|
+
# check if the exe actually is wine
|
|
98
|
+
if File.exists?('/proc/'+pid+'/exe') and File.symlink?('/proc/'+pid+'/exe')
|
|
99
|
+
linkValue = File.readlink('/proc/'+pid+'/exe')
|
|
100
|
+
if File.readlink('/proc/'+pid+'/exe') !~ /wine/i
|
|
101
|
+
next
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
# Clean up the name
|
|
105
|
+
name.sub!(/\s*$/,'')
|
|
106
|
+
# Send SIGTERM (or output information if in dryRun mode)
|
|
107
|
+
if !dryRun
|
|
108
|
+
puts 'Sending '+sigName+' to '+name+' (PID '+pid+')'
|
|
109
|
+
begin
|
|
110
|
+
Process.kill(signal,pid.to_i)
|
|
111
|
+
rescue
|
|
112
|
+
puts('Error while attempting to send signal to '+pid+': '+$!)
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
puts 'Would send '+sigName+' to '+name+' (PID '+pid+')'
|
|
116
|
+
end
|
|
117
|
+
killed = true
|
|
118
|
+
end
|
|
119
|
+
if ! killed
|
|
120
|
+
puts 'No wine processes found.'
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Purpose: Print formatted --help output
|
|
125
|
+
# Usage: printHelp('-shortoption', '--longoption', 'description');
|
|
126
|
+
# Description will be reformatted to fit within a normal terminal
|
|
127
|
+
def printHelp (short,long,description)
|
|
128
|
+
maxlen = 80
|
|
129
|
+
optionlen = 20
|
|
130
|
+
# Check if the short/long are LONGER than optionlen, if so, we need
|
|
131
|
+
# to do some additional magic to take up only $maxlen.
|
|
132
|
+
# The +1 here is because we always add a space between them, no matter what
|
|
133
|
+
if (short.length + long.length + 1) > optionlen
|
|
134
|
+
optionlen = short.length + long.length + 1;
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
generatedDesc = ''
|
|
138
|
+
currdesc = ''
|
|
139
|
+
|
|
140
|
+
description.split(/ /).each do |part|
|
|
141
|
+
if(generatedDesc.length > 0)
|
|
142
|
+
if (currdesc.length + part.length + 1 + 20) > maxlen
|
|
143
|
+
generatedDesc.concat("\n")
|
|
144
|
+
currdesc = ''
|
|
145
|
+
else
|
|
146
|
+
currdesc.concat(' ')
|
|
147
|
+
generatedDesc.concat(' ')
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
currdesc.concat(part)
|
|
151
|
+
generatedDesc.concat(part)
|
|
152
|
+
end
|
|
153
|
+
if !(generatedDesc.length > 0)
|
|
154
|
+
raise("Option mismatch")
|
|
155
|
+
end
|
|
156
|
+
generatedDesc.split(/\n/).each do |descr|
|
|
157
|
+
printf("%-4s %-15s %s\n",short,long,descr)
|
|
158
|
+
short = ''; long = ''
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Purpose: Quote a string (or array of strings) for use in the shell
|
|
163
|
+
def shellQuote(target)
|
|
164
|
+
if target.class == Array
|
|
165
|
+
newTarget = []
|
|
166
|
+
target.each do |subt|
|
|
167
|
+
subt = shellQuote(subt)
|
|
168
|
+
newTarget.push(subt)
|
|
169
|
+
end
|
|
170
|
+
return newTarget
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
fixedTarget = target.gsub('\\') { '\\\\' }
|
|
174
|
+
fixedTarget.gsub!(/'/,"\\\\'")
|
|
175
|
+
|
|
176
|
+
finalTarget = "'"
|
|
177
|
+
finalTarget.concat(fixedTarget)
|
|
178
|
+
finalTarget.concat("'");
|
|
179
|
+
return finalTarget
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Purpose: Unquote a string generated by shellQuote
|
|
183
|
+
def unShellQuote(target)
|
|
184
|
+
fixedTarget = target.gsub("\\'","'")
|
|
185
|
+
fixedTarget.gsub!('\\\\') { '\\' }
|
|
186
|
+
return fixedTarget
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Purpose: Unquote a full line of shellQuoted strings
|
|
190
|
+
def unquoteShellArray (source,targetarr)
|
|
191
|
+
source.split(/ '/).each do |part|
|
|
192
|
+
part.sub!(/'$/,'')
|
|
193
|
+
part.sub!(/^'/,'')
|
|
194
|
+
part.chomp!
|
|
195
|
+
if part.match(/\S/)
|
|
196
|
+
targetarr.push(unShellQuote(part))
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
return targetarr
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Purpose: Write a wrapper script
|
|
203
|
+
def writeWrapper (targetFile, wwineCommand, otherCommand, cwd, wwineInfo, args, wineprefix = nil)
|
|
204
|
+
# Open the file for riting
|
|
205
|
+
begin
|
|
206
|
+
file = File.open(targetFile,'w')
|
|
207
|
+
rescue
|
|
208
|
+
puts('Failed to open "'+targetFile+'" for writing: '+$!)
|
|
209
|
+
exit(1)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
file.puts('#!/bin/sh')
|
|
213
|
+
file.puts('# Script autogenerated by wwine '+$version.to_s+' (http://random.zerodogg.org/wwine)')
|
|
214
|
+
file.puts('# Licensed under the GNU General Public License version 3 or later')
|
|
215
|
+
file.puts('#')
|
|
216
|
+
file.puts('# You should have received a copy of the GNU General Public License')
|
|
217
|
+
file.puts('# along with wwine. If not, see <http://www.gnu.org/licenses/>.')
|
|
218
|
+
file.puts('#')
|
|
219
|
+
file.puts('# The following two lines contain wwine metadata');
|
|
220
|
+
file.puts('# wwineInfo: v1 '+shellQuote(wwineInfo).join(' '))
|
|
221
|
+
file.puts('# wwineCmd: '+shellQuote(args).join(' '));
|
|
222
|
+
file.puts('')
|
|
223
|
+
file.puts("cd "+shellQuote(cwd)+" || exit 1")
|
|
224
|
+
file.puts('wwine='+shellQuote(File.expand_path($0)))
|
|
225
|
+
file.puts('if [ ! -x "$wwine" ]; then')
|
|
226
|
+
file.puts("\t"+'wwine="`which wwine 2> /dev/null`"')
|
|
227
|
+
file.puts('fi')
|
|
228
|
+
file.puts('if [ "x$wwine" != "x" ]; then')
|
|
229
|
+
file.puts("\t"+'exec "$wwine" '+shellQuote(wwineCommand).join(" ")+' "$@"')
|
|
230
|
+
file.puts('else')
|
|
231
|
+
# Add wineprefix if needed. This is used when --wine is wine because wine
|
|
232
|
+
# has no support for specifying a bottle on the command-line.
|
|
233
|
+
if wineprefix != nil
|
|
234
|
+
wineprefix.sub!(/'/,'\\')
|
|
235
|
+
file.puts("\t"+'export WINEPREFIX='+shellQuote(wineprefix))
|
|
236
|
+
file.puts("\t"+"export WINEDEBUG='-all'");
|
|
237
|
+
end
|
|
238
|
+
file.puts("\t"+"exec "+shellQuote(otherCommand).join(" ")+' "$@"')
|
|
239
|
+
file.puts('fi')
|
|
240
|
+
file.puts('echo "Launch script failed. No wwine found and wine command failed to exec."')
|
|
241
|
+
file.puts('exit 1')
|
|
242
|
+
|
|
243
|
+
file.chmod(0755)
|
|
244
|
+
file.close
|
|
245
|
+
|
|
246
|
+
puts('Wrote wrapper script to '+targetFile)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Purpose: Prepare to generate a wrapper script
|
|
250
|
+
def generateWrapper (wine,bottle,targetFile,wineCommand,args,type = nil)
|
|
251
|
+
wwineCmd = []
|
|
252
|
+
wwineInfo = ['nil','nil','nil','nil']
|
|
253
|
+
|
|
254
|
+
if File.exists?(targetFile)
|
|
255
|
+
puts(targetFile+': already exists. Bailing out')
|
|
256
|
+
puts('Remove the target file first, then try again')
|
|
257
|
+
exit(1)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Generate a wwine command-line
|
|
261
|
+
if $verbose
|
|
262
|
+
wwineCmd.push('--verbose')
|
|
263
|
+
end
|
|
264
|
+
if $cxPath
|
|
265
|
+
wwineCmd.push('--cxinstalldir',$cxPath)
|
|
266
|
+
wwineInfo[3] = $cxPath
|
|
267
|
+
end
|
|
268
|
+
if wine
|
|
269
|
+
wwineCmd.push('--wine',wine)
|
|
270
|
+
wwineInfo[1] = wine
|
|
271
|
+
end
|
|
272
|
+
if bottle
|
|
273
|
+
wwineCmd.push('--bottle',bottle)
|
|
274
|
+
wwineInfo[2] = bottle;
|
|
275
|
+
end
|
|
276
|
+
# Append -- if it isn't already
|
|
277
|
+
if ! args.join(' ').match(/ -- /)
|
|
278
|
+
wwineCmd.push('--')
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
wwineCmd.concat(args)
|
|
282
|
+
|
|
283
|
+
if $wrapperCwd == nil
|
|
284
|
+
$wrapperCwd = Dir.pwd
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
wwineInfo[0] = $wrapperCwd
|
|
288
|
+
|
|
289
|
+
wineprefix = nil
|
|
290
|
+
|
|
291
|
+
# For wine there is no --bottle definition in the wine command itself,
|
|
292
|
+
# so we need to export a wineprefix in the launch script
|
|
293
|
+
if type == 'wine'
|
|
294
|
+
wineprefix = ENV['WINEPREFIX']
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
writeWrapper(targetFile ,wwineCmd, wineCommand, $wrapperCwd, wwineInfo, args, wineprefix)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Purpose: Load wwine data from a wrapper script
|
|
301
|
+
def loadWwineDataFromFile (file,dryRun = false)
|
|
302
|
+
begin
|
|
303
|
+
puts 'Loading settings from '+file+':'
|
|
304
|
+
outFormat = '%-20s: %s'+"\n"
|
|
305
|
+
source = File.open(file)
|
|
306
|
+
|
|
307
|
+
wwineInfo = ''
|
|
308
|
+
wwineCmd = ''
|
|
309
|
+
|
|
310
|
+
source.each do |line|
|
|
311
|
+
if line.sub!(/^#\s+wwineInfo:\s*/,'')
|
|
312
|
+
wwineInfo = line
|
|
313
|
+
elsif line.sub!(/^#\s+wwineCmd:\s*/,'')
|
|
314
|
+
wwineCmd = line
|
|
315
|
+
end
|
|
316
|
+
if wwineInfo != '' && wwineCmd != ''
|
|
317
|
+
break
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
info = []
|
|
322
|
+
cmd = []
|
|
323
|
+
|
|
324
|
+
if wwineInfo == nil || wwineCmd == nil || wwineInfo == '' || wwineCmd == ''
|
|
325
|
+
puts "The wwine header in this file is broken or missing."
|
|
326
|
+
puts "Unable to continue."
|
|
327
|
+
exit(0)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
unquoteShellArray(wwineInfo,info)
|
|
331
|
+
unquoteShellArray(wwineCmd,cmd)
|
|
332
|
+
|
|
333
|
+
if info[0] != 'v1'
|
|
334
|
+
puts "This version of wwine only supports info format v1."
|
|
335
|
+
puts "This file is verison "+info[0]
|
|
336
|
+
puts "Unable to continue."
|
|
337
|
+
exit(0)
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
if wwineInfo.length < 6 || wwineCmd.length < 1
|
|
341
|
+
puts "The wwine header in this file is broken."
|
|
342
|
+
puts "Unable to continue."
|
|
343
|
+
exit(0)
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
if info[1] != 'nil'
|
|
347
|
+
printf(outFormat,'Switching to directory',info[1])
|
|
348
|
+
if File.exists?(info[1])
|
|
349
|
+
Dir.chdir(info[1])
|
|
350
|
+
else
|
|
351
|
+
puts info[1]+': does not exist, giving up.'
|
|
352
|
+
exit(0)
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
if $wine == nil && info[2] != 'nil'
|
|
357
|
+
$wine = info[2]
|
|
358
|
+
printf(outFormat,'Using --wine',$wine)
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
if $bottle == nil && info[3] != 'nil'
|
|
362
|
+
$bottle = info[3]
|
|
363
|
+
printf(outFormat,'Using --bottle',$bottle)
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
if $cxPath == nil && info[4] != 'nil'
|
|
367
|
+
$cxPath = info[4]
|
|
368
|
+
printf(outFormat,'Using --cxinstalldir',$cxPath)
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
if ! dryRun
|
|
372
|
+
printf(outFormat,'Will now run',cmd.join(' '))
|
|
373
|
+
ARGV.unshift(*cmd)
|
|
374
|
+
end
|
|
375
|
+
rescue => ex
|
|
376
|
+
handleException(ex)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Purpose: Run a command, outputting info of it in verbose mode
|
|
381
|
+
def runcmd(cmd, type = 'exec')
|
|
382
|
+
if(type == 'exec')
|
|
383
|
+
vputs 'Executing: '+cmd.join(' ')
|
|
384
|
+
exec *cmd
|
|
385
|
+
else
|
|
386
|
+
vputs 'Running: '+cmd.join(' ')
|
|
387
|
+
return system(*cmd)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Purpose: Check for a file in path
|
|
392
|
+
def inPath(exec)
|
|
393
|
+
ENV['PATH'].split(/:/).each do |part|
|
|
394
|
+
if File.executable?(part+'/'+exec) and not File.directory?(part+'/'+exec)
|
|
395
|
+
return true
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
return false
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Purpose: Output a string if in verbose mode
|
|
402
|
+
def vputs (str)
|
|
403
|
+
if $verbose
|
|
404
|
+
puts(str)
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# Purpose: Print the help output
|
|
409
|
+
def Help ()
|
|
410
|
+
puts "wwine "+$version.to_s
|
|
411
|
+
puts ""
|
|
412
|
+
puts "Usage: wwine (WWINE PARAMETERS) PROGRAM -- [PROGRAM ARGUMENTS]"
|
|
413
|
+
puts ""
|
|
414
|
+
printHelp('-h','--help','Display this help text')
|
|
415
|
+
printHelp('-w','--wine','Select the wine to use: wine, cxoffice, cxgames, cedega, or a path to a wine bin. Default: wine')
|
|
416
|
+
printHelp('-b','--bottle','Use the selected bottle (~/.wwinebottles/[NAME] for wine, CX bottle or cedega folder, depending on the --wine in use). The bottle will be created if it does not exist.')
|
|
417
|
+
printHelp('-k','--kill','Attempt to kill all running wine processes')
|
|
418
|
+
printHelp('','--drykill','Print what --kill would have done, but don\'t actually do anything')
|
|
419
|
+
printHelp('-c','--cxinstalldir','Use the supplied path as the install path for CXoffice/CXgames (default: autodetect).')
|
|
420
|
+
printHelp('','--wrap','Write a wrapper script of your current wwine command to the path supplied')
|
|
421
|
+
printHelp('','--wrapdir','Use the supplied directory as the working directory for the script created by --wrap (default: current directory)')
|
|
422
|
+
printHelp('-s','--from','Load parameters and program from the wrapper script supplied. Command-line arguments overrides settings from wrapper script.')
|
|
423
|
+
printHelp('-v','--verbose','Enable verbose mode')
|
|
424
|
+
printHelp('','--man','Show the wwine manpage')
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
# Purpose: Show the manpage
|
|
428
|
+
def showManPage ()
|
|
429
|
+
if ! inPath('man')
|
|
430
|
+
puts
|
|
431
|
+
puts "You don't appear to have the 'man' program installed."
|
|
432
|
+
puts "Please install it, then re-run wwine --man"
|
|
433
|
+
exit(0)
|
|
434
|
+
end
|
|
435
|
+
mySelf = File.expand_path($0)
|
|
436
|
+
while File.symlink?(mySelf)
|
|
437
|
+
mySelf = File.readlink(mySelf)
|
|
438
|
+
end
|
|
439
|
+
sourceDir = '.'
|
|
440
|
+
if mySelf != nil
|
|
441
|
+
sourceDir = File.dirname(mySelf)
|
|
442
|
+
end
|
|
443
|
+
dirs = [sourceDir]
|
|
444
|
+
if ENV['MANPATH']
|
|
445
|
+
dirs.concat(ENV['MANPATH'].split(':'))
|
|
446
|
+
end
|
|
447
|
+
dirs.push('./')
|
|
448
|
+
dirs.each do |dir|
|
|
449
|
+
[ 'wwine.1','man1/wwine.1','man1/wwine.1.gz','man1/wwine.1.bz2','man1/wwine.1.lzma'].each do |manFile|
|
|
450
|
+
if File.exists?(dir+'/'+manFile)
|
|
451
|
+
exec('man',dir+'/'+manFile)
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
puts
|
|
456
|
+
puts 'wwine failed to locate its manpage.'
|
|
457
|
+
puts 'Run the following command to view it:'
|
|
458
|
+
puts '\curl -s "http://github.com/zerodogg/wwine/raw/master/wwine.1" | groff -T utf8 -man | \less'
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
# Purpose: Get wine version
|
|
462
|
+
def getWineVersion (source = 'wine', fromStderr = false, cmdOpt = '--version')
|
|
463
|
+
wineVer = nil
|
|
464
|
+
|
|
465
|
+
# Don't try to get it if we have no wine to run
|
|
466
|
+
if inPath(source) || File.executable?(source)
|
|
467
|
+
begin
|
|
468
|
+
cmd = [ source,cmdOpt ]
|
|
469
|
+
Open3.popen3(*cmd) { |stdin, stdout, stderr|
|
|
470
|
+
# Fetch the line from either stderr or out
|
|
471
|
+
if fromStderr
|
|
472
|
+
wineVer = stderr.gets(nil)
|
|
473
|
+
else
|
|
474
|
+
wineVer = stdout.gets(nil)
|
|
475
|
+
end
|
|
476
|
+
}
|
|
477
|
+
# Get the actual version number by stripping away any leading nondigit text
|
|
478
|
+
wineVer.sub!(/^\D+/,'')
|
|
479
|
+
wineVer.chomp!
|
|
480
|
+
rescue
|
|
481
|
+
wineVer = nil
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
return wineVer
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# Purpose: Get cedega version string
|
|
488
|
+
def getCedegaVersionString ()
|
|
489
|
+
cedegaVer = nil
|
|
490
|
+
|
|
491
|
+
if inPath('cedega')
|
|
492
|
+
begin
|
|
493
|
+
# We need the HOME variable
|
|
494
|
+
if ENV.has_key?('HOME')
|
|
495
|
+
# The cedega RC file
|
|
496
|
+
rcFile = ENV['HOME']+'/.cedega/.cedegarc'
|
|
497
|
+
# The cedega build number file
|
|
498
|
+
uiBuildFile = ENV['HOME']+'/.cedega/.ui/BUILDNUMBER'
|
|
499
|
+
# If we have the rc file, open it and fetch the current default
|
|
500
|
+
# engine version from the 'default' setting. It is the closest we are
|
|
501
|
+
# going to get to a current version number without jumping through a lot
|
|
502
|
+
# of hoops.
|
|
503
|
+
if File.exists?(rcFile)
|
|
504
|
+
ind = File.open(rcFile)
|
|
505
|
+
ind.each do |line|
|
|
506
|
+
if line.match(/^default=/)
|
|
507
|
+
line.sub!(/^default=/,'')
|
|
508
|
+
line.chomp!
|
|
509
|
+
cedegaVer = line
|
|
510
|
+
break
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
# If we have a default ver, fetch the UI version as well, as we have to pass
|
|
515
|
+
# through the UI, that number can be useful
|
|
516
|
+
if cedegaVer != nil && File.exists?(uiBuildFile)
|
|
517
|
+
ind = File.open(uiBuildFile)
|
|
518
|
+
buildNo = ind.gets(nil)
|
|
519
|
+
buildNo.chomp!
|
|
520
|
+
if buildNo != nil
|
|
521
|
+
cedegaVer.concat(' (UI build '+buildNo+')');
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
rescue
|
|
526
|
+
end
|
|
527
|
+
if cedegaVer == nil
|
|
528
|
+
cedegaVer = 'present'
|
|
529
|
+
end
|
|
530
|
+
else
|
|
531
|
+
cedegaVer = '(not present)'
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
return cedegaVer
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# Purpose: Get cx* version
|
|
538
|
+
def getCXVersionsFrom (source,wantString = false)
|
|
539
|
+
cxVer = nil
|
|
540
|
+
cxwVer = nil
|
|
541
|
+
if source != nil
|
|
542
|
+
begin
|
|
543
|
+
# Store the binfile for use later
|
|
544
|
+
binFile = source[0]
|
|
545
|
+
# pop off the dummy command
|
|
546
|
+
source.pop
|
|
547
|
+
# Add version
|
|
548
|
+
source.push('--version')
|
|
549
|
+
source = source.join(' ')
|
|
550
|
+
|
|
551
|
+
out = IO.popen(source)
|
|
552
|
+
# The info we need is on line two
|
|
553
|
+
cxVer = out.readline
|
|
554
|
+
cxVer = out.readline
|
|
555
|
+
# Get the actual version number by stripping away any leading nondigit text
|
|
556
|
+
cxVer.sub!(/^\D+/,'')
|
|
557
|
+
cxVer.chomp!
|
|
558
|
+
|
|
559
|
+
cxwVer = getWineVersion(binFile.sub(/cxstart$/,'wineserver'),true,'-v')
|
|
560
|
+
rescue
|
|
561
|
+
cxwVer = nil
|
|
562
|
+
cxVer = nil
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
if wantString
|
|
566
|
+
# If a string has been requested, generate one and return it
|
|
567
|
+
if cxVer != nil
|
|
568
|
+
if cxwVer != nil
|
|
569
|
+
return cxVer+' (based on wine '+cxwVer+')'
|
|
570
|
+
else
|
|
571
|
+
return cxVer
|
|
572
|
+
end
|
|
573
|
+
else
|
|
574
|
+
return '(not present)'
|
|
575
|
+
end
|
|
576
|
+
else
|
|
577
|
+
return cxVer,cxwVer
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# Purpose: Print debugging info
|
|
582
|
+
def debugInfo ()
|
|
583
|
+
outFormat = '%-20s: %s'+"\n"
|
|
584
|
+
puts "wwine "+$version.to_s
|
|
585
|
+
# Load a --from file if it is set
|
|
586
|
+
if $wwineDataFrom
|
|
587
|
+
loadWwineDataFromFile($wwineDataFrom,true)
|
|
588
|
+
end
|
|
589
|
+
# Fetch the md5sum of us. This will at least give a certain clue about the revision
|
|
590
|
+
# of wwine used. Primarily useful for identifying older git clones in bug reports.
|
|
591
|
+
begin
|
|
592
|
+
if inPath('md5sum')
|
|
593
|
+
outStr = nil
|
|
594
|
+
out = IO.popen('md5sum '+File.expand_path($0))
|
|
595
|
+
outStr = out.readline
|
|
596
|
+
outStr.sub!(/\s+.*$/,'')
|
|
597
|
+
outStr.chomp!
|
|
598
|
+
printf(outFormat,'wwine md5sum',outStr)
|
|
599
|
+
else
|
|
600
|
+
printf(outFormat,'wwine md5sum','(md5sum command missing)')
|
|
601
|
+
end
|
|
602
|
+
rescue
|
|
603
|
+
printf(outFormat,'wwine md5sum','(exception: '+$!+')');
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
begin
|
|
607
|
+
|
|
608
|
+
defaultWine,defaultWCMD = getAutoWithParams(nil,false)
|
|
609
|
+
if defaultWine == nil
|
|
610
|
+
defaultWine = '(no wine found)'
|
|
611
|
+
end
|
|
612
|
+
printf(outFormat,'Default flavour',defaultWine)
|
|
613
|
+
|
|
614
|
+
if inPath('wine')
|
|
615
|
+
wineVer = getWineVersion()
|
|
616
|
+
else
|
|
617
|
+
wineVer = '(not present)'
|
|
618
|
+
end
|
|
619
|
+
printf(outFormat,'Wine',wineVer)
|
|
620
|
+
|
|
621
|
+
cxgBin = getCXwithParams('cxgames',nil,false)
|
|
622
|
+
cxgVer = getCXVersionsFrom(cxgBin,true)
|
|
623
|
+
printf(outFormat,'Crossover Games',cxgVer)
|
|
624
|
+
|
|
625
|
+
cxoBin = getCXwithParams('cxoffice',nil,false)
|
|
626
|
+
cxoVer = getCXVersionsFrom(cxoBin,true)
|
|
627
|
+
printf(outFormat,'Crossover Office',cxoVer)
|
|
628
|
+
|
|
629
|
+
cedegaVer = getCedegaVersionString()
|
|
630
|
+
printf(outFormat,'Cedega',cedegaVer)
|
|
631
|
+
rescue => ex
|
|
632
|
+
handleException(ex)
|
|
633
|
+
end
|
|
634
|
+
exit(0)
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
# Purpose: Handle an exception
|
|
638
|
+
def handleException(ex)
|
|
639
|
+
puts('---')
|
|
640
|
+
puts('Exception: '+ex.to_s)
|
|
641
|
+
puts('Backtrace: '+"\n"+ex.backtrace.join("\n"))
|
|
642
|
+
puts('---')
|
|
643
|
+
puts()
|
|
644
|
+
puts('An exception has occurred and wwine can not continue.')
|
|
645
|
+
puts('This almost certainly reflects a bug in wwine.')
|
|
646
|
+
puts('Please check that you have the latest version off wwine,')
|
|
647
|
+
puts('and if you do, report this issue along with the text between the "---" above');
|
|
648
|
+
puts('to http://random.zerodogg.org/wwine/bugs')
|
|
649
|
+
exit(1)
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
# Purpose: Get parameters for wine
|
|
653
|
+
def getWineWithParams (wine,bottle, missingIsFatal = true)
|
|
654
|
+
final = []
|
|
655
|
+
possibleWines = [ 'wine32','wine','wine64','wine.bin','wine.real' ]
|
|
656
|
+
# Manual search path, in the odd case none of the above are in $PATH.
|
|
657
|
+
# Ie. /usr/lib32/wine/wine.bin is the real wine binary on Debian
|
|
658
|
+
searchPath = [ '/usr/lib32/wine/','/usr/bin' ]
|
|
659
|
+
# If wine is not a path or does not exist, check for wine in the path
|
|
660
|
+
if !File.exists?(wine)
|
|
661
|
+
wine = nil
|
|
662
|
+
possibleWines.each do |w|
|
|
663
|
+
if inPath(w)
|
|
664
|
+
wine = w
|
|
665
|
+
break
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
if wine == nil
|
|
670
|
+
searchPath.each do |p|
|
|
671
|
+
possibleWines.each do |w|
|
|
672
|
+
if File.executable?(p+'/'+w) && File.file?(p+'/'+w)
|
|
673
|
+
wine = p+'/'+w
|
|
674
|
+
break
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
if wine != nil
|
|
678
|
+
break
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
if wine == nil
|
|
684
|
+
if missingIsFatal == true
|
|
685
|
+
puts('"wine" does not appear to be installed')
|
|
686
|
+
exit(1)
|
|
687
|
+
else
|
|
688
|
+
return nil
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
final.push(wine)
|
|
693
|
+
|
|
694
|
+
# Set WINEPREFIX for bottle support
|
|
695
|
+
if(bottle != nil && bottle.length > 0)
|
|
696
|
+
if ENV.has_key?('WINEPREFIX') && ENV['WINEPREFIX'].length > 0
|
|
697
|
+
warn 'WINEPREFIX= was already set, overriding it.'
|
|
698
|
+
end
|
|
699
|
+
if ! (bottle =~ /^\.?\//)
|
|
700
|
+
bottle = ENV['HOME']+'/.wwinebottles/'+bottle
|
|
701
|
+
if !File.exists?(ENV['HOME']+'/.wwinebottles/')
|
|
702
|
+
vputs(ENV['HOME']+'/.wwinebottles/: does not exist, creating')
|
|
703
|
+
begin
|
|
704
|
+
Dir.mkdir(ENV['HOME']+'/.wwinebottles/')
|
|
705
|
+
rescue SystemCallError
|
|
706
|
+
puts('Failed to create directory "'+ENV['HOME']+'/.wwinebottles/'+": "+$!)
|
|
707
|
+
puts('Unable to continue.')
|
|
708
|
+
exit(1)
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
end
|
|
712
|
+
ENV['WINEPREFIX'] = bottle
|
|
713
|
+
vputs('Set WINEPREFIX='+bottle)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# Default to no debugging output if WINEDEBUG is not set yet
|
|
717
|
+
if ! ENV.has_key?('WINEDEBUG')
|
|
718
|
+
vputs 'Set WINEDEBUG=-all'
|
|
719
|
+
ENV['WINEDEBUG'] = '-all'
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
return final
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
# Purpose: Get parameters for crossover
|
|
726
|
+
def getCXwithParams (wine,bottle, missingIsFatal = true)
|
|
727
|
+
final = []
|
|
728
|
+
cxdir = nil
|
|
729
|
+
|
|
730
|
+
# Various crossover install paths
|
|
731
|
+
wines = ['/opt/'+wine, ENV['HOME']+'/'+wine, ENV['HOME']+'/.local/'+wine, ENV['HOME']+'/games/'+wine]
|
|
732
|
+
|
|
733
|
+
# If cxpath is set then overwrite the default paths
|
|
734
|
+
if $cxPath != nil
|
|
735
|
+
wines = [ $cxPath+'/'+wine ]
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
wines.each do |path|
|
|
739
|
+
if File.exists?(path) and File.executable?(path+'/bin/cxstart')
|
|
740
|
+
cxdir = path
|
|
741
|
+
break
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
# If we're using cxPath, perform some additional detection
|
|
746
|
+
if $cxPath != nil
|
|
747
|
+
if File.exists?($cxPath+'/etc/'+wine+'.conf')
|
|
748
|
+
cxdir = $cxPath
|
|
749
|
+
end
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
# If the dir does not exist, give up
|
|
753
|
+
if not cxdir
|
|
754
|
+
if !missingIsFatal
|
|
755
|
+
return nil
|
|
756
|
+
end
|
|
757
|
+
if $cxPath != nil
|
|
758
|
+
puts('Could not find a directory named "'+wine+'" in '+$cxPath)
|
|
759
|
+
puts('and '+$cxPath+' does not appear to be a '+wine+' install directory')
|
|
760
|
+
if wine == 'cxgames'
|
|
761
|
+
reverse = 'cxoffice'
|
|
762
|
+
else
|
|
763
|
+
reverse = 'cxgames'
|
|
764
|
+
end
|
|
765
|
+
if File.exists?($cxPath+'/'+reverse) || File.exists?($cxPath+'/etc/'+reverse+'.conf')
|
|
766
|
+
puts('The directory looks like a '+reverse+' directory. Maybe you wanted')
|
|
767
|
+
puts('--wine '+reverse+' instead?')
|
|
768
|
+
end
|
|
769
|
+
else
|
|
770
|
+
puts('Failed to locate '+wine)
|
|
771
|
+
puts('You could try to explicitly tell wwine where '+wine+' is installed')
|
|
772
|
+
puts('by supplying --cxinstalldir')
|
|
773
|
+
end
|
|
774
|
+
exit(1)
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
final.push(cxdir+'/bin/cxstart')
|
|
778
|
+
if(bottle != nil && bottle.length > 0)
|
|
779
|
+
final.push('--bottle',bottle)
|
|
780
|
+
end
|
|
781
|
+
final.push('--');
|
|
782
|
+
|
|
783
|
+
# Create the bottle if it does not exist
|
|
784
|
+
if bottle != nil and ! File.exists?(ENV['HOME']+'/.'+wine+'/'+bottle)
|
|
785
|
+
puts 'The bottle '+bottle+' did not exist, creating...'
|
|
786
|
+
runcmd([ cxdir+'/bin/cxbottle', '--bottle',bottle,'--create'],'system')
|
|
787
|
+
if ! File.exists?(ENV['HOME']+'/.'+wine+'/'+bottle)
|
|
788
|
+
puts 'Bottle creation failed.'
|
|
789
|
+
exit 1
|
|
790
|
+
end
|
|
791
|
+
end
|
|
792
|
+
|
|
793
|
+
return final
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
# Purpose: Get parameters for cedega
|
|
797
|
+
def getCedegaWithParams (wine,bottle, missingIsFatal = true)
|
|
798
|
+
final = []
|
|
799
|
+
|
|
800
|
+
if not inPath('cedega')
|
|
801
|
+
if missingIsFatal
|
|
802
|
+
puts('cedega does not appear to be installed')
|
|
803
|
+
exit(1)
|
|
804
|
+
else
|
|
805
|
+
return nil
|
|
806
|
+
end
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
final.push('cedega','--install')
|
|
810
|
+
|
|
811
|
+
# Use wwineFolder as the folder if no bottle was supplied
|
|
812
|
+
if (bottle == nil || bottle.length == 0)
|
|
813
|
+
bottle = 'wwineFolder'
|
|
814
|
+
end
|
|
815
|
+
final.push(bottle)
|
|
816
|
+
|
|
817
|
+
return final
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
# Purpose: Detect which wine to use and get parameters for that one
|
|
821
|
+
# Returns: type,cmd
|
|
822
|
+
def getAutoWithParams (bottle, missingIsFatal = true, returnFlavour = false)
|
|
823
|
+
cmd = getWineWithParams('wine',bottle,false)
|
|
824
|
+
type = 'wine'
|
|
825
|
+
if cmd == nil
|
|
826
|
+
cmd = getCXwithParams('cxgames',bottle,false)
|
|
827
|
+
type = 'cxgames'
|
|
828
|
+
end
|
|
829
|
+
if cmd == nil
|
|
830
|
+
cmd = getCXwithParams('cxoffice',bottle,false)
|
|
831
|
+
type = 'cxoffice'
|
|
832
|
+
end
|
|
833
|
+
if cmd == nil
|
|
834
|
+
cmd = getCedegaWithParams('cedega',bottle,false)
|
|
835
|
+
type = 'cedega'
|
|
836
|
+
end
|
|
837
|
+
if cmd == nil
|
|
838
|
+
if missingIsFatal
|
|
839
|
+
puts 'Failed to detect any wine version at all.'
|
|
840
|
+
exit(1)
|
|
841
|
+
else
|
|
842
|
+
return nil
|
|
843
|
+
end
|
|
844
|
+
else
|
|
845
|
+
return type,cmd
|
|
846
|
+
end
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
# Purpose: Run the wine specified, using the bottle specified and arguments specified
|
|
850
|
+
def runWine (wine,bottle,args)
|
|
851
|
+
cmd = nil
|
|
852
|
+
type = nil
|
|
853
|
+
|
|
854
|
+
if wine == nil
|
|
855
|
+
type,cmd = getAutoWithParams(bottle)
|
|
856
|
+
else
|
|
857
|
+
# Expand cxg and cxo
|
|
858
|
+
if wine == 'cxg'
|
|
859
|
+
wine = 'cxgames'
|
|
860
|
+
elsif wine == 'cxo'
|
|
861
|
+
wine = 'cxoffice'
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
type = wine
|
|
865
|
+
|
|
866
|
+
if wine == 'cxgames' || wine == 'cxoffice'
|
|
867
|
+
cmd = getCXwithParams(wine,bottle)
|
|
868
|
+
elsif wine == 'wine' || File.executable?(wine)
|
|
869
|
+
type = 'wine'
|
|
870
|
+
cmd = getWineWithParams(wine,bottle)
|
|
871
|
+
elsif wine == 'cedega'
|
|
872
|
+
cmd = getCedegaWithParams(wine,bottle)
|
|
873
|
+
else
|
|
874
|
+
puts('Unknown --wine: '+wine)
|
|
875
|
+
puts('Must be one of: wine, cxgames, cxoffice, cedega, or the path to a wine executable')
|
|
876
|
+
exit(1)
|
|
877
|
+
end
|
|
878
|
+
end
|
|
879
|
+
cmd.concat(args)
|
|
880
|
+
|
|
881
|
+
# If wrapperPath is set, then we're suppose to generate a wrapper script instead
|
|
882
|
+
# of actually executing it.
|
|
883
|
+
if $wrapperPath != nil
|
|
884
|
+
generateWrapper(wine,bottle,$wrapperPath,cmd,args,type)
|
|
885
|
+
else
|
|
886
|
+
runcmd(cmd)
|
|
887
|
+
end
|
|
888
|
+
end
|
|
889
|
+
|
|
890
|
+
opts = GetoptLong.new(
|
|
891
|
+
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
|
|
892
|
+
[ '--wine', '-w', GetoptLong::REQUIRED_ARGUMENT ],
|
|
893
|
+
[ '--bottle', '-b', GetoptLong::REQUIRED_ARGUMENT ],
|
|
894
|
+
[ '--kill', '-k', GetoptLong::OPTIONAL_ARGUMENT ],
|
|
895
|
+
[ '--drykill', GetoptLong::NO_ARGUMENT ],
|
|
896
|
+
[ '--cxinstalldir','-c',GetoptLong::REQUIRED_ARGUMENT ],
|
|
897
|
+
[ '--version',GetoptLong::NO_ARGUMENT ],
|
|
898
|
+
[ '--wrap', GetoptLong::REQUIRED_ARGUMENT ],
|
|
899
|
+
[ '--wrapdir', GetoptLong::REQUIRED_ARGUMENT ],
|
|
900
|
+
[ '--debuginfo', GetoptLong::NO_ARGUMENT ],
|
|
901
|
+
[ '--man', GetoptLong::NO_ARGUMENT ],
|
|
902
|
+
[ '--from', '-s', GetoptLong::REQUIRED_ARGUMENT ],
|
|
903
|
+
[ '--verbose', '-v', GetoptLong::NO_ARGUMENT ]
|
|
904
|
+
)
|
|
905
|
+
|
|
906
|
+
# Handle command-line arguments
|
|
907
|
+
begin
|
|
908
|
+
opts.each do |opt, arg|
|
|
909
|
+
case opt
|
|
910
|
+
when '--help'
|
|
911
|
+
Help()
|
|
912
|
+
exit(0)
|
|
913
|
+
when '--wine'
|
|
914
|
+
$wine = arg
|
|
915
|
+
when '--bottle'
|
|
916
|
+
$bottle = arg
|
|
917
|
+
when '--verbose'
|
|
918
|
+
$verbose = true
|
|
919
|
+
when '--drykill'
|
|
920
|
+
killWine(true)
|
|
921
|
+
exit(0)
|
|
922
|
+
when '--debuginfo'
|
|
923
|
+
debugInfo()
|
|
924
|
+
when '--kill'
|
|
925
|
+
begin
|
|
926
|
+
killWine(false,arg)
|
|
927
|
+
rescue
|
|
928
|
+
puts "Error while attempting to kill processes: "+$!
|
|
929
|
+
end
|
|
930
|
+
exit(0)
|
|
931
|
+
when '--cxinstalldir'
|
|
932
|
+
$cxPath = arg
|
|
933
|
+
when '--version'
|
|
934
|
+
puts('wwine version '+$version.to_s+' (for wine version info, run wwine --debuginfo)')
|
|
935
|
+
exit(0)
|
|
936
|
+
when '--wrap'
|
|
937
|
+
$wrapperPath = arg
|
|
938
|
+
when '--wrapdir'
|
|
939
|
+
$wrapperCwd = arg
|
|
940
|
+
when '--from'
|
|
941
|
+
$wwineDataFrom = arg
|
|
942
|
+
when '--man'
|
|
943
|
+
showManPage()
|
|
944
|
+
exit(0)
|
|
945
|
+
end
|
|
946
|
+
end
|
|
947
|
+
|
|
948
|
+
if ENV['WWINE_VERBOSE'] != nil && ENV['WWINE_VERBOSE'] == '1'
|
|
949
|
+
puts('--verbose assumed because the environment variable WWINE_VERBOSE is set to 1')
|
|
950
|
+
$verbose = true
|
|
951
|
+
end
|
|
952
|
+
rescue
|
|
953
|
+
puts('See --help for more inforation')
|
|
954
|
+
exit(1)
|
|
955
|
+
end
|
|
956
|
+
|
|
957
|
+
if $wwineDataFrom
|
|
958
|
+
loadWwineDataFromFile($wwineDataFrom)
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
if ARGV.length == 0
|
|
962
|
+
Help()
|
|
963
|
+
exit(1)
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
begin
|
|
967
|
+
runWine($wine,$bottle,ARGV)
|
|
968
|
+
rescue => ex
|
|
969
|
+
handleException(ex)
|
|
970
|
+
end
|