help.c

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

C
1,490
字号
/****************************************************************************
*
*                            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:  Help file access functions.
*
****************************************************************************/


#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>

#include "uidef.h"
#include "helpmem.h"
#include "stdui.h"
#include "uibox.h"
#include "help.h"
#include "hlpuicvr.h"
#include "hlputkys.h"
#include "uidialog.h"
#include "uimenu.h"
#include "uitab.h"
#include "helpscan.h"
#include "msgbox.h"
#include "uigchar.h"
#ifndef __WATCOMC__
    #include "clibext.h"
#endif


extern  EVENT   uivget( VSCREEN * );

static int CheckHelpBlock( HelpFp help_file, char *topic, char *buffer,
                           long int start );
static void replacetopic( char *word );
int do_showhelp( char **helptopic, char *filename, EVENT (*rtn)( EVENT ),
                 bool first );

// In normal QNX text files, the record separator is just a LF.
// However, with the new help file format containing both binary and
// text data, we can't do a text conversion, so the record separator
// is still a CR/LF from DOS. So the RSEP_LEN is 2.

#define RSEP_LEN                2

#if defined( QNX )
    #define EV_MARK_PRESS       EV_CTRL_PRESS
    #define EV_MARK_RELEASE     EV_CTRL_RELEASE
#else
    #define EV_MARK_PRESS       EV_SHIFT_PRESS
    #define EV_MARK_RELEASE     EV_SHIFT_RELEASE
#endif

#define AT(x) UIData->attrs[x]
#define AT_BLINK  0x80

#define TRUE  1
#define FALSE 0


#define C_PLAIN         0
#define C_ULINE         1
#define C_BOLD          2
#define C_ULBOLD        3

#define HELP_MIN_WIDTH          63

#define BUF_LEN 400

enum {
    HSTCK_NAME,
    HSTCK_OFFSET
};

typedef struct hstackent {
    struct hstackent    *next;
    int                 cur;
    int                 line;
    int                 type;
    char                helpfname[_MAX_PATH];
    char                word[1];        /* dynamic array */
}a_hstackent;

typedef struct a_field {
    SAREA               area;
    struct a_field      *next;
    unsigned            key1_len;
    unsigned            key2_len;
    char                keyword[1];
} a_field;

typedef struct {
    char        *buf;
    int         pos;
    bool        changecurr;
    int         line;
} ScanInfo;

static VSCREEN helpScreen = {
    EV_NO_EVENT,                    /* event number */
    NULL,                           /* screen title */
    {0, 0, 0, 0},                   /* location and size */
    V_NO_ZOOM | V_DIALOGUE,         /* flags */
    0, 0,                           /* initial cursor position */
    C_OFF                           /* cursor type */
};

static a_gadget         vGadget = {
    NULL,                       /* window */
    VERTICAL,                   /* direction */
    0,                          /* anchor position */
    0,                          /* start of bar */
    0,                          /* end of bar */
    E_DOWN,                     /* forward event */
    E_UP,                       /* backward event */
    EV_PAGE_DOWN,               /* forward page event */
    EV_PAGE_UP,                 /* backward page event */
    EV_NO_EVENT,                /* slider event */
    0,                          /* total size */
    0,                          /* page size */
    0,                          /* current position */
    FALSE                       /* lockable */
};

static a_hot_spot              hotSpots[] = {
    { "&Back",            EV_FUNC(4),     -1,       1,     15, 0  },
    { "&Search",          EV_ALT_S,       -1,       0,     15, 0  },
    { "Cancel",           EV_ESCAPE,      -1,      -2,     15, 0  },
    { NULL,               EV_NO_EVENT }
    };

#define SEARCH_HOT_SPOT         2

static a_hot_spot_field       hotSpotFields[] = {
    {{0}, FLD_HOT, &hotSpots[0] },
    {{0}, FLD_HOT, &hotSpots[2] },
    {{0}, FLD_HOT, &hotSpots[1] },
    {{0}, FLD_VOID,NULL }
    };

static EVENT keyShift[] = {
    EV_NO_EVENT,
    EV_ALT_FUNC_12,
    EV_MARK_PRESS,      EV_MARK_RELEASE,
    EV_MOUSE_RELEASE,   EV_MOUSE_DRAG,
    EV_INSERT,          EV_DELETE,
    EV_MOUSE_DCLICK,
    EV_NO_EVENT
};

static EVENT helpEventList[] = {
    EV_NO_EVENT,             /* end of event-range pairs */
    EV_ALT_B, 'b', 'B',
    EV_ALT_S, 's', 'S',
    EV_CURSOR_LEFT,
    EV_CURSOR_RIGHT,
    EV_TAB_FORWARD,
    EV_TAB_BACKWARD,
    EV_ENTER,
    EV_ESCAPE,
    EV_HELP,
    EV_PAGE_UP,
    EV_PAGE_DOWN,
    '-','+',
    EV_FUNC(4),
    EV_FUNC(9),
    EV_FUNC(10),
    EV_CURSOR_UP,
    EV_CURSOR_DOWN,
    EV_TOP,
    EV_BOTTOM,
    EV_SCROLL_VERTICAL,
    EV_MOUSE_PRESS,
    EV_MOUSE_REPEAT,
    EV_MOUSE_RELEASE,
    EV_MOUSE_RELEASE_R,
    EV_FIELD_CHANGE,
    E_UP,
    E_DOWN,
    EV_NO_EVENT };           /* end of single event list */

static a_hstackent      *helpStack;
static a_field          *helpTab;
static a_field          *helpCur;
static char             *helpInBuf;
static char             *helpOutBuf;
static char             helpWord[] = { "HELP" };
static int              helpLines;
static unsigned         *helpPos;
static long             topPos;
static int              maxPos;
static int              maxLine;
static int              currLine;
static int              lastHelpLine;
static int              currentAttr;
static int              currentColour;
static bool             ignoreMouseRelease;

static char             curFile[_MAX_PATH];
static HelpFp           helpFileHdl;
static HelpHdl          helpSearchHdl;
static VTAB             tabFilter;
static EVENT            curEvent;
static EVENT            (*eventMapFn)();

extern a_ui_edit        *UIEdit;

static void window_pos( ORD *start, ORD *size, int slack, int pos )
{
    ORD         bump;

    if( slack > 0 ) {
        if( pos == 0 ) {
            bump = slack / 2;
        } else if( pos > 0 ) {
            if( --pos > slack ) {
                pos = slack;
            }
            bump = pos;
        } else {
            pos = -pos;
            if( --pos > slack ) {
                pos = slack;
            }
            bump = slack - pos;
        }
        *start += bump;
        *size -= slack;
    }
}


SAREA *hlp_ut_screen_area( SAREA *area, bool all, bool framed )
{
    area->col = framed;
    area->width = UIData->width - 2*framed;
    area->row = framed;
    area->height = UIData->height - 2*framed;
    if( !all  &&  uimenuson() ) {
        area->row += 1;
        area->height -= 1;
    }
    return( area );
}

void hlp_ut_position( SAREA *a, ORD h, ORD w, int rpos, int cpos, bool overmenus )
{
    hlp_ut_screen_area( a, overmenus, TRUE );
    if( h > 0 ) {
        window_pos( &a->row, &a->height, a->height - h, rpos );
    }
    if( w > 0 ) {
        window_pos( &a->col, &a->width, a->width - w, cpos );
    }
}

static void addSearchButton( bool add )
{
    if( add ) {
        hotSpotFields[SEARCH_HOT_SPOT].typ = FLD_HOT;
        hotSpotFields[SEARCH_HOT_SPOT].ptr = &hotSpots[1];
    } else {
        hotSpotFields[SEARCH_HOT_SPOT].typ = FLD_VOID;
        hotSpotFields[SEARCH_HOT_SPOT].ptr = NULL;
    }
}

/*
 * helpGetString
 */
static char *helpGetString( char *buf, size_t size, HelpFp fp )
{
    long int            pos;
    int                 bytesread;
    int                 cnt;

    pos = HelpTell( fp );
    bytesread = HelpRead( fp, buf, size - 1 );
    if( bytesread == 0 || bytesread == -1 ) return( NULL );
    cnt = 0;
    while( cnt < bytesread ) {
        if( buf[cnt] == '\n' ) {
            cnt++;
            break;
        }
        cnt ++;
    }
    HelpSeek( fp, pos + cnt, HELP_SEEK_SET );
    buf[cnt] = '\0';
    return( buf );
}

/*
 * OpenTopicInFile - open a help file and look for a topic
 */
static int OpenTopicInFile( help_file *fileinfo, char *topic, char *buffer )
{
    long int            start_offset;     /* - starting offset in HELP file        */
    long int            size_left;        /* - size left to search                 */
    int                 next_posn;        /* - contains indicator for next pos'n   */
    unsigned long       topic_pos;

    if( fileinfo->f == -1 ) return( 0 );
    if( fileinfo->searchhdl != NULL ) {
        /* search by new method */
        topic_pos = HelpFindTopicOffset( fileinfo->searchhdl, topic );
        if( topic_pos == (unsigned long)-1 ) {
            return( 0 );
        } else {
            HelpSeek( fileinfo->f, topic_pos, HELP_SEEK_SET );
            if( helpGetString( buffer, BUF_LEN, fileinfo->f ) == NULL ) {
                return( 0 );
            } else {
                return( 1 );
            }
        }
    } else {
        start_offset = 0L;
    }
    size_left = HelpFileLen( fileinfo->f );
    do {
        size_left = size_left / 2;
        if( size_left <= 8 ) {
            if( CheckHelpBlock( fileinfo->f, topic, buffer, start_offset ) != 0 ) {
                return( 0 );
            } else {
                return( 1 );
            }
        }
        next_posn = CheckHelpBlock( fileinfo->f, topic, buffer,
                                    start_offset + size_left );
        if( next_posn > 0 ) {
            start_offset += size_left;
        }
    } while( next_posn != 0 );
    return( 1 );
}

static char *scanTopic( char *buf, char **theend )
{
    char        *topic;
    char        *end;

    if( memcmp( buf, "::::", 4 ) != 0 ) return( NULL );
    if( buf[4] == '"' ) {
        topic = buf + 5;
        end = topic;
        while( *end != '"' && *end != '\0' ) {
            if( *end == HELP_ESCAPE ) end++;
            end++;
        }
    } else {
        topic = buf + 5;
        while( *topic == ' ' ) topic++;
        end = topic;
        while( *end != ' ' && *end != '\n' && end != '\0' ) end++;
    }
    if( theend != NULL ) *theend = end;
    return( topic );
}

/*
 * CheckHelpBlock - see if a topic is in the 2nd half of a block
 */
static int CheckHelpBlock( HelpFp help_file, char *topic, char *buffer,
                           long int start )
{
    int         retn;
    char        *ftopic;
    char        *end;
    unsigned    len;

    HelpSeek( help_file, start, HELP_SEEK_SET );
    retn = 0;
    do {
        if( helpGetString( buffer, BUF_LEN, help_file ) == NULL ) {
            retn = -1;
            break;
        }
    } while( memcmp( buffer, "::::", 4 ) != 0 );
    if( retn == 0 ) {
        ftopic = scanTopic( buffer, &end );
        len = end - ftopic;
        retn = strnicmp( topic, ftopic, len );
        if( !retn && topic[ len ] != '\0' ) retn = 1;
    }
    return( retn );
}

static void help_close( void )
{
    help_file *h;

    for( h = HelpFiles; h->name != NULL; ++h ) {
        if( h->f != 0 ) {
            HelpClose( h->f );
            FiniHelpSearch( h->searchhdl );
            h->searchhdl = NULL;
            h->f = 0;
        }
    }
}

/*
 * help_open - open a help file at a topic location
 */
static help_file *help_open( char *buffer )
{
    help_file   *h;
    char        *newtopic;

    for( h=HelpFiles; h->name != NULL; ++h ) {
        if( h->f == 0 ) {
            /* text files screw up ctrl z */
            h->f = HelpOpen( h->name, HELP_OPEN_RDONLY | HELP_OPEN_BINARY );
            h->searchhdl = InitHelpSearch( h->f );
        }
        if( helpStack->word[0] == '\0' ) {
            newtopic = GetDefTopic( h->searchhdl );
            replacetopic( newtopic );
        }
        if( OpenTopicInFile( h, helpStack->word, buffer ) ) {
            break;
        }
    }
    if( h->name == NULL ) return( NULL );
    return( h );
}


static void add_field( a_field *ht, bool changecurr )
{
    a_field             **p;
    int                 count;

    count = 0;
    for( p=&helpTab; ; p = &((*p)->next) ) {
        if( *p == NULL
        ||  (*p)->area.row > ht->area.row
        || ((*p)->area.row == ht->area.row  &&  (*p)->area.col > ht->area.col )
        ) {
            ht->next = *p;
            *p = ht;
            if( changecurr && count < helpStack->cur ) {
                helpStack->cur += 1;
            }
            break;
        }
        ++count;
    }
    tabFilter.first = helpTab;
}

static int field_count( a_field *table, a_field *field )
{
    int                 i;

    if( field == NULL ) return( 0 );
    for( i = 0; table != NULL; table = table->next, ++i ) {
        if( table == field ) {
            return( i );
        }
    }
    return( 0 );
}

static void del_field( a_field *table, a_field **field, bool changecurr )
{
    a_field             *next;
    int                 count;

    count = field_count( table, *field );

⌨️ 快捷键说明

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