objio.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 516 行

C
516
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  OMF (Object Module Format) I/O.
*
****************************************************************************/


#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>      /* for SEEK_SET, SEEK_CUR, SEEK_END */
#include <string.h>
#include "womp.h"
#include "genutil.h"
#include "memutil.h"
#include "myassert.h"
#include "objio.h"
#include "objrec.h"


#if _WOMP_OPT & _WOMP_WATFOR
extern  void            GObjError(void);
#define Fatal(__x,__y)  GObjError()
#elif _WOMP_OPT & _WOMP_WASM
extern  void            ObjWriteError( void );
#define Fatal(__x,__y)  ObjWriteError()
#endif

STATIC void safeSeek( int fh, long offset, int mode ) {

    if( lseek( fh, offset, mode ) == -1 ) {
        Fatal( MSG_DISK_ERROR, "lseek" );
    }
}

#if _WOMP_OPT & _WOMP_READ

/*
    Routines for buffered reading of an object file
*/

OBJ_RFILE *ObjReadOpen( const char *filename ) {
/********************************************/
    int         fh;
    OBJ_RFILE   *new;

    fh = open( filename, O_RDONLY | O_BINARY );
    if( fh < 0 ) {
        return( NULL );
    }
    new = MemAlloc( sizeof( *new ) );
    new->fh = fh;
    new->bufs = NULL;
    new->cur_off = 0;
    return( new );
}

void ObjReadClose( OBJ_RFILE *obj ) {
/*********************************/
    objread_buf *cur;
    objread_buf *next;

/**/myassert( obj != NULL );
    close( obj->fh );
    cur = obj->bufs;
    while( cur != NULL ) {
        next = cur->next;
        MemFree( cur );
        cur = next;
    }
    MemFree( obj );
}

STATIC uint_8 *readData( OBJ_RFILE *obj, size_t len_reqd ) {

    objread_buf *cur;
    objread_buf *buf;
    size_t      len_read;
    size_t      cur_off;
    size_t      partial_len;

/**/myassert( obj != NULL );
/**/myassert( len_reqd <= OBJ_BUFFER_SIZE );
    cur = obj->bufs;
    if( cur != NULL ) {
        cur_off = obj->cur_off;
        partial_len = cur->in_buf - cur_off;
        if( len_reqd <= partial_len ) {
            obj->cur_off += len_reqd;
            return( cur->data + cur_off );
        }
        buf = MemAlloc( sizeof( *buf ) + partial_len + OBJ_BUFFER_SIZE );
        memcpy( buf->data, cur->data + cur_off, partial_len );
        cur->in_buf = cur_off;
        buf->next = MemRealloc( cur, sizeof( *cur ) + cur_off );
/**/    myassert( cur == buf->next );   /* FIXME is this reqd by ANSI? */
    } else {
        buf = MemAlloc( sizeof( *buf ) + OBJ_BUFFER_SIZE );
        buf->next = NULL;
        partial_len = 0;
    }
    obj->cur_off = len_reqd;
    len_read = read( obj->fh, buf->data + partial_len, OBJ_BUFFER_SIZE );
    if( len_read == 0 ) {
        Fatal( MSG_PREMATURE_EOF );
    }
    buf = MemRealloc( buf, sizeof( *buf ) + partial_len + len_read );
    buf->in_buf = partial_len + len_read;
    obj->bufs = buf;
    return( buf->data );
}

obj_rec *ObjReadRec( OBJ_RFILE *obj ) {
/***********************************/
    obj_rec *new;
    uint_8  command;
    uint_16 length;
    uint_8  *data;

/**/myassert( obj != NULL );

    data = readData( obj, 3 );
    command = data[0];
    length = ReadU16( data + 1 );
    --length;               /* we don't care about checksum */
    if( length > OBJ_MAX_REC ) {
        Fatal( MSG_MAX_REC_EXCEEDED, OBJ_MAX_REC );
    }
    data = readData( obj, length );
    new = ObjNewRec( command );
    ObjAttachData( new, data, length );
    readData( obj, 1 );     /* advance over checksum byte */
    return( new );
}

int ObjRMoreData( OBJ_RFILE *obj ) {
/**********************************/
    objread_buf *buf;

/**/myassert( obj != NULL );
    buf = obj->bufs;
    if( buf == NULL ) {
        return( !eof( obj->fh ) );
    }
    return( obj->cur_off < buf->in_buf || !eof( obj->fh ) );
}

void ObjRSkipPage( OBJ_RFILE *obj, size_t page_len ) {
/****************************************************/
    objread_buf *buf;
    long        offset;
    long        seek_ofs;

/**/myassert( obj != NULL );
    if( page_len == 0 ) {
        return;
    }
    buf = obj->bufs;
    if( buf == NULL ) {
        return;
    }
    offset = tell( obj->fh );
    if( offset == -1 ) {
        Fatal( MSG_DISK_ERROR, "tell" );
    }
    offset = page_len - ( offset - buf->in_buf + obj->cur_off ) % page_len;
    if( offset != page_len ) {
        seek_ofs = offset + obj->cur_off - buf->in_buf;
        if( seek_ofs < 0 ) {
            obj->cur_off += offset;
        } else {
            obj->cur_off = buf->in_buf;
            safeSeek( obj->fh, seek_ofs, SEEK_CUR );
        }
    }
}

#endif


#if _WOMP_OPT & _WOMP_WRITE

#ifdef __UNIX__
#define OP_MODE         (O_RDWR | O_CREAT | O_TRUNC)
#define OP_PERM         (0666)
#else
#define OP_MODE         (O_RDWR | O_CREAT | O_TRUNC | O_BINARY)
#define OP_PERM         (S_IREAD | S_IWRITE)
#endif

/*
    Routines for buffered writing of an object file
*/

STATIC void safeWrite( int fh, const char *buf, size_t len ) {

    if( write( fh, buf, len ) != len ) {
        Fatal( MSG_DISK_ERROR, "write" );
    }
}

OBJ_WFILE *ObjWriteOpen( const char *filename ) {
/*********************************************/
    int         fh;
    OBJ_WFILE    *new;

    fh = open( filename, OP_MODE, OP_PERM );
    if( fh < 0 ) {
        return( NULL );
    }
    new = MemAlloc( sizeof( *new ) + OBJ_BUFFER_SIZE );
    new->fh = fh;
    new->in_buf = 0;
    new->in_rec = 0;

    return( new );
}

void ObjWriteClose( OBJ_WFILE *obj ) {
/**********************************/
/**/myassert( obj != NULL );

    if( obj->in_rec ) {
        ObjWEndRec( obj );
    }
    close( obj->fh );
    MemFree( obj );
}

void ObjWBegRec( OBJ_WFILE *obj, uint_8 command ) {
/***********************************************/
    char    buf[3];

/**/myassert( obj != NULL && !obj->in_rec );

    buf[0] = command;
    buf[1] = 0;
    buf[2] = 0;
    safeWrite( obj->fh, buf, 3 );
    obj->in_rec = 1;
    obj->checksum = command;
    obj->in_buf = 0;
    obj->length = 0;
}

static void objWFlushBuffer( OBJ_WFILE *obj ) {
/*******************************************/
    size_t  len_to_write;
    uint_8  checksum;
    char    *p;

/**/myassert( obj != NULL );

    len_to_write = obj->in_buf;
    if( len_to_write == 0 )  return;
    checksum = obj->checksum;
    for( p = obj->buffer; p < obj->buffer + len_to_write; ++p ) {
        checksum += *p;
    }
    obj->checksum = checksum;
    obj->length += len_to_write;
    safeWrite( obj->fh, obj->buffer, len_to_write );
    obj->in_buf = 0;
}

void ObjWEndRec( OBJ_WFILE *obj ) {
/*******************************/
    char    buf[2];
    uint_8  checksum;

/**/myassert( obj != NULL && obj->in_rec );

    if( obj->in_buf > 0 ) {
        objWFlushBuffer( obj );
    }
    ++obj->length;                  /* add 1 for checksum byte */
    WriteU16( buf, obj->length );
    checksum = obj->checksum + buf[0] + buf[1];
    checksum = -checksum;
    safeWrite( obj->fh, &checksum, 1 );
        /* back up to length */
    safeSeek( obj->fh, - (int_32)obj->length - 2, SEEK_CUR );
    safeWrite( obj->fh, buf, 2 );                   /* write the length */
    safeSeek( obj->fh, 0L, SEEK_END );       /* move to end of file again */
    obj->in_rec = 0;
}

void ObjWrite8( OBJ_WFILE *obj, uint_8 byte ) {
/*******************************************/
/**/myassert( obj != NULL && obj->in_rec );

    if( obj->in_buf == OBJ_BUFFER_SIZE ) {
        objWFlushBuffer( obj );
    }
    obj->buffer[ obj->in_buf++ ] = byte;
}

void ObjWrite16( OBJ_WFILE *obj, uint_16 word ) {
/*********************************************/
/**/myassert( obj != NULL && obj->in_rec );

    if( obj->in_buf >= OBJ_BUFFER_SIZE - 1 ) {
        objWFlushBuffer( obj );
    }
    WriteU16( obj->buffer + obj->in_buf, word );
    obj->in_buf += 2;
}

void ObjWrite32( OBJ_WFILE *obj, uint_32 dword ) {
/**********************************************/
/**/myassert( obj != NULL && obj->in_rec );

    if( obj->in_buf >= OBJ_BUFFER_SIZE - 3 ) {
        objWFlushBuffer( obj );
    }
    WriteU32( obj->buffer + obj->in_buf, dword );
    obj->in_buf += 4;
}

void ObjWriteIndex( OBJ_WFILE *obj, uint_16 index ) {
/*************************************************/
    if( index > 0x7f ) {
        ObjWrite8( obj, 0x80 | ( index >> 8 ) );
    }
    ObjWrite8( obj, index & 0xff );
}

void ObjWrite( OBJ_WFILE *obj, const char *buf, size_t length ) {
/*************************************************************/
    const char *write;
    size_t amt;

/**/myassert( obj != NULL && buf != NULL );

    write = buf;
    for(;;) {
        amt = OBJ_BUFFER_SIZE - obj->in_buf;
        if( amt >= length ) {
            memcpy( &obj->buffer[ obj->in_buf ], write, length );
            obj->in_buf += length;
            break;
        } else if( amt > 0 ) {
            memcpy( &obj->buffer[ obj->in_buf ], write, amt );
            obj->in_buf += amt;
            write += amt;
            length -= amt;
        }
        objWFlushBuffer( obj );
    }
}

STATIC uint_8 checkSum( const uint_8 *buf, uint_16 length ) {
/***********************************************************/
    uint_8 checksum;

    checksum = 0;
    while( length ) {
        checksum += *buf;
        ++buf;
        --length;
    }
    return( checksum );
}

void ObjWriteRec( OBJ_WFILE *obj, uint_8 command, uint_16 length,
    const char *contents ) {
/***************************************************************/
/*
    Contents and length don't include checksum
*/
    char buf[3];
    uint_8 checksum;

/**/myassert( obj != NULL && !obj->in_rec );

    checksum  = buf[0] = command;
    checksum += buf[1] = ( length + 1 ) & 0xff;
    checksum += buf[2] = ( length + 1 ) >> 8;
    safeWrite( obj->fh, buf, 3 );
    checksum += checkSum( contents, length );
    safeWrite( obj->fh, contents, length );
    checksum = -checksum;
    safeWrite( obj->fh, &checksum, 1 );
}

#if _WOMP_OPT & _WOMP_NASM

obj_offset ObjWSkip32( OBJ_WFILE *obj ) {
/*************************************/
    obj_offset off;

/**/myassert( obj != NULL && obj->in_rec );
    off.rec_begin = tell( obj->fh ) - obj->length - 2;
    off.offset = obj->length + obj->in_buf;
    ObjWrite32( obj, 0 );
    return( off );
}

void ObjWRedo32( OBJ_WFILE *obj, obj_offset off, uint_32 dword ) {
/*************************************************************/
#if defined( __BIG_ENDIAN__ )
    unsigned char    buf[4];
#endif
    uint_16 rec_length;
    char    checksum;
    int i;

/**/myassert( obj != NULL );
    safeSeek( obj->fh, off.rec_begin, SEEK_SET );
#if defined( __BIG_ENDIAN__ )
    safeRead( obj->fh, buf, 2 );
    rec_length = ReadU16( buf );
#else
    safeRead( obj->fh, (char *)&rec_length, 2 );
#endif
    safeSeek( obj->fh, off.offset, SEEK_CUR );
#if defined( __BIG_ENDIAN__ )
    for (i = 0; i < 4; i++) {
        buf[i] = ((char*)&dword)[3-i];
    }
    safeWrite( obj->fh, buf, 4 );
#else
    safeWrite( obj->fh, (char *)&dword, 4 );
#endif
    safeSeek( obj->fh, (int_32)rec_length - off.offset - 5, SEEK_CUR );
    safeRead( obj->fh, &checksum, 1 );
    checksum = -checksum;
    for (i = 0; i < 4; i++) {
        checksum += ((char*)&dword)[i];
    }
    checksum = -checksum;
    safeSeek( obj->fh, -1L, SEEK_CUR );
    safeWrite( obj->fh, &checksum, 1 );
    safeSeek( obj->fh, 0L, SEEK_END );
}

obj_offset ObjWSkip16( OBJ_WFILE *obj ) {
/*************************************/
    obj_offset off;

/**/myassert( obj != NULL && obj->in_rec );
    off.rec_begin = tell( obj->fh ) - obj->length - 2;
    off.offset = obj->length + obj->in_buf;
    ObjWrite16( obj, 0 );
    return( off );
}

STATIC void safeRead( int fh, char *buf, size_t len ) {

    if( read( fh, buf, len ) != len ) {
        Fatal( MSG_PREMATURE_EOF, "read");
    }
}

void ObjWRedo16( OBJ_WFILE *obj, obj_offset off, uint_16 word ) {
/*************************************************************/
#if defined( __BIG_ENDIAN__ )
    char    buf[2];
#endif
    uint_16 rec_length;
    char    checksum;

/**/myassert( obj != NULL );
    safeSeek( obj->fh, off.rec_begin, SEEK_SET );
#if defined( __BIG_ENDIAN__ )
    safeRead( obj->fh, buf, 2 );
    rec_length = ReadU16( buf );
#else
    safeRead( obj->fh, (char *)&rec_length, 2 );
#endif
    safeSeek( obj->fh, off.offset, SEEK_CUR );
#if defined( __BIG_ENDIAN__ )
    buf[0] = word & 0xff;
    buf[1] = word >> 8;
    safeWrite( obj->fh, buf, 2 );
#else
    safeWrite( obj->fh, (char *)&word, 2 );
#endif
    safeSeek( obj->fh, (int_32)rec_length - off.offset - 3, SEEK_CUR );
    safeRead( obj->fh, &checksum, 1 );
    checksum = -checksum;
    checksum += word & 0xff;
    checksum += word >> 8;
    checksum = -checksum;
    safeSeek( obj->fh, -1L, SEEK_CUR );
    safeWrite( obj->fh, &checksum, 1 );
    safeSeek( obj->fh, 0L, SEEK_END );
}

#endif

#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?