Fix a few font problems with rotated text and non MM_TEXT mapping
[wine/hacks.git] / tools / wineconf
blob8a5e0badf6138ecc989bdb527cde9620f42cbb92
1 #!/usr/bin/perl -w
3 # This program generates wine.conf files on STDOUT.
4 # Copyright (C) 1996 Stephen Simmons
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # NOTES:
22 # This program examines the contents of the DOS filesystems and
23 # attempts to generate a sensible wine.conf file. This is output
24 # to STDOUT.
25 # It reads /etc/fstab to find mounting locations of the hard disk drives
26 # It uses the correct algorithm for ordering DOS drives, with the
27 # exception of the case of multiple drive controller types, where I don't
28 # know what DOS's algorithm is.
29 # It uses find to find all of the win.ini files on any DOS partition
30 # and sorts them by age to guess which is part of the active Windows
31 # installation.
32 # It reads the autoexec.bat file (if found) and records all variable
33 # settings. There are some inaccuracies in its determination.
34 # First, while variables are interpolated properly, no control
35 # structures are supported so calls and execs to other batch files are
36 # ignored, and all variable settings take effect regardless of whether
37 # they would in DOS (i,e., both if and else clauses are read).
38 # This is used to determine the path and temp directories. Duplicate
39 # path directories and path directories that don't exist are thrown
40 # out.
41 # On failing to find C:\AUTOEXEC.BAT, wineconf finds all executables
42 # in the windows directory and subdirectories, and generates an
43 # optimized path statement encompassing all the executables.
44 # Then it also looks for \TEMP and \TMP on all drives taking the first
45 # one it finds.
46 # wineconf doesn't support floppy drives, network drives, printers,
47 # and serial device configuration is hardcoded and not configured for
48 # the machine it runs on. Similarly, spy parameters are hard coded.
50 # It would make sense to incorporate much of the heuristic code in
51 # this program into a library to be shared with a dosemu configuration
52 # program, because it seems that at least some of the same stuff will
53 # be wanted. The program needs to be cleaned up still. A better tmp
54 # search algorithm could be written. A fast option is planned. Less
55 # Linux-dependence is desired. Should look for devices independent
56 # of /etc/fstab; then sanity checks on /etc/fstab can be performed.
58 use Getopt::Long;
59 use File::Basename;
60 use strict;
61 use Carp;
63 GetOptions('windir=s', 'sysdir=s', 'thorough', 'debug:s', 'inifile=s') || &Usage;
65 print "WINE REGISTRY Version 2\n";
66 print ";; All keys relative to \\\\Machine\\\\Software\\\\Wine\\\\Wine\\\\Config\n\n";
67 &ReadFSTAB();
68 &FindWindowsDir();
69 &ReadAutoexecBat();
70 &StandardStuff();
72 sub Usage {
73 print "Usage: $0 <options>\n";
74 # print "-fstab <filename> Location of alternate fstab file\n";
75 print "-windir <filename> Location of windows dir in DOS space\n";
76 print "-thorough Do careful analysis (default)\n";
77 print "-sysdir <filename> Location of systems dir in DOS space\n";
78 print "-inifile <filename> Path to the wine.ini file (by default './wine.ini')\n";
79 # print "-tmpdir <filename> Location of tmp directory\n";
80 print "Generates (to STDOUT) a wine configuration file based on\n";
81 print "/etc/fstab and searching around in DOS directories\n";
82 print "The options above can override certain values\n";
83 print "This should be considered ALPHA code\n";
84 exit(0);
87 sub ReadFSTAB {
88 $::opt_f = $::opt_f ? $::opt_f : '/etc/fstab';
89 open(FSTAB, $::opt_f) || die "Cannot read $::opt_f\n";
90 while(<FSTAB>) {
91 next if /^\s*\#/;
92 next if /^\s*$/;
94 my ($device, $mntpoint, $type, @rest) = split(' ', $_);
95 if ($device !~ m"^/dev/fd") {
96 if ($type eq "msdos" || $type eq "vfat") {
97 push(@::FatDrives, [$device, $mntpoint, $type]);
99 elsif ($type eq "iso9660" ||
100 $mntpoint eq "/cdrom" ||
101 ($device eq '/dev/cdrom' && $type eq 'auto') ) {
102 push(@::CdromDrives, [$device, $mntpoint, 'win95']);
106 if (!@::FatDrives) {
107 warn "ERROR ($0): Cannot find any MSDOS drives.\n";
108 warn "This does not mean you cannot run Wine, but $0\n";
109 warn "cannot help you (yet)\n";
110 exit(1);
112 push(@::UnixDrives, ['', '/tmp', 'hd']);
113 push(@::UnixDrives, ['', '${HOME}', 'network']);
114 my $MagicDrive = 'C';
115 @::FatDrives = sort byDriveOrder @::FatDrives;
116 @::CdromDrives = sort byCdOrder @::CdromDrives;
117 foreach my $FatDrive (@::FatDrives) {
118 print "[Drive $MagicDrive]\n";
119 my $MntPoint = $FatDrive->[1];
120 my $FileSys = $FatDrive->[2];
121 print "\"Path\" = \"$MntPoint\"\n";
122 print "\"Type\" = \"hd\"\n";
123 print "\"Filesystem\" = \"$FileSys\"\n";
124 print "\n";
125 &RegisterDrive($MagicDrive, $FatDrive);
126 if(!&IsMounted($FatDrive->[0])) {
127 warn "WARNING: DOS Drive $MagicDrive (" . $FatDrive->[0] .
128 ") is not mounted\n";
130 $MagicDrive++;
132 foreach my $CdromDrive (@::CdromDrives) {
133 print "[Drive $MagicDrive]\n";
134 my $Device = $CdromDrive->[0];
135 my $MntPoint = $CdromDrive->[1];
136 my $FileSys = $CdromDrive->[2];
137 print "\"Path\" = \"$MntPoint\"\n";
138 print "\"Type\" = \"cdrom\"\n";
139 print "\"Device\" = \"$Device\"\n";
140 print "\"Filesystem\" = \"$FileSys\"\n";
141 print "\n";
142 &RegisterDrive($MagicDrive, $CdromDrive);
143 $MagicDrive++;
145 foreach my $UnixDrive (@::UnixDrives) {
146 print "[Drive $MagicDrive]\n";
147 my $MntPoint = $UnixDrive->[1];
148 my $Type = $UnixDrive->[2];
149 print "\"Path\" = \"$MntPoint\"\n";
150 print "\"Type\" = \"$Type\"\n";
151 print "\"Filesystem\" = \"win95\"\n";
152 print "\n";
153 $MagicDrive++;
157 sub FindWindowsDir {
158 my($MagicDrive) = 'C';
159 my(@FATD)=@::FatDrives;
160 my(@wininis) = ();
161 my ($winini);
162 my ($ThisDrive);
164 if (!$::opt_windir && !$::opt_fast && !$::opt_thorough) {
165 $::opt_thorough++;
167 if ($::opt_windir) {
168 $winini = &ToUnix($::opt_windir);
169 if (!-e $winini) {
170 die "ERROR: Specified winini file does not exist\n";
173 elsif ($::opt_fast) {
174 die "-fast code can be implemented\n";
176 elsif ($::opt_thorough) {
177 if ($::opt_debug) { print STDERR "DEBUG: Num FATD = ", $#FATD+1, "\n"; }
178 foreach $ThisDrive (@FATD) {
179 my $MntPoint = $ThisDrive->[1];
180 push(@wininis, `find $MntPoint -iname win.ini -print`);
182 foreach $winini (@wininis) {
183 chomp $winini;
185 my ($winini_cnt) = $#wininis+1;
186 if ($::opt_debug) {
187 print STDERR "DEBUG: Num wininis found: $winini_cnt\n";}
188 if ($winini_cnt > 1) {
189 warn "$winini_cnt win.ini files found:\n";
190 @wininis = sort byFileAge @wininis;
191 warn join("\n", @wininis), "\n";
192 $winini = $wininis[0];
193 warn "Using most recent one: $winini\n";
195 elsif ($winini_cnt == 0) {
196 die "ERROR: No win.ini found in DOS partitions\n";
198 else {
199 $winini = $wininis[0];
202 else {
203 die "ERROR: None of -windir, -fast, or -thorough set\n";
205 $::windir = &ToDos(dirname($winini));
206 print "[wine]\n";
207 print "\"windows\" = ", &marshall ($::windir), "\n";
208 if ($::opt_sysdir) {
209 print "\"system\" = ", &marshall ($::opt_sysdir), "\n";
211 else {
212 print "\"system\" = ", &marshall ("$::windir\\SYSTEM"), "\n";
216 # Returns 1 if the device is mounted; -1 if mount check failed; 0 if not
217 # mounted.
218 # This code is Linux specific, and needs to be broadened.
219 sub IsMounted {
220 my($Device) = @_;
221 if (-d "/proc") {
222 if (-e "/proc/mounts") {
223 open(MOUNTS, "/proc/mounts") ||
224 (warn "Cannot open /proc/mounts, although it exists\n" &&
225 return -1);
226 while(<MOUNTS>) {
227 if (/^$Device/) {
228 return 1; # Tested 1.4
231 return 0; # Tested 1.4
234 return -1;
237 sub RegisterDrive {
238 my($DOSdrive, $Drive) = @_;
239 $::DOS2Unix{$DOSdrive} = $Drive;
240 $::Device2DOS{$Drive->[0]} = $DOSdrive;
241 $::MntPoint2DOS{$Drive->[1]} = $DOSdrive;
242 $::DOS2MntPoint{$DOSdrive} = $Drive->[1];
243 $::DOS2Device{$DOSdrive} = $Drive->[0];
246 sub ReadAutoexecBat {
247 if (!%::DOS2Unix) { &ReadFSTAB; }
248 my($DriveC) = $::DOS2MntPoint{"C"};
249 $DriveC =~ s%/$%%;
250 my($path);
251 if ($::opt_debug) {
252 print STDERR "DEBUG: Looking for $DriveC/autoexec.bat\n"; }
253 if (-e "$DriveC/autoexec.bat") {
254 # Tested 1.4
255 open(AUTOEXEC, "$DriveC/autoexec.bat") ||
256 die "Cannot read autoexec.bat\n";
257 while(<AUTOEXEC>) {
258 s/\015//;
259 if (/^\s*(set\s+)?(\w+)\s*[\s\=]\s*(.*)$/i) {
260 my($varname) = $2;
261 my($varvalue) = $3;
262 chomp($varvalue);
263 $varname =~ tr/A-Z/a-z/;
264 while ($varvalue =~ /%(\w+)%/) {
265 my $matchname = $1;
266 my $subname = $1;
267 $subname =~ tr/A-Z/a-z/;
268 if (($::opt_debug) && ($::opt_debug =~ /path/i)) {
269 print STDERR "DEBUG: Found $matchname as $subname\n";
270 print STDERR "DEBUG: Old varvalue:\n$varvalue\n";
271 print STDERR "DEBUG: Old subname value:\n" .
272 $::DOSenv{$subname} . "\n";
274 if ($::DOSenv{$subname}) {
275 $varvalue =~ s/\%$matchname\%/$::DOSenv{$subname}/;
277 else {
278 warn "DOS environment variable $subname not\n";
279 warn "defined in autoexec.bat. (Reading config.sys\n";
280 warn "is not implemented.) Using null value\n";
281 $varvalue =~ s/%$matchname%//;
283 if (($::opt_debug) && ($::opt_debug =~ /path/i)) {
284 print STDERR "DEBUG: New varvalue:\n$varvalue\n";
287 if ($::opt_debug) {
288 print STDERR "DEBUG: $varname = $varvalue\n";
290 $::DOSenv{$varname} = $varvalue;
293 close(AUTOEXEC);
295 else {
296 # Tested 1.4
297 warn "WARNING: C:\\AUTOEXEC.BAT was not found.\n";
300 if ($::DOSenv{"path"}) {
301 my @pathdirs = split(/\s*;\s*/, $::DOSenv{"path"});
302 if (($::opt_debug) && ($::opt_debug =~ /path/i)) {
303 print STDERR "DEBUG (path): @pathdirs\n";
305 foreach my $pathdir (@pathdirs) {
306 if (-d &ToUnix($pathdir)) {
307 if ($::DOSpathdir{$pathdir}++) {
308 warn "Ignoring duplicate DOS path entry $pathdir\n";
310 else {
311 if (($::opt_debug) && ($::opt_debug =~ /path/i)) {
312 print STDERR "DEBUG (path): Found $pathdir\n";
314 push(@::DOSpathlist, $pathdir);
317 else {
318 warn "Ignoring DOS path directory $pathdir, as it does not\n";
319 warn "exist\n";
322 print "\"path\" = ", &marshall (join (";", @::DOSpathlist)), "\n";
324 else {
325 # Code status: tested 1.4
326 warn "WARNING: Making assumptions for PATH\n";
327 warn "Will scan windows directory for executables and generate\n";
328 warn "path from that\n";
329 my $shellcmd = 'find ' . &ToUnix($::windir) . " -iregex '" .
330 '.*\.\(exe\|bat\|com\|dll\)' . "' -print";
331 if ($::opt_debug) {
332 print STDERR "DEBUG: autoexec.bat search command:\n $shellcmd\n";
334 push(@::DOScommand, `$shellcmd`);
335 if ($::opt_debug && $::opt_debug =~ /autoexec/i) {
336 print STDERR "DEBUG: autoexec.bat search results:\n\@DOS::command\n";
338 foreach my $command (@::DOScommand) {
339 $command =~ s%[^/]+$%%;
340 $::DOSexecdir{&ToDos($command)}++;
342 print "\"path\" = " .
343 &marshall (join(";",
344 grep(s%\\$%%,
345 sort {$::DOSexecdir{$b} <=> $::DOSexecdir{$a}}
346 (keys %::DOSexecdir)))) . "\n";
349 if ($::DOSenv{"temp"} && -d &ToUnix($::DOSenv{"temp"})) {
350 print "\"temp\" = ", &marshall ($::DOSenv{"temp"}), "\n";
352 else {
353 my $TheTemp;
355 warn "WARNING: Making assumptions for TEMP\n";
356 warn "Looking for \\TEMP and then \\TMP on every drive\n";
357 # Watch out .. might pick CDROM drive :-)
358 foreach my $DOSdrive (keys %::DOS2Unix) {
359 my $tmp = &ToUnix("$DOSdrive:\\temp");
360 if (-d $tmp) { $TheTemp = "$DOSdrive:\\temp"; last; }
361 $tmp = &ToUnix("$DOSdrive:\\tmp");
362 if (-d $tmp) { $TheTemp = "$DOSdrive:\\tmp"; last; }
364 $TheTemp = '/tmp' if (!$TheTemp && -d '/tmp');
365 if ($TheTemp) {
366 warn "Using $TheTemp\n";
367 print "\"temp\" = ", &marshall ($TheTemp), "\n";
369 else {
370 warn "Using C:\\\n";
371 print "\"temp\" = ", &marshall ("C:\\"), "\n";
374 print "\n";
377 # FNunix = &ToUnix(FNdos);
378 # Converts DOS filenames to Unix filenames, leaving Unix filenames
379 # untouched.
380 sub ToUnix {
381 my($FNdos) = @_;
382 my($FNunix);
384 # Initialize tables if necessary.
385 if (!%::DOS2Unix) { &ReadFSTAB; }
387 # Determine which type of conversion is necessary
388 if ($FNdos =~ /^([A-Z])\:(.*)$/) { # DOS drive specified
389 $FNunix = $::DOS2MntPoint{$1} . "/$2";
391 elsif ($FNdos =~ m%\\%) { # DOS drive not specified, C: is default
392 $FNunix = $::DOS2MntPoint{"C"} . "/$FNdos";
394 else { # Unix filename
395 $FNunix = $FNdos;
397 1 while ($FNunix =~ s%\\%/%); # Convert \ to /
398 $FNunix =~ tr/A-Z/a-z/; # Translate to lower case
399 1 while ($FNunix =~ s%//%/%); # Translate double / to /
400 return $FNunix;
403 # FNdos = &ToDOS(FNunix)
404 # Converts Unix filenames to DOS filenames
405 sub ToDos {
406 my($FNunix) = @_;
407 my(@MntList) = keys %::MntPoint2DOS;
408 my ($TheMntPt, $FNdos);
410 foreach my $MntPt (@MntList) { # Scan mount point list to see if path matches
411 if ($FNunix =~ /^$MntPt/) {
412 $TheMntPt = $MntPt;
413 last;
416 if (!$TheMntPt) {
417 Carp("ERROR: $FNunix not found in DOS directories\n");
418 exit(1);
420 $FNdos = $FNunix;
421 $FNdos =~ s/^$TheMntPt//;
422 $FNdos = $::MntPoint2DOS{$TheMntPt} . ":" . $FNdos;
423 1 while($FNdos =~ s%/%\\%);
424 return $FNdos;
427 sub InsertDefaultFile {
428 my ($fileName, $tag) = @_;
429 my $state = 0;
431 if (open(DEFFILE, "$fileName")) {
432 while (<DEFFILE>) {
433 $state = 0 if ($state == 1 && $_ =~ /^[ \t]*\#/o && index($_, "</$tag>") >= 0);
434 print $_ if ($state == 1);
435 $state = 1 if ($state == 0 && $_ =~ /^[ \t]*\#/o && index($_, "<$tag>" ) >= 0);
437 close(DEFFILE);
438 } else {
439 print STDERR "Cannot read $fileName\n";
443 sub marshall {
444 my ($s) = @_;
445 $s =~ s/\\/\\\\/g;
446 return "\"$s\"";
450 sub StandardStuff {
451 if (!$::opt_inifile) {
452 &InsertDefaultFile("./wine.ini", "wineconf");
453 } else {
454 &InsertDefaultFile($::opt_inifile, "wineconf");
458 sub byFileAge {
459 -M $a <=> -M $b;
462 sub byDriveOrder {
463 my($DeviceA) = $a->[0];
464 my($DeviceB) = $b->[0];
466 # Primary drives come first, logical drives last
467 # DOS User's Guide (version 6) p. 70, IBM version.
468 # If both drives are the same type, sort alphabetically
469 # This makes drive a come before b, etc.
470 # It also makes SCSI drives come before IDE drives;
471 # this may or may not be right :-(
472 my($Alogical, $Blogical);
473 if (substr($DeviceA, 3, 1) >= 5) { $Alogical++; }
474 if (substr($DeviceB, 3, 1) >= 5) { $Blogical++; }
475 if ($Alogical && !$Blogical) { return -1; }
476 elsif ($Blogical && !$Alogical) { return 1; }
477 else { return ($DeviceA cmp $DeviceB); }
480 sub byCdOrder {
481 my($DeviceA) = $a->[0];
482 my($DeviceB) = $b->[0];
483 $DeviceA cmp $DeviceB;