parsing.cpp
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C++ 代码 · 共 1,349 行 · 第 1/3 页
CPP
1,349 行
/****************************************************************************
*
* 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: .RTF file parsing.
*
****************************************************************************/
#include "parsing.h"
#include "hcerrors.h"
#include <string.h>
#include <ctype.h>
// Generate the list of supported RTF commands.
#define _COMMAND( n, s ) n
enum com_nums {
#include "../h/commands.h"
};
#undef _COMMAND
#define _COMMAND( n, s ) s
static char const *com_strs[] = {
#include "../h/commands.h"
};
#define TOPIC_LIMIT 512 // Arbitrary limit to topic size.
char const RtfExt[] = ".RTF";
// FindCommand --Map command strings to their assigned numbers.
// Returns (-1) for failure.
static int FindCommand( char const string[] )
{
int left=0, right=RC_DUMMY-1, _current, result;
// I use binary search; the list is reasonably small.
while( right >= left ){
_current = (left+right)/2;
result = strcmp( string, com_strs[_current] );
if( result < 0 ){
right = _current - 1;
} else if( result > 0 ){
left = _current + 1;
} else if( result == 0 ){
return _current;
}
}
return -1;
}
#define MAX_STATES 20
#define BLOCK_SIZE 80
// RTFparser::RTFparser --Mostly, this function just records
// where other important objects are.
RTFparser::RTFparser( Pointers *p, InFile *src )
: _storage( BLOCK_SIZE )
{
_topFile = p->_topFile;
_fontFile = p->_fontFile;
_hashFile = p->_hashFile;
_keyFile = p->_keyFile;
_titleFile = p->_titleFile;
_bitFiles = p->_bitFiles;
_sysFile = p->_sysFile;
_input = new Scanner( src );
_fname = new char[ strlen(src->name()) + 1];
strcpy( _fname, src->name() );
_nestLevel = 0;
_storSize = 0;
_maxStor = BLOCK_SIZE;
_tabType = TAB_LEFT;
}
// RTFparser::~RTFparser
RTFparser::~RTFparser()
{
delete _input;
if( _fname ) delete[] _fname;
}
// RTFparser::skipSection --Pass over RTF text until the "_nestLevel"
// decreases.
void RTFparser::skipSection()
{
int target = _nestLevel-1;
while( _nestLevel > target ){
_current = _input->next();
switch( _current->_type ){
case TOK_PUSH_STATE:
++_nestLevel;
break;
case TOK_POP_STATE:
--_nestLevel;
break;
case TOK_END:
HCWarning( RTF_BADEOF, _fname );
_wereWarnings = 1;
return;
}
}
return;
}
// RTFparser::closeBraces --Attempt to combine successive font changes.
// Returns the index of the final font.
uint_16 RTFparser::closeBraces()
{
uint_16 result = _fontFile->currentFont();
TokenTypes t_type;
for( ;; ){
t_type = _input->look(1)->_type;
if( t_type == TOK_PUSH_STATE ){
_fontFile->push();
++_nestLevel;
} else if( t_type == TOK_POP_STATE &&
_nestLevel > 0 ){
result = _fontFile->pop();
--_nestLevel;
} else if( t_type == TOK_COMMAND ){
if( !isFontCommand( _input->look(1), &result ) ){
break;
}
} else {
break;
}
_input->next();
}
return result;
}
// RTFparser::isParCommand --Identify commands which affect paragraph
// attributes (tab stops, indents, ...)
int RTFparser::isParCommand()
{
int result=0;
if( _input->look(1)->_type == TOK_COMMAND ){
int com_num = FindCommand( _input->look(1)->_text );
switch( FindCommand( _input->look(1)->_text ) ){
case RC_BOX:
case RC_FI:
case RC_LI:
case RC_KEEP:
case RC_KEEPN:
case RC_PARD:
case RC_RI:
case RC_QC:
case RC_QJ:
case RC_QL:
case RC_QR:
case RC_SA:
case RC_SB:
case RC_SL:
case RC_TX:
result = 1;
}
}
return result;
}
// RTFparser::isFontCommand --Identify a "font" command, AND implement
// the corresponding font change.
// The new font is stored in "newfont".
int RTFparser::isFontCommand( Token * tok, uint_16 *newfont )
{
int result;
int num = FindCommand( tok->_text );
// First check for a command which 'toggles' a font attribute.
switch( num ){
case RC_B:
case RC_I:
case RC_SCAPS:
case RC_STRIKE:
case RC_UL:
case RC_ULDB:
uint_8 style;
switch( num ){
case RC_B: style = FNT_BOLD; break;
case RC_I: style = FNT_ITALICS; break;
case RC_SCAPS: style = FNT_SMALL_CAPS; break;
case RC_STRIKE: style = FNT_STRIKEOUT; break;
case RC_UL: style = FNT_UNDERLINE; break;
case RC_ULDB: style = FNT_DBL_UNDER; break;
}
if( !tok->_hasValue || tok->_value != 0 ){
*newfont = _fontFile->setAttribs( style );
} else {
*newfont = _fontFile->clearAttribs( style );
}
result = 1;
break;
default:
// Now check for commands which change the base font.
switch( num ){
case RC_F:
if( tok->_hasValue ){
*newfont = _fontFile->selectFont( (short) tok->_value,
tok->_lineNum,
_input->file()->name() );
result = 1;
} else {
HCWarning( FONT_NONUM, tok->_lineNum, _fname );
_wereWarnings = 1;
tok->_type = TOK_NONE;
result = 0;
}
break;
case RC_FS:
if( tok->_hasValue ){
*newfont = _fontFile->newSize( (uint_8) (tok->_value) );
result = 1;
} else {
HCWarning( RTF_NOARG, (const char *) tok->_text,
tok->_lineNum, _fname );
_wereWarnings = 1;
tok->_type = TOK_NONE;
result = 0;
}
break;
case RC_PLAIN:
*newfont = _fontFile->clearAttribs( 0xFF );
result = 1;
break;
default:
result = 0;
}
}
return result;
}
// RTFparser::handleCommand --Implement non-font-related commands.
void RTFparser::handleCommand()
{
int com_num = FindCommand( _current->_text );
uint_8 attribs;
// two variables we may need to deal with a \par command.
uint_16 temp_font;
int is_new_topic;
// Certain commands may necessitate a new node in the |TOPIC file.
if( _writeState == HEADER ){
switch( com_num ){
case RC_LINE:
case RC_PAR:
case RC_SECT:
case RC_TAB:
case RC_V:
_writeState = SCROLL;
_topFile->newNode(0);
_topFile->addAttr( TOP_FONT_CHANGE, _curFont );
_topFile->startScroll();
}
}
switch( com_num ){
// Sections to skip 'cos they're unused in .HLP files.
case RC_COLORTBL: // actually, I should support this one.
case RC_INFO:
case RC_STYLESHEET:
skipSection();
break;
// Commands to ignore 'cos they're meaningless in .HLP files.
case RC_ENDNHERE:
case RC_FTNBJ:
case RC_LINEX:
case RC_SECTD:
case RC_ULW:
// do nothing
break;
case RC_BOX: // The "Boxed paragraph" command
_topFile->setPar( TOP_BORDER, 0x1 );
break;
case RC_DEFF: // The "Set Default Font" command
if( !_current->_hasValue ){
HCWarning( RTF_NOARG, (const char *) _current->_text,
_current->_lineNum, _fname );
_wereWarnings = 1;
} else {
_defFont = (uint_16) _current->_value;
}
break;
case RC_FI: // The "First Line Indent" command
if( !_current->_hasValue ){
HCWarning( RTF_NOARG, (const char *) _current->_text,
_current->_lineNum, _fname );
_wereWarnings = 1;
} else {
if( !_topFile->setPar( TOP_FIRST_INDENT, _current->_value ) ){
HCWarning( TOP_BADARG, _current->_value, _current->_lineNum, _fname );
_wereWarnings = 1;
}
}
break;
case RC_FONTTBL: // The "Font Table" command
if( !_current->_hasValue || _current->_value != 0 ){
handleFonts();
}
break;
case RC_KEEP: // The "No LineWrap" command
_topFile->setPar( TOP_NO_LINE_WRAP );
break;
case RC_KEEPN: // The "Start Non-scroll Area" command.
if( _writeState == HEADER ){
_topFile->newNode(0);
_topFile->addAttr( TOP_FONT_CHANGE, _curFont );
_topFile->startNonScroll();
_writeState = NON_SCROLL;
} else if( _writeState == SCROLL ){
HCWarning( RTF_LATEKEEPN, _current->_lineNum, _fname );
_wereWarnings = 1;
}
break;
case RC_LI: // The "Left Indent" command.
if( !_current->_hasValue ){
HCWarning( RTF_NOARG, (const char *) _current->_text,
_current->_lineNum, _fname );
_wereWarnings = 1;
} else {
if( !_topFile->setPar( TOP_LEFT_INDENT, _current->_value ) ){
HCWarning( TOP_BADARG, _current->_value, _current->_lineNum, _fname );
_wereWarnings = 1;
}
}
break;
case RC_LINE: // The "Explicit New-Line".
_topFile->addAttr( TOP_NEW_LINE );
break;
case RC_PAGE: // The "Hard Page".
// \page ALWAYS signals a new topic.
HCTick();
_topFile->newNode( 1 );
_topFile->clearPar();
_curFont = _fontFile->clearAttribs( 0xFF );
_writeState = HEADER;
break;
case RC_PAR: // "Paragraph return".
case RC_SECT: // deliberate fall-through
_topFile->addAttr( TOP_NEW_PAR );
_lastFont = _fontFile->clearAttribs( 0xFF );
temp_font = closeBraces();
// These commands signal a new topic if the next token is
// a paragraph command, or if the current topic has grown
// too large for comfort.
is_new_topic = _topFile->presentSize() >= TOPIC_LIMIT || isParCommand();
if( is_new_topic || _curFont != temp_font ){
if( is_new_topic ){
_topFile->newNode(0);
}
_curFont = temp_font;
int attr = _topFile->addAttr( TOP_FONT_CHANGE, _curFont );
attribs = _fontFile->getAttribs( _curFont );
if( attribs & ( FNT_UNDERLINE | FNT_STRIKEOUT |
FNT_DBL_UNDER ) ){
_hotlinkStart = attr;
}
}
break;
case RC_PARD: // "Set Paragraph Properties to Default"
_topFile->clearPar();
if( _writeState == NON_SCROLL ){
_topFile->startScroll();
_writeState = SCROLL;
}
_tabType = TAB_LEFT;
break;
case RC_QC: // Centre Justification
_topFile->unsetPar( TOP_RIGHT_JUST );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?