topic.cpp

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 1,642 行 · 第 1/3 页

CPP
1,642
字号
// used to calculate the size of a text attribute.
const int TextHeader::_attrSizes[] = {  3, 1, 1, 1, 9, 9, 9, 1, 3, 3,
                    5, 5, 5, 5, 7, 7, 7, 7, 1
};


//  TextHeader::addAttr --Add a text attribute.

int TextHeader::addAttr( FontFlags type, uint_32 val, char const str[],
                          int length )
{
    int result = _numAttribs;
    if( _numAttribs == _maxAttribs ){
    _maxAttribs += TEXT_ATTR_MAX;
    _attribs.resize( _maxAttribs );
    }
    _attribs[ _numAttribs ]._type = type;
    _attribs[ _numAttribs ]._data = val;
    if( length > 0 ){
    _attribs[ _numAttribs ]._stringDat = new char[length];
    memcpy( _attribs[ _numAttribs ]._stringDat, str, length );
    } else {
    _attribs[ _numAttribs ]._stringDat = NULL;
    }

    _attribs[ _numAttribs ]._size = _attrSizes[ type ];
    if( type == TOP_MACRO_LINK || type == TOP_MACRO_INVIS ||
        ( type >= TOP_POPUP_FILE && type <= TOP_JUMP_FILE_INVIS ) ){
    _attribs[ _numAttribs ]._size += length;
    }
    _size += _attribs[ _numAttribs ]._size;
    ++_numAttribs;

    return result;
}


//  TextHeader::appendAttr   --Append a text attribute after a given one.

int TextHeader::appendAttr( int index, FontFlags type, uint_32 val,
                 char const str[], int length )
{
    if( index >= _numAttribs ){
    HCError( HLP_ATTR );
    }

    int result = index+1;

    if( _numAttribs == _maxAttribs ){
    _maxAttribs += TEXT_ATTR_MAX;
    _attribs.resize( _maxAttribs );
    }

    if( result < _numAttribs ){
    memmove( &_attribs[result+1], &_attribs[result],
             (_numAttribs-result)*sizeof( TextAttr ) );
    }
    _attribs[ result ]._type = type;
    _attribs[ result ]._data = val;
    if( length > 0 ){
    _attribs[ result ]._stringDat = new char[length];
    memcpy( _attribs[ result ]._stringDat, str, length );
    } else {
    _attribs[ result ]._stringDat = NULL;
    }

    _attribs[ result ]._size = _attrSizes[ type ];
    if( type == TOP_MACRO_LINK || type == TOP_MACRO_INVIS ||
        ( type >= TOP_POPUP_FILE && type <= TOP_JUMP_FILE_INVIS ) ){
    _attribs[ result ]._size += length;
    }
    _size += _attribs[ result ]._size;
    ++_numAttribs;

    return result;
}


//  TextHeader::chgAttr   --Modify a text attribute.

void TextHeader::chgAttr( int index, FontFlags type, uint_32 val,
                           char const str[], int length )
{
    if( index >= _numAttribs ){
    HCError( HLP_ATTR );
    }

    _size -= _attribs[ index ]._size;
    _attribs[ index ]._type = type;
    _attribs[ index ]._data = val;
    if( _attribs[ index ]._stringDat != NULL ){
    delete _attribs[ index ]._stringDat;
    }
    if( length > 0 ){
    _attribs[ index ]._stringDat = new char[length];
    memcpy( _attribs[ index ]._stringDat, str, length );
    } else {
    _attribs[ index ]._stringDat = NULL;
    }

    _attribs[ index ]._size = _attrSizes[ type ];
    if( type == TOP_MACRO_LINK || type == TOP_MACRO_INVIS ||
        ( type >= TOP_POPUP_FILE && type <= TOP_JUMP_FILE_INVIS ) ){
    _attribs[ index ]._size += length;
    }

    _size += _attribs[ index ]._size;
}


//  TextHeader::attrData    --Read the data from an attribute.

uint_32 TextHeader::attrData( int index )
{
    if( index >= _numAttribs ){
    HCError( HLP_ATTR );
    }

    return _attribs[ index ]._data;
}


//  TextHeader::DumpTo  --Convert the node to it's binary form.
//            Complicated, thanks to many variable-length fields.

void TextHeader::dumpTo( TopicLink *dest )
{
    char    *location = dest->_myData;
    int     i;

    *( (uint_16*) location ) = (uint_16) ( (2*_headerSize) | 0x8000 );
    location += sizeof( uint_16 );
    if( _textSize < INT_SMALL_LIMIT ){
    *location++ = (uint_8) (_textSize*2);
    } else {
    *( (uint_16*) location ) = (uint_16) (_textSize*2+1) ;
    location += sizeof( uint_16 );
    }
    *location++ = _numColumns;
    *location++ = 0x80; // magic byte
    *((uint_32*) location ) = _flags;
    location += sizeof( uint_32 );

    // Print out the paragraph attributes.
    for( i=0; i < TOP_BORDER; i++ ){
    if( _flags & _parBits[i] ){
        if( _spacing[i] & 0x1 ){
        *((uint_16*) location) = _spacing[i];
        location += sizeof( uint_16 );
        } else {
        *location++ = (uint_8) _spacing[i];
        }
    }
    }
    if( _flags & _parBits[ TOP_BORDER ] ){
    *((uint_16*) location) = (uint_16) _border;
    location += sizeof( uint_16 );
    *location++ = (uint_8) (_border >> 16);
    }
    // Dump the tab stops, converting them into WinHelp's integer format.
    if( _flags & _parBits[ TOP_TAB_STOPS ] ){
    uint_16 stops_num = _numStops;
    stops_num <<= 1;
    if( stops_num < INT_SMALL_LIMIT ){
        stops_num |= 0x80;
        *location++ = (uint_8) stops_num;
    } else {
        stops_num |= 0x8001;
        *((uint_16*) location) = stops_num;
        location += sizeof( uint_16 );
    }
    for( i=0; i<_numStops; i++ ){
        if( _tabStops[i] & 0x1 ){
        *((uint_16*) location) = _tabStops[i];
        location += sizeof( uint_16 );
        if( _tabStops[i] & 0x8000 ){
            *location++ = _tabFlags[i];
        }
        } else {
        *location++ = (uint_8) _tabStops[i];
        if( _tabStops[i] & 0x80 ){
            *location++ = _tabFlags[i];
        }
        }
    }
    }

    // Now the text attributes.
    uint_16 length;
    for( i=0; i < _numAttribs; i++ ){
    *location++ = _attrBits[ _attribs[i]._type ];
    switch( _attribs[i]._type ){

        // deliberate fall-through
    case TOP_NEW_LINE:
    case TOP_NEW_PAR:
    case TOP_HTAB:
    case TOP_END_LINK:
    case TOP_END:
        // No argument for these flags.
        break;

    case TOP_CENT_BITMAP:
    case TOP_LEFT_BITMAP:
    case TOP_RIGHT_BITMAP:
        // Right now these numbers are mostly magic.
        *((uint_32*) location) = 0x02800822;
        location += sizeof( uint_32 );
        *((uint_16*) location) = (uint_16) 0;
        location += sizeof( uint_16 );
        *((uint_16*) location) = (uint_16) _attribs[i]._data;
        location += sizeof( uint_16 );
        break;

    case TOP_FONT_CHANGE:
        *((uint_16*) location) = (uint_16) _attribs[i]._data;
        location += sizeof( uint_16 );
        break;

        // more fall-through
    case TOP_POPUP_LINK:
    case TOP_JUMP_LINK:
    case TOP_POPUP_INVIS:
    case TOP_JUMP_INVIS:
        *((uint_32*) location) = _attribs[i]._data;
        location += sizeof( uint_32 );
        break;

    case TOP_MACRO_LINK:
    case TOP_MACRO_INVIS:
        length = (uint_16) (_attribs[i]._size-3);
        *((uint_16*) location) = length;
        location += sizeof( uint_16 );
        memcpy( location, _attribs[i]._stringDat, length );
        location += length;
        break;

    default:
        length = (uint_16) (_attribs[i]._size-_attrSizes[_attribs[i]._type]);
        *((uint_16*) location) = (uint_16) (length+4);
        location += sizeof( uint_16 );
        *location++ = _attribs[i]._stringDat[0];
        *((uint_32*) location) = _attribs[i]._data;
        location += sizeof( uint_32 );
        memcpy( location, _attribs[i]._stringDat+1, length-1 );
        location += length-1;
    }
    }

    dest->_size = _size;
}


//  TextHolder::TextHolder

TextHolder::TextHolder()
    : _text( TEXT_BLOCK_SIZE+1 ),
      _zeroes( TEXT_ZERO_SIZE ),
      _size( 0 ),
      _uncompSize( 0 ),
      _maxSize( TEXT_BLOCK_SIZE ),
      _numZeroes( 0 ),
      _maxZeroes( TEXT_ZERO_SIZE )
{
    // empty
}


//  TextHolder::DumpTo  --Convert the node to it's binary form.

void TextHolder::dumpTo( TopicLink *dest )
{
    if( _size > 0 ){
    memcpy( dest->_myData, _text, _size );
    }
    dest->_size = _size;
}


//  HFTopic::HFTopic

HFTopic::HFTopic( HFSDirectory * d_file, HFPhrases *ph )
    : _size( PAGE_HEADER_SIZE ),  // The initial 3-DWORD page header.
      _numPages( 1 ),
      _numTopics( 0 ),
      _haveCleanedUp( 0 ),
      _phFile( ph ),
      _head( NULL ),
      _tail( NULL ),
      _browseStr( NULL ),
      _bhead( NULL ),
      _btail( NULL ),
      _curOffset( PAGE_HEADER_SIZE ),
      _curCharOffset( 0 ),
      _lastTopic( ~0 ),
      _lastLink( ~0 ),
      _lastNode( NULL ),
      _lastHeader( NULL )
{
    _size = PAGE_HEADER_SIZE;
    _useCompress = (ph != NULL);
    _phead = new PageHeader;
    _ptail = _phead;

    // Set up the text-compression facilities, if necessary.
    // Note the initial writer is a dummy, used just to get the size
    // of the compressed data.
    if( _useCompress ){
    _myWriter = new CompWriter;
    _myReader = new CompReader( _myWriter );
    } else {
    _myWriter = NULL;
    _myReader = NULL;
    }

    // Create an initial linked-list node to work with.
    _curNode = new GenericNode( ~0 );
    _curNode->_recordType = TOP_HEADER;
    _curTopic = new TopicHeader( _numTopics++ );
    _curText = new TextHolder;
    _curPar = new TextHeader;


    // Set the initial page header.
    _phead->lastNode() = _lastTopic;
    _phead->nextNode() = _curOffset;
    _phead->lastTopic() = 0;

    // Register ourself with the directory.
    d_file->addFile( this, "|TOPIC" );
}


//  HFTopic::~HFTopic

HFTopic::~HFTopic()
{
    if( _myWriter ) delete _myWriter;
    if( _myReader ) delete _myReader;

    if( _lastNode != _curNode ){
    delete _lastNode;
    }
    if( _lastHeader != _curTopic ){
    delete _lastHeader;
    }
    delete _curNode;
    delete _curTopic;
    delete _curPar;
    delete _curText;

    // Lotsa linked lists to delete.

    TopicLink   *current = _head;
    TopicLink   *temp;
    while( current != NULL ){
    temp = current;
    current = current->_next;
    delete temp;
    }

    PageHeader  *pcurrent = _phead;
    PageHeader  *ptemp;
    while( pcurrent != NULL ){
    ptemp = pcurrent;
    pcurrent = pcurrent->_next;
    delete ptemp;
    }

    StringNode  *bcurrent = _bhead;
    StringNode  *btemp;
    while( bcurrent != NULL ){
    btemp = bcurrent;
    bcurrent = bcurrent->_next;
    delete[] btemp->_string;
    delete btemp;
    }
}


//  HFTopic::size   --Overridden from Dumpable.

uint_32 HFTopic::size()
{
    if( !_haveCleanedUp ){

    // Dump the last linked-list node, if necessary.
    newNode();
    _haveCleanedUp = 1;
    }
    return _size;
}


//  HFTopic::dump   --Overridden from Dumpable.

int HFTopic::dump( OutFile * dest )
{
    // Write the last few blocks of binary data.
    if( _lastNode != NULL ){
    _lastNode->dumpTo( _lastNode->_myLink );
    }
    if( _lastHeader != NULL ){
    _lastHeader->dumpTo( _lastHeader->_myLink );
    }

    // Put in browse sequence information.
    dumpBrowse();

    // If we're compressing, stop the dummy compressor and start
    // the real thing.
    if( _useCompress ){
    CompWriter  *temp = new CompOutFile( dest );
    _myReader->reset( temp );
    if( _myWriter ) delete _myWriter;
    _myWriter = temp;
    }

    TopicLink       *current = _head;
    PageHeader      *cur_page = _phead->_next;
    dest->writebuf( _phead->_pageNums, sizeof( uint_32 ), 3 );
    uint_32     page_size = PAGE_HEADER_SIZE;

    // Write the linked list nodes in order.
    int i;
    while( current != NULL ){

    // At the start of a page, flush the compressor and
    // write a page header.
    if( current->_isFirstLink ){
        HCTick();
        if( _useCompress ){
        _myReader->flush();
        }
        while( page_size < COMP_PAGE_SIZE ){
        dest->writech( 0 );
        page_size++;
        }
        page_size = PAGE_HEADER_SIZE;
        dest->writebuf( cur_page->_pageNums, sizeof( uint_32 ), 3 );
        cur_page = cur_page->_next;
    }

    if( _useCompress ){
        page_size += _myReader->add( current->_myData, current->_size );

        // "Magic" check to see if the current node is a topic header
        // or a text header.  This is the only way to do it since
        // at this stage the node is just a binary data block.
        if( current->_myData[20] == 0x02 ){
        current = current->_next;
        page_size += _myReader->add( current->_myData, current->_size );
        } else {
        current = current->_next;
        page_size += _myReader->compress( current->_myData, current->_size );
        }
        current = current->_next;
        page_size += _myReader->compress( current->_myData, current->_size );
        current = current->_next;
    } else {
        for( i=0; i<3; i++, current=current->_next ){
        page_size += current->_size;
        dest->writebuf( current->_myData, 1, current->_size );
        }
    }
    }

    // If we're compressing, a few bytes may be left in the writer.
    if( _useCompress ){
    _myReader->flush();
    }
    return 1;
}


//  HFTopic::startNonScroll --Signal the start of a non-scrolling
//                region of text.

void HFTopic::startNonScroll()
{
    _lastHeader->_startNonScroll = _curOffset;
}


//  HFTopic::startScroll    --Signal the start of a scrolling
//                region of text.

void HFTopic::startScroll()
{
    _lastHeader->_startScroll = _curOffset;
    if( _lastHeader->_startNonScroll == _curOffset ){
    _lastHeader->_startNonScroll = ~0;
    }
}


//  HFTopic::addBrowse      --Add browse sequence information.

void HFTopic::addBrowse( char const str[] )
{
    if( _browseStr != NULL ){
    HCWarning( TOP_TWOBROWSE, _browseStr, str );
    delete[] _browseStr;
    }
    int length = strlen( str );
    _browseStr = new char[length+1];
    strncpy( _browseStr, str, length+1 );
    _browseOffset = _curCharOffset;
}


//  HFTopic::recordBrowse   --Get the browse sequence info, in
//                binary form.

void HFTopic::recordBrowse( TopicLink *me )
{
    StringNode  *current = _bhead;
    StringNode  *prev = NULL;
    StringNode  *newnode = new StringNode;
    newnode->_me= me;
    newnode->_charOffset = _browseOffset;
    newnode->_string = _browseStr;
    strlwr( newnode->_string );
    _browseStr = NULL;
    while( current != NULL ){
    if( strcmp( current->_string, newnode->_string ) > 0 ) break;
    prev = current;
    current = current->_next;
    }

    if( current == NULL ){
    if( prev == NULL ){
        _bhead = _btail = newnode;
        newnode->_next = newnode->_prev = NULL;
    } else {
        prev->_next = newnode;
        newnode->_prev = prev;
        newnode->_next = NULL;
        _btail = newnode;
    }
    } else {
    newnode->_next = current;
    newnode->_prev = current->_prev;
    current->_prev = newnode;
    if( prev == NULL ){
        _bhead = newnode;
    } else {
        prev->_next = newnode;

⌨️ 快捷键说明

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