topic.cpp

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

CPP
1,642
字号
/****************************************************************************
*
*                            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:  Write help text in .hlp format.
*
****************************************************************************/


#include <string.h>
#include "topic.h"

#define COMP_PAGE_SIZE 4096


//
//  TextAttr    --Structure to record changes to text.
//

struct TextAttr
{
    FontFlags   _type;
    uint_32 _data;
    int     _size;
    char    *_stringDat;
};


//
//  TopicLink   --Linked list record to store binary topic data
//        once it's generated.
//

struct TopicLink
{
    TopicLink       *_next;
    uint_32     _size;
    int         _isFirstLink;
    Buffer<char>    _myData;

    TopicLink( uint_32 s );
};


//
//  StringNode  --A linked list record to keep track of browse sequences.
//

struct StringNode
{
    char    *_string;
    TopicLink   *_me;
    uint_32 _charOffset;
    StringNode  *_next, *_prev;

    // Handy access functions used by HFTopic::dumpBrowse().
    uint_32 &   prevBrowse() { return *((uint_32*) (_me->_myData+4)); };
    uint_32 &   nextBrowse() { return *((uint_32*) (_me->_myData+8)); };
};


//
//  PageHeader  --Structure to store paging-related information.
//

#define PAGE_HEADER_SIZE    12

struct PageHeader
{
    PageHeader  *_next;
    uint_32 _pageNums[3];

    // Some mnemonic access functions for accessing _pageNums.
    uint_32 &   lastNode() { return *_pageNums; };
    uint_32 &   nextNode() { return *(_pageNums+1); };
    uint_32 &   lastTopic() { return *(_pageNums+2); };

    PageHeader();
};


// NOTE:  every node in the |TOPIC linked list consistes of three parts:
// a node header, a type-specific header, and the text.  There are three
// different type-specific headers, two of which are implemented here.


//
//  GenericNode --Class to represent the 'node header'.
//

#define GENERIC_NODE_SIZE   21
class GenericNode
{
    uint_32 _topicSize;
    uint_32 _dataSize;
    uint_32 _prevNode;
    uint_32 _nextNode;
    uint_32 _dataOffset;
    uint_8  _recordType;
    uint_32 _size;
    TopicLink   *_myLink;

    GenericNode( uint_32 prev );

    void    dumpTo( TopicLink *dest );

    friend class HFTopic;
};


//
//  TopicHeader --Class to store topic headers, one kind of
//        type-specific header.
//

#define TOPIC_HEADER_SIZE   28
class TopicHeader
{
    uint_32 _totalSize;
    uint_32 _nextBrowse;
    uint_32 _prevBrowse;
    uint_32 _topicNum;
    uint_32 _startNonScroll;
    uint_32 _startScroll;
    uint_32 _nextTopic;
    uint_32 _size;
    TopicLink   *_myLink;

    TopicHeader( uint_32 tnum );

    void    dumpTo( TopicLink *dest );

    friend class HFTopic;
};


#define TEXT_ARG_MAX    10
#define TEXT_ATTR_MAX   25


//
//  TextHeader  --Class to store text headers, one type of
//        type-specific header.
//

#define TEXT_HEADER_SIZE    9
class TextHeader
{
    uint_32 _size;
    uint_32 _parAttrSize;
    uint_16 _headerSize;
    uint_16 _textSize;
    uint_8  _numColumns;
    uint_32 _flags;

    Buffer<uint_16> _tabStops;
    Buffer<uint_8>  _tabFlags;
    uint_16     _numStops, _maxStops;

    uint_32 _border;
    uint_16 _spacing[6];

    static const uint_32 _parBits[];

    Buffer<TextAttr>    _attribs;
    int         _numAttribs;
    int         _maxAttribs;

    static const uint_8 _attrBits[];
    static const int    _attrSizes[];

    TextHeader();
    ~TextHeader();

    // Functions to manipulate paragraph attributes (tabs, indents, ...)
    void    dumpTo( TopicLink *dest );
    int     setTab( int val, uint_8 flags );
    int     setPar( ParFlags type, int val );
    void    unsetPar( ParFlags type );
    void    clearPar();
    int     addAttr( FontFlags type, uint_32 val, char const str[], int length );
    int     appendAttr( int index, FontFlags type, uint_32 val,
                     char const str[], int length );
    void    chgAttr( int index, FontFlags type, uint_32 val,
                          char const str[], int length );
    uint_32 attrData( int index );
    void    reset();

    friend class HFTopic;
};


//
//  TextHolder  --Class to store raw text, for topic titles and help text.
//

#define TEXT_BLOCK_SIZE 0x200
#define TEXT_ZERO_SIZE  10
class TextHolder
{
    uint_32     _size;
    uint_32     _uncompSize;
    uint_32     _maxSize;
    Buffer<char>    _text;

    // Formatting changes are signalled by 0x00 bytes in the text;
    // I must be able to insert those zeroes in the middle of the text.

    Buffer<uint_16> _zeroes;
    uint_16     _numZeroes;
    uint_16     _maxZeroes;

    TextHolder();

    void    dumpTo( TopicLink *dest );
    void    reset() { _size = 0; _uncompSize = 0; _numZeroes = 0; };

    friend class HFTopic;
};


//  TopicLink::TopicLink

TopicLink::TopicLink( uint_32 s ) : _size( s ), _myData( s ), _isFirstLink(0)
{
    // empty
}


//  GenericNode::GenericNode

GenericNode::GenericNode( uint_32 prev )
    : _prevNode( prev ),
      _topicSize( GENERIC_NODE_SIZE ),
      _size( GENERIC_NODE_SIZE ),
      _dataSize( 0 ),
      _nextNode( ~0 )
{
    // empty
}


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

void GenericNode::dumpTo( TopicLink *dest )
{
    memcpy( dest->_myData, this, GENERIC_NODE_SIZE );   // EXTREME unsafeness!
    dest->_size = _size;
}


//  TopicHeader::TopicHeader

TopicHeader::TopicHeader( uint_32 tnum )
    : _topicNum( tnum ),
      _size( TOPIC_HEADER_SIZE ),
      _totalSize( 0 ),
      _nextTopic( ~0 ),
      _nextBrowse( ~0 ),
      _prevBrowse( ~0 ),
      _startNonScroll( ~0 ),
      _startScroll( ~0 )
{
    // empty
}


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

void TopicHeader::dumpTo( TopicLink *dest )
{
    memcpy( dest->_myData, this, TOPIC_HEADER_SIZE );   // EXTREME unsafeness!
    dest->_size = _size;
}


//  PageHeader::PageHeader

PageHeader::PageHeader()
    : _next(NULL)
{
    // empty
}


//  TextHeader c-tor and d-tor.

#define TSTOP_BLOCKS 10
TextHeader::TextHeader()
    : _tabStops( TSTOP_BLOCKS ),
      _tabFlags( TSTOP_BLOCKS ),
      _attribs( TEXT_ATTR_MAX ),
      _size( TEXT_HEADER_SIZE ),
      _parAttrSize( 0 ),
      _flags( 0 ),
      _numStops( 0 ),
      _maxStops( TSTOP_BLOCKS ),
      _numAttribs( 0 ),
      _maxAttribs( TEXT_ATTR_MAX )
{
    // empty
}


TextHeader::~TextHeader()
{
    reset();
}


//  TextHeader::reset   --Clear the text attributes.

void TextHeader::reset()
{
    for( int i=0; i<_numAttribs; i++ ){
    if( _attribs[i]._stringDat != NULL ){
        delete[] _attribs[i]._stringDat;
    }
    }
    _size = TEXT_HEADER_SIZE;
    _numColumns = 0;
    _numAttribs = 0;
}


//  The bitfields corresponding to paragraph attributes.
const uint_32 TextHeader::_parBits[] = {
                0x00020000,
            0x00040000,
            0x00080000,
            0x00100000,
            0x00200000,
            0x00400000,
            0x01000000,
            0x02000000,
            0x04000000,
            0x08000000,
            0x10000000
};


//  TextHeader::setTab  --Set a (possibly non-standard) tab stop.

#define INT_SMALL_LIMIT 0x80
#define INT_LARGE_LIMIT 0x4000
#define BORDER_BYTE_SIZE 3

int TextHeader::setTab( int val, uint_8 flag )
{
    uint_16 trueval;

    if( val < 0 ){
    return 0;
    } else if( val >= INT_LARGE_LIMIT ){
    return 0;
    }

    // Convert the value into WinHelp's bizarre format for
    // storing integers; see "topic.doc".

    trueval = (uint_16) (val/10);
    trueval <<= 1;
    if( trueval < INT_SMALL_LIMIT ){
    _parAttrSize += 1;
    } else {
    trueval |= 0x1;
    _parAttrSize += 2;
    }
    if( flag != 0x0 ){
    _parAttrSize += 1;
    if( trueval < INT_SMALL_LIMIT ){
        trueval |= 0x80;
    } else {
        trueval |= 0x8000;
    }
    }

    if( _numStops == 0 ){
    _parAttrSize += 1;
    } else if( _numStops == _maxStops ){
    _maxStops += TSTOP_BLOCKS;
    _tabStops.resize( _maxStops );
    _tabFlags.resize( _maxStops );
    }
    _tabStops[_numStops] = trueval;
    _tabFlags[_numStops] = flag;
    if( ++_numStops == 0x40 ){
    _parAttrSize += 1;
    }

    _flags |= _parBits[TOP_TAB_STOPS];
    return 1;
}


//  TextHeader::setPar  --Set a paragraph attribute.

int TextHeader::setPar( ParFlags type, int val )
{
    int already_set = _flags & _parBits[type];
    int sign;
    uint_16 trueval;
    if( val < 0 && type == TOP_TAB_STOPS ){
    return 0;
    }

    if( type == TOP_BORDER ){
    _border = (uint_32) val;
    _parAttrSize += BORDER_BYTE_SIZE;
    } else {
    // Convert the value into binary form.
    // This is complicated by WinHelp's bizarre format for
    // storing integers; see "topic.doc".
    if( type < TOP_RIGHT_JUST ){
        if( val == -1 ) return 1;
        sign = val < 0;
        if( sign ){
        val = -val;
        }
        if( val >= INT_LARGE_LIMIT ) {
        return 0;
        }
        trueval = (uint_16) (val/10);
        trueval <<= 1;
    }
    if( type == TOP_TAB_STOPS ){
        if( trueval < INT_SMALL_LIMIT ){
        _parAttrSize += 1;
        } else {
        trueval |= 0x1;
        _parAttrSize += 2;
        }

        if( _numStops == 0 ){
        _parAttrSize += 1;
        } else if( _numStops == _maxStops ){
        _maxStops += TSTOP_BLOCKS;
        _tabStops.resize( _maxStops );
        _tabFlags.resize( _maxStops );
        }
        _tabStops[ _numStops ] = trueval;
        _tabFlags[ _numStops ] = 0x0;
        if( ++_numStops == 0x40 ){
        _parAttrSize += 1;
        }
    } else if( type < TOP_TAB_STOPS ){
        if( already_set ){
        if( _spacing[ type ] & 0x1 ){
            _parAttrSize -= 2;
        } else {
            _parAttrSize -= 1;
        }
        }
        if( trueval < INT_SMALL_LIMIT ){
        trueval |= 0x80;
        _parAttrSize += 1;
        } else {
        trueval |= 0x8001;
        _parAttrSize += 2;
        }
        if( sign ){
        if( trueval & 01 ){
            trueval ^= (uint_16) ~1;
        } else {
            trueval ^= (uint_8) ~1;
        }
        trueval += 4;
        }
        _spacing[ type ] = trueval;
    }
    }
    _flags |= _parBits[type];
    return 1;
}


//  TextHeader::unsetPar  --Clear a paragraph attribute.

void TextHeader::unsetPar( ParFlags type )
{
    int already_set = _flags & _parBits[type];
    if( !already_set ) return;
    _flags ^= _parBits[type];
    if( type == TOP_TAB_STOPS ){
    _parAttrSize -= _numStops;
    for( int i=0; i < _numStops; ++i ){
        if( _tabStops[i] & 0x1 ){
        _parAttrSize -= 1;
        }
        if( _tabFlags[i] != 0 ){
        _parAttrSize -= 1;
        }
    }
    if( _numStops >= 0x40 ){
        _parAttrSize -= 2;
    } else if( _numStops > 0 ){
        _parAttrSize -= 1;
    }
    _numStops = 0;
    } else if( type == TOP_BORDER ){
    _parAttrSize -= BORDER_BYTE_SIZE;
    } else if( type < TOP_TAB_STOPS ){
    if( _spacing[type] & 0x1 ){
        _parAttrSize -= 2;
    } else {
        _parAttrSize -= 1;
    }
    }
}


//  TextHeader::clearPar  --Clear all paragraph attributes.

void TextHeader::clearPar()
{
    _flags = 0;
    _parAttrSize = 0;
    _numStops = 0;
}

// The flag values corresponding to text attributes.
const uint_8 TextHeader::_attrBits[] = {
    0x80, 0x81, 0x82, 0x83, 0x86, 0x87, 0x88, 0x89, 0xC8, 0xCC,
    0xE2, 0xE3, 0xE6, 0xE7, 0xEA, 0xEB, 0xEE, 0xEF, 0xFF
};

⌨️ 快捷键说明

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