#!/usr/bin/perl
# $Id: segopts,v 1.0 92/07/31 17:39:51 cap Exp $
# This program gives you direct access to the fields of the
# struct segment_command's in a Mach-O file. This is dangerous
# because you can make the resulting file inconsistent.
#
$usagestring="Usage: segopts\t\t\tDescription of option:
       -segname name		name of the segment to operate on
       [-cmd n]			change this to another command!
       [-cmdsize n]		set the command size
       [-newsegname name]	change the segment name to name
       [-vmaddr n]		set the memory address
       [-vmsize n]		set the memory size
       [-fileoff n]		set the file offset
       [-filesize n]		set the file size
       [-maxprot n]		set the maximum VM protection
       [-initprot n]		set the initial VM protection
       [-nsects n]		set the number of sections
       [-flags n]		set the flags
       filename			executable program to change

In the above, the character n represents a number, which may be input
in decimal, octal, or hexadecimal, using C's notation. The -segname option
must be present. Any fields that are not speficied with options retain
their original values.\n";

require 'newgetopt.pl';
require 'mach-o.pl';
do NGetOpt("cmd=s",
	   "cmdsize=s",
	   "segname=s",
	   "newsegname=s",
	   "vmaddr=s",
	   "vmsize=s",
	   "fileoff=s",
	   "filesize=s",
	   "maxprot=s",
	   "initprot=s",
	   "nsects=s",
	   "flags=s");

if ($#ARGV != 0) {
    die $usagestring;
} elsif (!$opt_segname) {
    print STDERR "You must specify a segment name with -segname.\n";
    die $usagestring;
}
$file = $ARGV[0];
# parse non-decimal arguments
$opt_cmd = oct($opt_cmd) if ($opt_cmd && $opt_cmd =~ /^0/);
$opt_cmdsize = oct($opt_cmdsize) if ($opt_cmdsize && $opt_cmdsize =~ /^0/);
$opt_vmaddr = oct($opt_vmaddr) if ($opt_vmaddr && $opt_vmaddr =~ /^0/);
$opt_vmsize = oct($opt_vmsize) if ($opt_vmsize && $opt_vmsize =~ /^0/);
$opt_fileoff = oct($opt_fileoff) if ($opt_fileoff && $opt_fileoff =~ /^0/);
$opt_filesize = oct($opt_filesize) if ($opt_filesize && $opt_filesize =~ /^0/);
$opt_maxprot = oct($opt_maxprot) if ($opt_maxprot && $opt_maxprot =~ /^0/);
$opt_initprot = oct($opt_initprot) if ($opt_initprot && $opt_initprot =~ /^0/);
$opt_nsects = oct($opt_nsects) if ($opt_nsects && $opt_nsects =~ /^0/);
$opt_flags = oct($opt_flags) if ($opt_flags && $opt_flags =~ /^0/);

open(FILE, "+<$file") || die "Can't open input file $file\n";

($cmd, $cmdsize, $segname, $vmaddr, $vmsize, $fileoff, $filesize,
 $maxprot, $initprot, $nsects, $flags) = &segment_info(FILE, $opt_segname);

if ($segname ne $opt_segname) {
    die "Couldn't locate segment $opt_segname in $file.\n";
} else {
    # back up over what we just read
    seek(FILE, -$sizeof_segment_command, 1);
    # change any values that the user specified on the command line
    $cmd = $opt_cmd if $opt_cmd;
    $cmdsize = $opt_cmdsize if $opt_cmdsize;
    $segname = $opt_newsegname if $opt_newsegname;
    $vmaddr = $opt_vmaddr if $opt_vmaddr;
    $vmsize = $opt_vmsize if $opt_vmsize;
    $fileoff = $opt_fileoff if $opt_fileoff;
    $filesize = $opt_filesize if $opt_filesize;
    $maxprot = $opt_maxprot if $opt_maxprot;
    $initprot = $opt_initprot if $opt_initprot;
    $nsects = $opt_nsects if $opt_nsects;
    $flags = $opt_flags if $opt_flags;

    &write_segment_command(FILE, ($cmd, $cmdsize, $segname, $vmaddr,
				  $vmsize, $fileoff, $filesize, $maxprot,
				  $initprot, $nsects, $flags));
}

close(FILE);
