From d1b995e771fa9dcce215313dcd495e3d7f7e5037 Mon Sep 17 00:00:00 2001 From: Warren Toomey Date: Thu, 10 Mar 2016 12:46:00 +1000 Subject: [PATCH] I've written more of mkfs7 but not tested it yet. --- tools/mkfs7 | 569 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 351 insertions(+), 218 deletions(-) diff --git a/tools/mkfs7 b/tools/mkfs7 index fb90f04..65399bc 100755 --- a/tools/mkfs7 +++ b/tools/mkfs7 @@ -7,128 +7,133 @@ use strict; use warnings; use Data::Dumper; +use Getopt::Long qw(GetOptions); + +Getopt::Long::Configure qw(gnu_getopt); # Constants -use constant NUMBLOCKS => 8000; # Number of blocks on a surface -use constant WORDSPERBLK => 64; # 64 words per block -use constant NUMINODEBLKS => 710; # Blocks 1 to 710 for i-nodes -use constant FIRSTINODEBLK => 1; # First i-node block number -use constant INODESIZE => 12; # Size of an i-node -use constant INODESPERBLK => WORDSPERBLK/INODESIZE; -use constant DIRENTSIZE => 8; # Size of an directory entry -use constant DIRENTSPERBLK => WORDSPERBLK/DIRENTSIZE; +use constant NUMBLOCKS => 8000; # Number of blocks on a surface +use constant WORDSPERBLK => 64; # 64 words per block +use constant NUMINODEBLKS => 710; # Blocks 1 to 710 for i-nodes +use constant FIRSTINODEBLK => 1; # First i-node block number +use constant INODESIZE => 12; # Size of an i-node +use constant INODESPERBLK => WORDSPERBLK / INODESIZE; +use constant DIRENTSIZE => 8; # Size of an directory entry +use constant DIRENTSPERBLK => WORDSPERBLK / DIRENTSIZE; -use constant ROOT_UID => -1; # Native root user-id -use constant MAXINT => 0777777; # Biggest unsigned integer +use constant ROOT_UID => -1; # Native root user-id +use constant MAXINT => 0777777; # Biggest unsigned integer -use constant DD_INUM => 2; # I-number of the dd directory +use constant DD_INUM => 2; # I-number of the dd directory # i-node field offsets -use constant I_FLAGS => 0; +use constant I_FLAGS => 0; use constant I_DISKPS => 1; -use constant I_UID => 8; -use constant I_NLKS => 9; -use constant I_SIZE => 10; -use constant I_UNIQ => 11; +use constant I_UID => 8; +use constant I_NLKS => 9; +use constant I_SIZE => 10; +use constant I_UNIQ => 11; -use constant I_NUMBLKS => 7; # Seven block pointers in i-node +use constant I_NUMBLKS => 7; # Seven block pointers in i-node # i-node flag masks -use constant I_USED => 0400000; -use constant I_LARGE => 0200000; -use constant I_SPECIAL => 0000040; -use constant I_DIRECTORY => 0000020; -use constant I_OWNERREAD => 0000010; +use constant I_USED => 0400000; +use constant I_LARGE => 0200000; +use constant I_SPECIAL => 0000040; +use constant I_DIRECTORY => 0000020; +use constant I_FILE => 0000000; +use constant I_OWNERREAD => 0000010; use constant I_OWNERWRITE => 0000004; -use constant I_WORLDREAD => 0000010; +use constant I_WORLDREAD => 0000010; use constant I_WORLDWRITE => 0000004; # Directory field offsets -use constant D_INUM => 0; -use constant D_NAME => 1; -use constant D_UNIQ => 5; -use constant D_NUMWORDS => 8; # Eight words in a direntry - +use constant D_INUM => 0; +use constant D_NAME => 1; +use constant D_UNIQ => 5; +use constant D_NUMWORDS => 8; # Eight words in a direntry # Globals -my $debug=0; -my @Block; # Array of blocks and words in each block -my $nextblknum= NUMINODEBLKS+1; # Next free block number -my $nextinum= 1; # i-num 0 is never used -my @Dirstack; # Stack of directories. Each value is a ref - # to a [ blocknum, offset, inum ] array which - # is the next free position in the directory +my $debug = 0; +my @Block; # Array of blocks and words in each block +my $nextblknum = NUMINODEBLKS + 1; # Next free block number +my $nextinum = 1; # i-num 0 is never used +my @Dirstack; # Stack of directories. Each value is a ref + # to a [ blocknum, offset, inum ] array which + # is the next free position in the directory # Debug printing sub dprint { - print(@_) if ($debug); -} -sub dprintf { - printf(@_) if ($debug); + print(@_) if ($debug); } +sub dprintf { + printf(@_) if ($debug); +} # Given a size in words, allocate and return a set of block numbers # for the entity sub allocate_blocks { - my $numwords= shift; - my @blklist; + my $numwords = shift; + my @blklist; - my $numblocks= int( ($numwords+WORDSPERBLK-1) / WORDSPERBLK ); - die("Not enough blocks\n") if (($nextblknum+$numblocks) >= NUMBLOCKS); - foreach my $b (1 .. $numblocks) { - push(@blklist, $nextblknum++); - } - dprint("Allocated blocks for size $numwords: $blklist[0] .. $blklist[-1]\n"); - return(@blklist); + my $numblocks = int( ( $numwords + WORDSPERBLK - 1 ) / WORDSPERBLK ); + die("Not enough blocks\n") if ( ( $nextblknum + $numblocks ) >= NUMBLOCKS ); + foreach my $b ( 1 .. $numblocks ) { + push( @blklist, $nextblknum++ ); + } + dprint( + "Allocated blocks for size $numwords: $blklist[0] .. $blklist[-1]\n"); + return (@blklist); } # Allocate and return either the specified i-node or the next # available one if there is no argument sub allocate_inode { - my $inum= shift; - return($nextinum++) if (!defined($inum)); - die("i-num $inum already allocated\n") if ($inum< $nextinum); - $nextinum= $inum+1; - return($inum); + my $inum = shift; + return ( $nextinum++ ) if ( !defined($inum) ); + die("i-num $inum already allocated\n") if ( $inum < $nextinum ); + $nextinum = $inum + 1; + return ($inum); } # Given a list of block numbers, allocate a set of indirect blocks # and install block pointers into the indirect blocks. Return the # list of indirect block numbers. sub build_indirect_blocks { - my @blklist= @_; - my $blkcount= @blklist; + my @blklist = @_; + my $blkcount = @blklist; - # Divide the number of data blocks by WORDSPERBLK and round up, so - # we know how many indirect blocks to allocate. - my $indcount= int(($blkcount+WORDSPERBLK-1)/WORDSPERBLK); + # Divide the number of data blocks by WORDSPERBLK and round up, so + # we know how many indirect blocks to allocate. + my $indcount = int( ( $blkcount + WORDSPERBLK - 1 ) / WORDSPERBLK ); - # Get enough indirect blocks - my @indlist= allocate_blocks($indcount); + # Get enough indirect blocks + my @indlist = allocate_blocks($indcount); - # Now fill in the pointers - my $indblock= $indlist[0]; - my $offset= 0; - foreach my $datablock (@blklist) { - $Block[$indblock][$offset++]= $datablock; - if ($offset == WORDSPERBLK) { - $offset=0; $indblock++; + # Now fill in the pointers + my $indblock = $indlist[0]; + my $offset = 0; + foreach my $datablock (@blklist) { + $Block[$indblock][ $offset++ ] = $datablock; + if ( $offset == WORDSPERBLK ) { + $offset = 0; + $indblock++; + } } - } - # Return the indirect block numbers - dprint("Built indirect blocks $indlist[0] .. $indlist[-1]\n"); - return(@indlist); + # Return the indirect block numbers + dprint("Built indirect blocks $indlist[0] .. $indlist[-1]\n"); + return (@indlist); } # Return blocknumber and offset for a specific i-node sub get_inode_block_offset { - my $inum= shift; - my $blocknum= FIRSTINODEBLK + int($inum/INODESPERBLK); - my $offset= INODESIZE * ($inum%INODESPERBLK); - dprint("inum $inum => block $blocknum offset $offset\n"); - return($blocknum, $offset); + my $inum = shift; + my $blocknum = FIRSTINODEBLK + int( $inum / INODESPERBLK ); + my $offset = INODESIZE * ( $inum % INODESPERBLK ); + dprint("inum $inum => block $blocknum offset $offset\n"); + return ( $blocknum, $offset ); } # Given an i-node number (possibly undef), permission, filetype, uid, size @@ -136,33 +141,34 @@ sub get_inode_block_offset { # with the data. If the i-node number is undef, allocate an i-node number. # Return the i-node number used. sub fill_inode { - my ($inum, $perms, $filetype, $uid, $size, @blklist)= @_; - die("Too many blocks\n") if (@blklist>7); + my ( $inum, $perms, $filetype, $uid, $size, @blklist ) = @_; + die("Too many blocks\n") if ( @blklist > 7 ); - # Deal with the root user-id - $uid= MAXINT if ($uid==ROOT_UID); + # Deal with the root user-id + $uid = MAXINT if ( $uid == ROOT_UID ); - # Calculate the block number and word offset for this - $inum= allocate_inode() if (!defined($inum)); - my ($blocknum, $offset)= get_inode_block_offset($inum); + # Calculate the block number and word offset for this + $inum = allocate_inode() if ( !defined($inum) ); + my ( $blocknum, $offset ) = get_inode_block_offset($inum); - # Fill in the easy fields - $Block[$blocknum][$offset+I_UID]= $uid; - $Block[$blocknum][$offset+I_SIZE]= $size; - $Block[$blocknum][$offset+I_NLKS]= 1; + # Fill in the easy fields + $Block[$blocknum][ $offset + I_UID ] = $uid; + $Block[$blocknum][ $offset + I_SIZE ] = $size; + $Block[$blocknum][ $offset + I_NLKS ] = 1; - my $i= $offset; - foreach my $datablocknum (@blklist) { - $Block[$blocknum][$i+I_DISKPS]= $datablocknum; - } + my $i = $offset; + foreach my $datablocknum (@blklist) { + $Block[$blocknum][ $i + I_DISKPS ] = $datablocknum; + } - # Deal with the flags and see if it's a large file - my $flags = $perms | $filetype | I_USED; - $flags |= I_LARGE if ($size> WORDSPERBLK * I_NUMBLKS); - $Block[$blocknum][$offset+I_FLAGS]= $flags; - - dprintf("fill inum %d: flags %06o uid %06o size %d\n", $inum, $flags, $uid, $size); - return($inum); + # Deal with the flags and see if it's a large file + my $flags = $perms | $filetype | I_USED; + $flags |= I_LARGE if ( $size > WORDSPERBLK * I_NUMBLKS ); + $Block[$blocknum][ $offset + I_FLAGS ] = $flags; + + dprintf( "fill inum %d: flags %06o uid %06o size %d\n", + $inum, $flags, $uid, $size ); + return ($inum); } # Convert an ASCII string into an array of 18-bit word values @@ -183,189 +189,316 @@ sub ascii2words { # Add an extra block to an i-node. NOTE: for now, we don't change the size # in the i-node. sub add_block_to_inode { - my ($blknum, $inum) = @_; + my ( $blknum, $inum ) = @_; - my ($iblock, $offset)= get_inode_block_offset($inum); + my ( $iblock, $offset ) = get_inode_block_offset($inum); - foreach my $i (1 .. I_NUMBLKS) { - next if ($Block[$iblock][$offset+$i]!=0); # Skip in-use blocks - $Block[$iblock][$offset+$i]= $blknum; - return; - } - die("Unable to add extra block to i-node $inum\n"); - dprint("Added block $blknum to i-node $inum\n"); + foreach my $i ( 1 .. I_NUMBLKS ) { + next if ( $Block[$iblock][ $offset + $i ] ); # Skip in-use blocks + $Block[$iblock][ $offset + $i ] = $blknum; + return; + } + die("Unable to add extra block to i-node $inum\n"); + dprint("Added block $blknum to i-node $inum\n"); } # Add a name and an i-node number to the current directory in the # directory stack. sub add_direntry { - my ($name, $inum)= @_; - dprint("Adding $name inode $inum to current directory\n"); + my ( $name, $inum ) = @_; + dprint("Adding $name inode $inum to current directory\n"); - # Get the block and offset to the next empty slot in the directory - my $dirref= $Dirstack[-1]; + # Get the block and offset to the next empty slot in the directory + my $dirref = $Dirstack[-1]; - if (!defined($dirref)) { - print("Empty dirstack, we must be building the root dir\n"); - return; - } + if ( !defined($dirref) ) { + dprint("Empty dirstack, we must be building the root dir\n"); + return; + } - my $blocknum= $dirref->[0]; - my $offset= $dirref->[1]; + my $blocknum = $dirref->[0]; + my $offset = $dirref->[1]; - # Convert the name into four words - my @wlist= ascii2words($name); + # Convert the name into four words + my @wlist = ascii2words($name); - # Fill in the directory entry - $Block[$blocknum][$offset+D_INUM]= $inum; - $Block[$blocknum][$offset+D_NAME]= pop(@wlist); - $Block[$blocknum][$offset+D_NAME+1]= pop(@wlist); - $Block[$blocknum][$offset+D_NAME+2]= pop(@wlist); - $Block[$blocknum][$offset+D_NAME+3]= pop(@wlist); + # Fill in the directory entry + $Block[$blocknum][ $offset + D_INUM ] = $inum; + $Block[$blocknum][ $offset + D_NAME ] = pop(@wlist); + $Block[$blocknum][ $offset + D_NAME + 1 ] = pop(@wlist); + $Block[$blocknum][ $offset + D_NAME + 2 ] = pop(@wlist); + $Block[$blocknum][ $offset + D_NAME + 3 ] = pop(@wlist); - # Move up to the next position in the directory. - $dirref->[1] += D_NUMWORDS; + # Move up to the next position in the directory. + $dirref->[1] += D_NUMWORDS; - # If we have filled the directory up, allocate another block to it - if ($dirref->[1] == WORDSPERBLK) { - my $nextblock= allocate_blocks(WORDSPERBLK); - $dirref->[0]= $nextblock; - $dirref->[1]= 0; + # If we have filled the directory up, allocate another block to it + if ( $dirref->[1] == WORDSPERBLK ) { + my $nextblock = allocate_blocks(WORDSPERBLK); + $dirref->[0] = $nextblock; + $dirref->[1] = 0; - # And add this new block to the directory's i-node - add_block_to_inode($nextblock, $dirref->[2]); - } + # And add this new block to the directory's i-node + add_block_to_inode( $nextblock, $dirref->[2] ); + } } # Given a name, perms, a user-id and an optional i-node number, make a # directory. Link it to the previous directory in the directory stack. # Allocate blocks and i-nodes for it. Add a "dd" entry as well. sub make_dir { - my ($dirname, $perms, $uid, $inum)= @_; + my ( $dirname, $perms, $uid, $inum ) = @_; - # Get an i-node number or validate the one we got - $inum= allocate_inode($inum); + # Get an i-node number or validate the one we got + $inum = allocate_inode($inum); - # Get a block for this directory - my $dirblock= allocate_blocks(WORDSPERBLK); + # Get a block for this directory + my $dirblock = allocate_blocks(WORDSPERBLK); - # Add this to the previous directory - # and fill the i-node with the details - add_direntry($dirname, $inum); - fill_inode($inum, $perms, I_DIRECTORY, $uid, 0, $dirblock); + # Add this to the previous directory + # and fill the i-node with the details + add_direntry( $dirname, $inum ); + fill_inode( $inum, $perms, I_DIRECTORY, $uid, 0, $dirblock ); - # Make this the top directory on the dirstack - dprint("Pushing dir block $dirblock inum $inum to dirstack\n"); - push(@Dirstack, [$dirblock, 0, $inum]); + # Make this the top directory on the dirstack + dprint("Pushing dir block $dirblock inum $inum to dirstack\n"); + push( @Dirstack, [ $dirblock, 0, $inum ] ); - # Add a "dd" entry to this directory - add_direntry("dd", DD_INUM); - dprintf("Made directory %s perms %06o uid %d in i-node %d\n\n", - $dirname, $perms, $uid, $inum); + # Add a "dd" entry to this directory + add_direntry( "dd", DD_INUM ); + dprintf( "Made directory %s perms %06o uid %d in i-node %d\n\n", + $dirname, $perms, $uid, $inum ); } # Read a word from a file in paper tape binary format. # Return -1 on EOF sub read_word { my $FH = shift; + # Convert three bytes into one 18-bit word - return(-1) if ( read( $FH, my $three, 3 ) != 3 ); # Not enough bytes read + return (-1) if ( read( $FH, my $three, 3 ) != 3 ); # Not enough bytes read my ( $b1, $b2, $b3 ) = unpack( "CCC", $three ); - return ((($b1 & 077) << 12 ) | - (($b2 & 077) << 6 ) | - ($b3 & 077)); + return ( ( ( $b1 & 077 ) << 12 ) | ( ( $b2 & 077 ) << 6 ) | ( $b3 & 077 ) ); } # Given a filename, perms, user-id and an external file, add a file to the # filesystem. Add an entry to this file in the current directory on # the dirstack. sub add_file { - my ($name, $perms, $uid, $extfile) = @_; - dprintf("Adding file %s perms %06o uid %d extfile %s\n", - $name, $perms, $uid, $extfile); + my ( $name, $perms, $uid, $extfile ) = @_; + dprintf( "Adding file %s perms %06o uid %d extfile %s\n", + $name, $perms, $uid, $extfile ); - # Open the external file - open(my $IN, "<", $extfile) || die("Can't open $extfile: $!\n"); + # Open the external file + open( my $IN, "<", $extfile ) || die("Can't open $extfile: $!\n"); - # Determine if this is ASCII or binary - my $isbinary=0; - my $c = getc($IN); - seek($IN, 0, 0); - $isbinary=1 if ((ord($c) & 0300) == 0200); + # Determine if this is ASCII or binary + my $isbinary = 0; + my $c = getc($IN); + seek( $IN, 0, 0 ); + $isbinary = 1 if ( ( ord($c) & 0300 ) == 0200 ); - # Read the whole file into a buffer, converting from ASCII or sixbit encoding - my @buf; - my $size; + # Read the whole file into a buffer, converting from ASCII or sixbit encoding + my @buf; + my $size; + + while (1) { + if ($isbinary) { - while (1) { - if ( $isbinary ) { # Convert three bytes into one 18-bit word my $result = read_word($IN); - last if ($result == -1); - $buf[$size++] = $result; - } - else { + last if ( $result == -1 ); + $buf[ $size++ ] = $result; + } else { # Convert two ASCII characters into one 18-bit word my $c1 = getc($IN); last if ( !defined($c1) ); # No character, leave the loop my $word = ord($c1) << 9; - my $c2 = getc($IN); - $word |= ord($c2) if (defined($c2)); - $buf[$size++] = $word; + my $c2 = getc($IN); + $word |= ord($c2) if ( defined($c2) ); + $buf[ $size++ ] = $word; } - } + } - # Allocate enough blocks for the file - my @blklist= allocate_blocks($size); + # Allocate enough blocks for the file + my @blklist = allocate_blocks($size); - # If it's too big, allocate indirect blocks - my $large=0; - my @indblocks; - if (@blklist > I_NUMBLKS) { - $large=1; - @indblocks= build_indirect_blocks(@blklist); - } + # If it's too big, allocate indirect blocks + my $large = 0; + my @indblocks; + if ( @blklist > I_NUMBLKS ) { + $large = 1; + @indblocks = build_indirect_blocks(@blklist); + } - # Allocate and fill in the i-node - my $inum= allocate_inode(); - if ($large) { - fill_inode($inum, $perms, 0, $uid, $size, @indblocks); - } else { - fill_inode($inum, $perms, 0, $uid, $size, @blklist); - } + # Allocate and fill in the i-node + my $inum = allocate_inode(); + if ($large) { + fill_inode( $inum, $perms, I_FILE, $uid, $size, @indblocks ); + } else { + fill_inode( $inum, $perms, I_FILE, $uid, $size, @blklist ); + } - # and add the entry in the directory - add_direntry($name, $inum); - dprint("Done adding file $name as inum $inum\n\n"); + # and add the entry in the directory + add_direntry( $name, $inum ); + dprint("Done adding file $name as inum $inum\n\n"); } # Given a name, perms, uid and i-number # add a special file to the filesystem sub add_special { - my ($name, $perms, $uid, $inum) = @_; + my ( $name, $perms, $uid, $inum ) = @_; - # Allocate and fill in the i-node - my $inum= allocate_inode($inum); - fill_inode($inum, $perms, I_SPECIAL, $uid, 0); + # Allocate and fill in the i-node + $inum = allocate_inode($inum); + fill_inode( $inum, $perms, I_SPECIAL, $uid, 0 ); - # Add the entry in the directory - add_direntry($name, $inum); - dprint("Done adding special file $name inum $inum\n\n"); + # Add the entry in the directory + add_direntry( $name, $inum ); + dprint("Done adding special file $name inum $inum\n\n"); +} + +# Parse the perms word from the proto file. +# Return filetype and perms as a number. +sub parse_perms { + my $permstring = shift; + my ( $filetype, $perms ) = ( I_FILE, 0 ); + + die("perms word $permstring is not 5 characters long\n") + if ( length($permstring) != 5 ); + + $filetype = I_DIRECTORY if ( $permstring =~ m{^d} ); + $filetype = I_SPECIAL if ( $permstring =~ m{^i} ); + + $perms |= I_OWNERREAD if ( $permstring =~ m{^.r} ); + $perms |= I_OWNERWRITE if ( $permstring =~ m{^..w} ); + $perms |= I_WORLDREAD if ( $permstring =~ m{^...r} ); + $perms |= I_WORLDWRITE if ( $permstring =~ m{^....w} ); + return ( $filetype, $perms ); +} + +# Open the named proto file and parse it +sub parse_proto_file { + my $file = shift; + open( my $IN, "<", $file ) || die("Can't one $file: $!\n"); + while (<$IN>) { + chomp; + + # Skip comments + s{#.*}{}; + + # Get the words on the line; + my @words = split( /\s+/, $_ ); + + # Skip if no words on this line + # but lose any empty word + next if ( @words == 0 ); + shift(@words) if ( $words[0] eq '' ); + + # If the first word is a $, then pop a directory from the stack + if ( $words[0] eq '$' ) { + pop(@Dirstack); + next; + } + + # Get the filetype and permissions + my ( $type, $perms ) = parse_perms( $words[1] ); + + if ( $type eq I_DIRECTORY ) { + my ( $name, $permstr, $uid, $inum ) = @words; + make_dir( $name, $perms, $uid, $inum ); + next; + } + if ( $type eq I_FILE ) { + my ( $name, $permstr, $uid, $extfile ) = @words; + add_file( $name, $perms, $uid, $extfile ); + next; + } + if ( $type eq I_SPECIAL ) { + my ( $name, $permstr, $uid, $inum ) = @words; + add_special( $name, $perms, $uid, $inum ); + next; + } + } + close($IN); +} + +# Convert an 18-bit word into a scalar which has three sixbit +# values in three bytes. Set the msb in the first byte +sub word2three { + my $val = shift; + + my $b1 = ( ( $val >> 12 ) & 077 ) | 0x80; + my $b2 = ( $val >> 6 ) & 077; + my $b3 = $val & 077; + return ( pack( "CCC", $b1, $b2, $b3 ) ); +} + +# Dump the image to the output file +sub dump_image { + my ( $format, $output ) = @_; + open( my $OUT, ">", $output ) || die("Can't write to $output: $!\n"); + + # list: Octal output with block comments + if ( $format eq "list" ) { + foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) { + printf( $OUT "Block %d (%06o)\n", $blocknum, $blocknum ) + if ($debug); + foreach my $line ( 0 .. 7 ) { + foreach my $offset ( 0 .. 7 ) { + printf( $OUT "%06o ", + $Block[$blocknum][ 8 * $line + $offset ] || 0 + ); + } + print( $OUT "\n" ) if ($debug); + } + print( $OUT "\n" ) if ($debug); + } + } + + # ptr: Each word into three bytes, a sixbit in each one + if ( $format eq "ptr" ) { + foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) { + foreach my $offset ( 0 .. WORDSPERBLK ) { + print( $OUT word2three( $Block[$blocknum][$offset] || 0 ) ); + } + } + } + + # simh: Each word into four bytes, little endian + if ( $format eq "simh" ) { + foreach my $blocknum ( 0 .. NUMBLOCKS - 1 ) { + foreach my $offset ( 0 .. WORDSPERBLK ) { + my $word = $Block[$blocknum][$offset] || 0; + my $packedword = pack( "CCCC", + ( $word >> 24 ) & 0xff, + ( $word >> 16 ) & 0xff, + ( $word >> 8 ) & 0xff, + $word & 0xff ); + print( $OUT $packedword ); + } + } + } + + close($OUT); +} + +# Keep this near the GetOptions call to make it easy to add documentation! +sub usage { + die("Usage: $0 [--debug] [--format=list|ptr|simh] [--out file] protofile\n"); } ### MAIN PROGRAM -$debug=1; -make_dir("dd", 014, -1, 2); -make_dir("system", 014, -1, 3); -add_file("init", 014, -1, "proto"); -pop(@Dirstack); -add_special("ttyin", 014, -1, 6); -add_special("keyboard", 014, -1, 7); -add_special("pptin", 014, -1, 8); -add_special("ttyout", 014, -1, 10); -add_special("display", 014, -1, 11); -add_special("pptout", 014, -1, 12); -add_file("as", 014, -1, "b.c"); -add_file("a7out", 014, -1, "a7out"); -add_file("oflow", 014, -1, "a7out"); +my ( $format, $output ) = ( "list", "image.fs" ); + +GetOptions( + 'debug|d' => \$debug, + 'format|f=s' => \$format, + 'output|o=s' => \$output, +) or usage(); + +usage() if ( @ARGV < 1 ); +parse_proto_file( $ARGV[0] ); +dump_image( $format, $output ); +exit(0);