Article 2946 of comp.lang.perl:
Xref: feenix.metronet.com comp.lang.perl:2946
Newsgroups: comp.lang.perl
Path: feenix.metronet.com!news.utdallas.edu!wupost!uunet!mcsun!sun4nl!eur.nl!evas
From: evas@cs.few.eur.nl (Eelco van Asperen)
Subject: Re: DOS: Script to edit WIN.INI?
Message-ID: <1993May24.140349.9132@cs.few.eur.nl>
Sender: news@cs.few.eur.nl
Organization: Erasmus Universiteit Rotterdam
References: <98273@hydra.gatech.EDU>
Date: Mon, 24 May 1993 14:03:49 GMT
Lines: 161

ce1zzes@prism.gatech.EDU (Eric Sheppard) writes:
>I manage a large lab of PC computers, and occasionally need to make global
>changes in their local configuration files.  The best way for me to do this
>automatically is through a master centralized script.  I've been successful
>so far with a unix-like SED to make simple changes, but editing the WIN.INI
>file is a bit trickier.  There are identical parameter names that require
>different information in different sections. For example, in the [boot]
>section, the network.drv item requires the driver file name, but the [info]
>section has a descriptive string for network.drv.  I'd also like it to add
>lines to sections if they don't already exist.  I'll bet that perl can do 
>this kind of task easily, but I don't yet know how to program perl very well.

>Could anyone offer some pointers to help me get started?

Here's some code I use in scripts to install/uninstall Windows software on pc's
in our network (btw, when is Microsoft going to realize that maintaining
Windows pc's is just about impossible and when will they do something about it...).

In the script, an array is defined that contains a list of entries to change
in the INI file. The operation can be "S" (set) or "D" (delete).
Here's an example from a script to install Paradox for Windows;

	$win = "c:\\windows";
	print "[updating Windows configuration file...]\n" if $verbose;

	local($ftab) = 4;		# number of fields per entry
	local(@tab) = (
	# section     entry  op   value
	# op: Set, Delete
	"Extensions", "DB", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.DB",
	"Extensions", "DBF", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.DBF",
	"Extensions", "FDL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.FDL",
	"Extensions", "FSL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.FSL",
	"Extensions", "LSL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.LSL",
	"Extensions", "RDL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.RDL",
	"Extensions", "RSL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.RSL",
	"Extensions", "SDL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.SDL",
	"Extensions", "SSL", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.SSL",
	"Extensions", "QBE", "S", "I:\\APP\\WIN\\PDW10\\PDOXWIN.EXE ^.QBE",

	"PDOXWIN", "WORKDIR", "S", "C:\\tmp",
	"PDOXWIN", "PRIVDIR", "S", "C:\\tmp",

	"ODAPI", "CONFIGFILE01", "S", "I:\\APP\\WIN\\PDW10\\ODAPI.CFG"
	);

	&update_winfile(1, ${win} . "\\win.ini", $ftab, *tab);

This would add entries like
	DB=I:\APP\WIN\PDW10\PDOXWIN.EXE ^.DB
to the [Extensions] section.
If the section does not exist, it is added at the end of the file.
The update_winfile() routine modifies the array to keep track of which 
entries it has already handled so you can't use it after the call to
update_winfile().

Here's the routine that does the hard work; I've just lifted it from
the source file so there may some missing variables or routines but it
should at least give you a general feeling for the thing.

sub update_winfile {
	local($keepbackup, $fname, $ftab, *tab) = @_;

#	if ($debug) {
#		open(INI, ">&STDOUT");
#		open(BAK, $fname) || die "could not open ${fname} file";
#	} else
	{
		local($bak) = $fname;
		if ($keepbackup) {
			$bak =~ s/\.ini$/\.in0$/;
		} else {
			$bak =~ s/\.ini$/\.___$/;
		}
		# delete previous backups, if any:
		if (-f $bak) {
			print "[a previous backup of $fname will be erased]\n"
				if $keepbackup;
			unlink($bak);
		}
		rename($fname, $bak) || die "could not rename ${fname} file";

		open(BAK, $bak) || die "could not open ${bak} file";
		open(INI, ">" . $fname) || die "could not create ${fname} file";

		undef $bak if $keepbackup;
	}

	$ext = 0;
	$section = "";
line:
	while (<BAK>) {
		if (/^\[(.+)\]/) {
			#
			# "[Header]" -- Section Header
			#
			if ($section ne "") {
				for ($i = 0; $i < $#tab; $i += $ftab) {
					if ($section eq $tab[$i]
					&& $tab[$i+2] eq "S") {
						&winf($tab[$i+1], "", $tab[$i+2], $tab[$i+3]);
						undef $tab[$i];
						$tab[$i] = "";
					}
				}
				print INI "\n";
			}
			$section = $1;
			print "section is now $section\n" if $debug > 1;
		} elsif (/^(.+)=(.*)$/) {
			#
			# "key=value" -- Data Line
			#
			for ($i = 0; $i < $#tab; $i += $ftab) {
				if ($section eq $tab[$i]
				&& $tab[$i+1] eq $1) {
					&winf($1, $2, $tab[$i+2], $tab[$i+3]);
					undef $tab[$i];
					$tab[$i] = "";
					next line;
				}
			}

		}
		print INI $_ if length > 1;
	}

	#
	# Are there sections we should add ?
	#
	$section = "";
	for ($i = 0; $i < $#tab; $i += $ftab) {
		if (length($tab[$i]) > 0 && $tab[$i+2] eq "S") {
			if ($tab[$i] ne $section) {
				$section = $tab[$i];
				print INI "\n[$section]\n";
			}
			&winf($tab[$i+1], "", $tab[$i+2], $tab[$i+3]);
		}
	}

	close(BAK);
	close(INI);
	unlink($bak) if ! $keepbackup;
}

sub winf {
	local($key,$oldvalue,$op,$arg) = @_;

	print STDERR "winf: $section $1: op=$op arg=$arg\n" if $debug > 1;
	if ($op eq "S") {
		print INI "$key=$arg\n";
	} elsif ($op eq "D") {
		#ignore
	}
}

-- 
Eelco van Asperen.           | Erasmus University Rotterdam
-----------------------------| Department of Computer Science, room H4-32
internet: evas@cs.few.eur.nl | PObox 1738, 3000 DR Rotterdam, The Netherlands


