/****************************************************************************
**
*A  fix_siow.c                  GAP Tools                         David Bayer
**
**  fix_siow <infile> <outfile>
**
**  'fix_siow'    copies <infile> to   <outfile> changing  the instruction at
**  location 3F94 from 'A063',  which is a call  to 'MaxApplZone', to '4E71',
**  which is  a NOP instruction.  It is  intended to create a patched version
**  of the Mac Programmers Workshop library file 'SIOW.o',  which is used for
**  creating a Simple Input Output Window for applications.
**
**  Such a patched  version of 'SIOW.o' is needed  for SIOW applications that
**  need more stack  space than  MPW will normally  make  available for them.
**  Such  applications must execute the   following two instructions early in
**  their lifetime, preferrably before doing any file input or output.
**
**      #include <Memory.h>
**      ...
**      SetApplLimit( GetApplLimit() - <amount-of-additional-stack-space> );
**      MaxApplZone();
**
**  Otherwise,   bungee-jumping the stack  will  lead to fatal head injuries.
**  Dave Bayer, July 14, 1994.
*/

#include        <stdio.h>
#include        <stdlib.h>
#include        <Files.h>

#define POS     (0x3F92 / sizeof(unsigned short))
unsigned short  before[] = { 0xA02D, 0xA063, 0x2038, 0x0130, 0x90B8, 0x02AA };
unsigned short  after [] = { 0xA02D, 0x4E71, 0x2038, 0x0130, 0x90B8, 0x02AA };

FILE *          infile;
FILE *          outfile;

#define BUF     0x4000
unsigned short  buffer[BUF];

unsigned long   match (
    unsigned short      str1 [],
    unsigned short      str2 [],
    unsigned long       len )
{
    unsigned long       i;
    for ( i = 0; i < len; i++ ) {
        if ( str1[i] != str2[i] )
            return 0;
    }
    return 1;
}

void            setfile (
    char *              name,
    OSType              type,
    OSType              creator )
{
    FInfo               fnderInfo;

    getfinfo( name, 0, &fnderInfo );
    if ( fnderInfo.fdType    == 0 )  fnderInfo.fdType    = type;
    if ( fnderInfo.fdCreator == 0 )  fnderInfo.fdCreator = creator;
    setfinfo( name, 0, &fnderInfo );
}

main (
    int                 argc,
    char *              argv [] )
{
    unsigned long       nr;

    /* check the number of arguments                                       */
    if ( argc != 3 ) {
        printf( "usage: fix_siow <infile> <outfile>\n" );
        exit( 1 );
    }

    /* open the infile for reading                                         */
    if ( ! (infile = fopen( argv[1], "rb" )) ) {
        printf( "fix_siow: cannot open '%s' for reading\n", argv[1] );
        exit( 1 );
    }

    /* open the outfile for writing                                        */
    if ( ! (outfile = fopen( argv[2], "wb" )) ) {
        printf( "fix_siow: cannot open '%s' for writing\n", argv[2] );
        exit( 1 );
    }

    /* copy the first part                                                 */
    if ( fread(  buffer, sizeof(unsigned short), POS, infile  ) != POS ) {
        printf( "fix_siow: cannot read first part from '%s'\n", argv[1] );
        exit( 1 );
    }
    if ( fwrite( buffer, sizeof(unsigned short), POS, outfile ) != POS ) {
        printf( "fix_siow: cannot write first part to '%s'\n", argv[2] );
        exit( 1 );
    }

    /* read the critical session                                           */
    if ( fread(  buffer, sizeof(unsigned short), 6,   infile  ) != 6   ) {
        printf( "fix_siow: cannot read second part from '%s'\n", argv[1] );
        exit( 1 );
    }

    /* check that it is not already patched                                */
    if ( match( buffer, after, 6 ) ) {
        printf( "fix_siow: '%s' seems to be already patched\n", argv[1] );
        printf( "          only copying <infile> to <outfile>\n" );
    }
    else if ( ! match( buffer, before, 6 ) ) {
        printf( "fix_siow: '%s' does not match expected layout\n", argv[1] );
        printf( "          giving up\n" );
        exit( 1 );
    }
    else {
        printf( "fix_siow: '%s' is allright, patching done\n", argv[1] );
    }

    /* write the modified critical session                                 */
    if ( fwrite( after,  sizeof(unsigned short), 6,   outfile ) != 6   ) {
        printf( "fix_siow: cannot write second part to '%s'\n", argv[2] );
        exit( 1 );
    }

    /* copy the remainder                                                  */
    while (  (nr = fread(  buffer, sizeof(unsigned short), BUF, infile )) ) {
        if ( nr != fwrite( buffer, sizeof(unsigned short), nr,  outfile ) ) {
            printf( "fix_siow: cannot write final part to '%s'\n", argv[2] );
            exit( 1 );
        }
    }

    /* close the files                                                     */
    fclose( infile );
    fclose( outfile );

    /* set type and creator of outfile                                     */
    setfile( argv[2], 'OBJ ', 'MPS ' );

    /* return success                                                      */
    return 0;
}



