Release 961023
[wine/multimedia.git] / tools / wineconf
blob9610366e13bd68e55f94a843050602b16a1645d1
1 #!/usr/bin/perl
3 # This program generates wine.conf files on STDOUT.
4 # (C) 1996 Stephen Simmons
5 # Redistributable under Wine License
7 $RCS_ID = '$Id$ ';
9 # This program examines the contents of the DOS filesystems and
10 # attempts to generate a sensible wine.conf file. This is output
11 # to STDOUT.
12 # It reads /etc/FSTAB to find mounting locations of the hard disk drives
13 # It uses the correct algorithm for ordering DOS drives, with the
14 # exception of the case of multiple drive controller types, where I don't
15 # know what DOS's algorithm is.
16 # It uses find to find all of the win.ini files on any DOS partition
17 # and sorts them by age to guess which is part of the active Windows
18 # installation.
19 # It reads the autoexec.bat file (if found) and records all variable
20 # settings. There are some inaccuracies in its determination.
21 # First, while variables are interpolated properly, no control
22 # structures are supported so calls and execs to other batch files are
23 # ignored, and all variable settings take effect regardless of whether
24 # they would in DOS (i,e., both if and else clauses are read).
25 # This is used to determine the path and temp directories. Duplicate
26 # path directories and path directories that don't exist are thrown
27 # out.
28 # On failing to find C:\AUTOEXEC.BAT, wineconf finds all executables
29 # in the windows directory and subdirectories, and generates an
30 # optimized path statement encompassing all the executables.
31 # Then it also looks for \TEMP and \TMP on all drives taking the first
32 # one it finds.
33 # wineconf doesn't support floppy drives, network drives, printers,
34 # and serial device configuration is hardcoded and not configured for
35 # the machine it runs on. Similarly, spy parameters are hard coded.
37 # It would make sense to incorporate much of the hueristic code in
38 # this program into a library to be shared with a dosemu configuration
39 # program, because it seems that at least some of the same stuff will
40 # be wanted. The program needs to be cleaned up still. A better tmp
41 # search algorithm could be written. A fast option is planned. Less
42 # Linux-dependence is desired. Should look for devices independent
43 # of /etc/fstab; then sanity checks on /etc/fstab can be performed.
45 use Getopt::Long;
46 use File::Basename;
47 use Carp;
49 GetOptions('windir=s', 'sysdir=s', 'thorough', 'debug:s') || &Usage;
51 &ReadFSTAB();
52 &FindWindowsDir();
53 &ReadAutoexecBat();
54 &StandardStuff();
56 sub Usage {
57 print "Usage: $0 <options>\n";
58 # print "-fstab <filename> Location of alternate fstab file\n";
59 print "-windir <filename> Location of windows dir in DOS space\n";
60 print "-thorough Do careful analysis (default)\n";
61 print "-sysdir <filename> Location of systems dir in DOS space\n";
62 # print "-tmpdir <filename> Location of tmp directory\n";
63 print "Generates (to STDOUT) a wine configuration file based on\n";
64 print "/etc/fstab and searching around in DOS directories\n";
65 print "The options above can override certain values\n";
66 print "This should be considered ALPHA code\n";
67 exit(0);
70 sub ReadFSTAB {
71 $opt_f = $opt_f ? $opt_f : '/etc/fstab';
72 open(FSTAB, $opt_f) || die "Cannot read $opt_f\n";
73 while(<FSTAB>) {
74 next if /^\s*\#/;
75 next if /^\s*$/;
76 ($device, $mntpoint, $type, @rest) = split(' ', $_);
77 if ($type eq "msdos") {
78 push(@FatDrives, [$device, $mntpoint]);
80 elsif ($type eq "iso9660") {
81 push(@CdromDrives, [$device, $mntpoint]);
84 if (!@FatDrives) {
85 warn "ERROR ($0): Cannot find any MSDOS drives.\n";
86 warn "This does not mean you cannot run Wine, but $0\n";
87 warn "cannot help you (yet)\n";
88 exit(1);
90 $MagicDrive = 'C';
91 @FatDrives = sort byDriveOrder @FatDrives;
92 @CdromDrives = sort byCdOrder @CdromDrives;
93 foreach $FatDrive (@FatDrives) {
94 print "[Drive $MagicDrive]\n";
95 $MntPoint = $FatDrive->[1];
96 print "Path=$MntPoint\n";
97 print "Type=hd\n";
98 print "\n";
99 &RegisterDrive($MagicDrive, $FatDrive);
100 if(!&IsMounted($FatDrive->[0])) {
101 warn "WARNING: DOS Drive $MagicDrive (" . $FatDrive->[0] .
102 ") is not mounted\n";
104 $MagicDrive++;
106 foreach $CdromDrive (@CdromDrives) {
107 print "[Drive $MagicDrive]\n";
108 $MntPoint = $CdromDrive->[1];
109 print "Path=$MntPoint\n";
110 print "Type=cdrom\n";
111 print "\n";
112 &RegisterDrive($MagicDrive, $CdromDrive);
113 $MagicDrive++;
117 sub FindWindowsDir {
118 my($MagicDrive) = 'C';
119 my(@FATD)=@FatDrives;
120 my(@wininis) = ();
121 if (!$opt_windir && !$opt_fast && !$opt_thorough) {
122 $opt_thorough++;
124 if ($opt_windir) {
125 $winini = &ToUnix($opt_windir);
126 if (!-e $winini) {
127 die "ERROR: Specified winini file does not exist\n";
130 elsif ($opt_fast) {
131 die "-fast code can be implemented\n";
133 elsif ($opt_thorough) {
134 if ($opt_debug) { print STDERR "DEBUG: Num FATD = ", $#FATD+1, "\n"; }
135 foreach(@FATD) {
136 $ThisDrive = shift(@FATD);
137 $MntPoint = $ThisDrive->[1];
138 push(@wininis, `find $MntPoint -name win.ini -print`);
140 foreach $winini (@wininis) {
141 chomp $winini;
143 my($winini_cnt) = $#wininis+1;
144 if ($opt_debug) {
145 print STDERR "DEBUG: Num wininis found: $winini_cnt\n";}
146 if ($winini_cnt > 1) {
147 warn "$winini_cnt win.ini files found:\n";
148 @wininis = sort byFileAge @wininis;
149 warn join("\n", @wininis), "\n";
150 $winini = $wininis[0];
151 warn "Using most recent one: $winini\n";
153 elsif ($winini_cnt == 0) {
154 die "ERROR: No win.ini found in DOS partitions\n";
156 else {
157 $winini = $wininis[0];
160 else {
161 die "ERROR: None of -windir, -fast, or -thorough set\n";
163 $windir = &ToDos(dirname($winini));
164 print "[wine]\n";
165 print "windows=$windir\n";
166 if ($opt_sysdir) {
167 print "system=$opt_sysdir\n";
169 else {
170 print "system=$windir\\SYSTEM\n";
174 # Returns 1 if the device is mounted; -1 if mount check failed; 0 if not
175 # mounted.
176 # This code is Linux specific, and needs to be broadened.
177 sub IsMounted {
178 my($Device) = @_;
179 if (-d "/proc") {
180 if (-e "/proc/mounts") {
181 open(MOUNTS, "/proc/mounts") ||
182 (warn "Cannot open /proc/mounts, although it exists\n" &&
183 return -1);
184 while(<MOUNTS>) {
185 if (/^$Device/) {
186 return 1; # Tested 1.4
189 return 0; # Tested 1.4
192 return -1;
195 sub RegisterDrive {
196 my($DOSdrive, $Drive) = @_;
197 $DOS2Unix{$DOSdrive} = $Drive;
198 $Device2DOS{$Drive->[0]} = $DOSdrive;
199 $MntPoint2DOS{$Drive->[1]} = $DOSdrive;
200 $DOS2MntPoint{$DOSdrive} = $Drive->[1];
201 $DOS2Device{$DOSdrive} = $Drive->[0];
204 sub ReadAutoexecBat {
205 if (!%DOS2Unix) { &ReadFSTAB; }
206 my($DriveC) = $DOS2MntPoint{"C"};
207 $DriveC =~ s%/$%%;
208 my($path);
209 if ($opt_debug) {
210 print STDERR "DEBUG: Looking for $DriveC/autoexec.bat\n"; }
211 if (-e "$DriveC/autoexec.bat") {
212 # Tested 1.4
213 open(AUTOEXEC, "$DriveC/autoexec.bat") ||
214 die "Cannot read autoexec.bat\n";
215 while(<AUTOEXEC>) {
216 s/\015//;
217 if (/^\s*(set\s+)?(\w+)\s*[\s\=]\s*(.*)$/i) {
218 my($varname) = $2;
219 my($varvalue) = $3;
220 chomp($varvalue);
221 $varname =~ tr/A-Z/a-z/;
222 while ($varvalue =~ /%(\w+)%/) {
223 $matchname = $subname = $1;
224 $subname =~ tr/A-Z/a-z/;
225 if ($opt_debug =~ /path/i) {
226 print STDERR "DEBUG: Found $matchname as $subname\n";
227 print STDERR "DEBUG: Old varvalue:\n$varvalue\n";
228 print STDERR "DEBUG: Old subname value:\n" .
229 $DOSenv{$subname} . "\n";
231 if ($DOSenv{$subname}) {
232 $varvalue =~ s/\%$matchname\%/$DOSenv{$subname}/;
234 else {
235 warn "DOS environment variable $subname not\n";
236 warn "defined in autoexec.bat. (Reading config.sys\n";
237 warn "is not implemented.) Using null value\n";
238 $varvalue =~ s/%$matchname%//;
240 if ($opt_debug =~ /path/i) {
241 print STDERR "DEBUG: New varvalue:\n$varvalue\n";
244 if ($opt_debug) {
245 print STDERR "DEBUG: $varname = $varvalue\n";
247 $DOSenv{$varname} = $varvalue;
250 close(AUTOEXEC);
252 else {
253 # Tested 1.4
254 warn "WARNING: C:\AUTOEXEC.BAT was not found.\n";
257 if ($DOSenv{"path"}) {
258 @pathdirs = split(/\s*;\s*/, $DOSenv{"path"});
259 if ($opt_debug =~ /path/i) {
260 print STDERR "DEBUG (path): @pathdirs\n";
262 foreach $pathdir (@pathdirs) {
263 if (-d &ToUnix($pathdir)) {
264 if ($DOSpathdir{$pathdir}++) {
265 warn "Ignoring duplicate DOS path entry $pathdir\n";
267 else {
268 if ($opt_debug =~ /path/i) {
269 print STDERR "DEBUG (path): Found $pathdir\n";
271 push(@DOSpathlist, $pathdir);
274 else {
275 warn "Ignoring DOS path directory $pathdir, as it does not\n";
276 warn "exist\n";
279 print "path=" . join(";", @DOSpathlist) . "\n";
281 else {
282 # Code status: tested 1.4
283 warn "WARNING: Making assumptions for PATH\n";
284 warn "Will scan windows directory for executables and generate\n";
285 warn "path from that\n";
286 $shellcmd = 'find ' . &ToUnix($windir) . " -iregex '" .
287 '.*\.\(exe\|bat\|com\|dll\)' . "' -print";
288 if ($opt_debug) {
289 print STDERR "DEBUG: autoexec.bat search command:\n $shellcmd\n";
291 push(@DOScommand, `$shellcmd`);
292 if ($opt_debug =~ /autoexec/i) {
293 print STDERR "DEBUG: autoexec.bat search results:\n@DOScommand\n";
295 foreach $command (@DOScommand) {
296 $command =~ s%[^/]+$%%;
297 $DOSexecdir{$command}++;
299 print "path=" .
300 join(";",
301 grep(s%/$%%,
302 sort {$DOSexecdir{$b} <=> $DOSexecdir{$a}}
303 (keys %DOSexecdir))) . "\n";
306 if ($DOSenv{"temp"} && -d &ToUnix($DOSenv{"temp"})) {
307 print "temp=" . $DOSenv{"temp"} . "\n";
309 else {
310 warn "WARNING: Making assumptions for TEMP\n";
311 warn "Looking for \\TEMP and then \\TMP on every drive\n";
312 # Watch out .. might pick CDROM drive :-)
313 foreach $DOSdrive (keys %DOS2Unix) {
314 $tmp = &ToUnix("$DOSdrive:\\temp");
315 if (-d $tmp) { $TheTemp = "$DOSdrive:\\temp"; last; }
316 $tmp = &ToUnix("$DOSdrive:\\tmp");
317 if (-d $tmp) { $TheTemp = "$DOSdrive:\\tmp"; last; }
319 if ($TheTemp) {
320 warn "Using $TheTemp\n";
321 print "temp=$TheTemp\n";
323 else {
324 warn "Using C:\\\n";
325 print "temp=C:\\\n";
328 print "\n";
331 # FNunix = &ToUnix(FNdos);
332 # Converts DOS filenames to Unix filenames, leaving Unix filenames
333 # untouched.
334 sub ToUnix {
335 my($FNdos) = @_;
336 my($FNunix);
338 # Initialize tables if necessary.
339 if (!%DOS2Unix) { &ReadFSTAB; }
341 # Determine which type of conversion is necessary
342 if ($FNdos =~ /^([A-Z])\:(.*)$/) { # DOS drive specified
343 $FNunix = $DOS2MntPoint{$1} . "/$2";
345 elsif ($FNdos =~ m%\\%) { # DOS drive not specified, C: is default
346 $FNunix = $DOS2MntPoint{"C"} . "/$FNdos";
348 else { # Unix filename
349 $FNunix = $FNdos;
351 1 while ($FNunix =~ s%\\%/%); # Convert \ to /
352 $FNunix =~ tr/A-Z/a-z/; # Translate to lower case
353 1 while ($FNunix =~ s%//%/%); # Translate double / to /
354 return $FNunix;
357 # FNdos = &ToDOS(FNunix)
358 # Converts Unix filenames to DOS filenames
359 sub ToDos {
360 my($FNunix) = @_;
361 my(@MntList) = keys %MntPoint2DOS;
362 foreach $MntPt (@MntList) { # Scan mount point list to see if path matches
363 if ($FNunix =~ /^$MntPt/) {
364 $TheMntPt = $MntPt;
365 last;
368 if (!$TheMntPt) {
369 Carp("ERROR: $FNunix not found in DOS directories\n");
370 exit(1);
372 $FNdos = $FNunix;
373 $FNdos =~ s/^$TheMntPt//;
374 $FNdos = $MntPoint2DOS{$TheMntPt} . ":" . $FNdos;
375 1 while($FNdos =~ s%/%\\%);
376 return $FNdos;
380 sub StandardStuff {
381 print "[serial]\n";
382 print "com1=/dev/cua0\n";
383 print "com2=/dev/cua1\n";
384 print "\n";
385 print "[spy]\n";
386 print ";File=CON\n";
387 print ";File=spy.log\n";
388 print "Exclude=WM_TIMER;WM_SETCURSOR;WM_MOUSEMOVE;WM_NCHITTEST;\n";
389 print "Include=WM_COMMAND;\n";
392 sub byFileAge {
393 -M $a <=> -M $b;
396 sub byDriveOrder {
397 my($DeviceA) = $a->[0];
398 my($DeviceB) = $b->[0];
400 # Primary drives come first, logical drives last
401 # DOS User's Guide (version 6) p. 70, IBM version.
402 # If both drives are the same type, sort alphabetically
403 # This makes drive a come before b, etc.
404 # It also makes SCSI drives come before IDE drives;
405 # this may or may not be right :-(
406 my($Alogical, $Blogical);
407 if (substr($DeviceA, 3, 1) >= 5) { $Alogical++; }
408 if (substr($DeviceB, 3, 1) >= 5) { $Blogical++; }
409 if ($Alogical && !$Blogical) { return -1; }
410 elsif ($Blogical && !$Alogical) { return 1; }
411 else { return ($DeviceA cmp $DeviceB); }
414 sub byCdOrder {
415 my($DeviceA) = $a->[0];
416 my($DeviceB) = $b->[0];
417 $DeviceA cmp $DeviceB;