readstr.c

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

C
870
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "walloca.h"
#include "vi.h"
#include "keys.h"
#include "win.h"
#include "source.h"
#include "mouse.h"
#ifdef __WIN__
#include "winvi.h"
#include "utils.h"
#endif

#define HANDLED     0

typedef struct input_win_info {
    window_id       id;
    type_style      style;
    int             width;
    int             line;       /* we don't support multi-line input yet */
} input_win_info;

typedef struct input_buffer {
    char            *prompt;
    char            *buffer;
#ifdef __WIN__
    char            *cache;
#endif
    char            *last_str;
    int             buffer_length;
    history_data    *history;
    int             curr_hist;
    input_win_info  window;
    type_style      style;
    int             curr_pos;
    int             left_column;
    int             line;
    unsigned        overstrike:1;
} input_buffer;

/*
 * This is half of a kluge connected with the window proc for the
 * command window under the __WIN__ environs. Puke...
 */
bool ReadingAString = FALSE;

/*
 * General utility funtions:
 *      insertChar( input_buffer *, char ) - insert the given character at the
 *          current position paying attention to overstrike mode. This
 *          function will update curr_pos.
 *      deleteChar( input_buffer *, backwards ) - deletes the character at the
 *          current position if possible and updates curr_pos.
 *      displayLine( input_buffer * ) - displays the line in the window and
 *          sets the cursor to curr_pos.
 *      saveStr( input_buffer *, str ) - saves the string in the input buffer
 *          to the location given. Enough memory to hold string is assumed.
 */

static bool insertChar( input_buffer *input, int ch )
{
    char            *ptr;
    int             len;

    if( input->curr_pos >= input->buffer_length - 1 ) {
        return( FALSE );
    }

    /* if we are in overstrike more or at the end of the line... */
    if( input->overstrike ) {
        len = strlen( input->buffer ) + 1;
        input->buffer[ input->curr_pos++ ] = ch;
        if( input->curr_pos == len ) {
            input->buffer[ input->curr_pos ] = 0;
        }
    } else {
        if( strlen( input->buffer ) >= input->buffer_length - 1 ) {
            return( FALSE );
        }
        ptr = &input->buffer[ input->curr_pos++ ];
        memmove( ptr + 1, ptr, strlen( ptr ) + 1 );
        *ptr = ch;
    }
    if( input->curr_pos >= input->left_column + input->window.width - 1 ) {
        input->left_column += 1;
    }
    return( TRUE );

} /* insertChar */

static bool deleteChar( input_buffer *input, bool backwards )
{
    char            *ptr;

    if( backwards ) {
        if( input->curr_pos == 0 ) {
            return( FALSE );
        }
        input->curr_pos -= 1;
        if( input->curr_pos < input->left_column ) {
            input->left_column -= 1;
        }
    }
    ptr = &input->buffer[ input->curr_pos ];
    memmove( ptr, ptr + 1, strlen( ptr + 1 ) + 1 );
    return( TRUE );

} /* deleteChar */

static void displayLine( input_buffer *input )
{
    char            display[ MAX_STR ];
    char            *buffer, *dest;
    unsigned        length;
    int             cursor_pos;

    if( EditFlags.NoInputWindow ) {
        return;
    }
    assert( strlen( input->prompt ) < MAX_STR );
    strcpy( display, input->prompt );
    length = strlen( display );
    dest = &display[ length ];
    buffer = input->buffer + input->left_column;
    while( *buffer && length < input->window.width ) {
        *dest++ = *buffer++;
        length += 1;
    }
    *dest = 0;
    cursor_pos = input->curr_pos - input->left_column + 1;
    cursor_pos += strlen( input->prompt );
#ifdef __WIN__
{
    RECT        rect;
    char        *ptr, *c;
    int         len, x;
    HWND        id;

    id = (HWND) input->window.id;
    MyHideCaret( id );
    GetClientRect( id, &rect );
    // BlankRectIndirect( input->window.id, input->window.style.background, &rect );
    c = input->cache;
    for( len = 0, ptr = input->buffer; *ptr; ptr++, len++ ) {
        if( *c != *ptr ) {
            break;
        }
        c++;
    }
    x = MyTextExtent( id, &input->window.style, input->cache, len );
    WriteString( id, x, 0, &input->window.style, display + len );
    rect.left = MyTextExtent( id, &input->window.style, display, strlen( display ) );
    BlankRectIndirect( id, input->window.style.background, &rect );
    MyShowCaret( id );
    SetCursorOnLine( input->window.id, cursor_pos, display, &input->window.style );
}
#else
    DisplayLineInWindowWithColor( input->window.id, input->window.line,
        display, &input->window.style, 0 );
    SetGenericWindowCursor( input->window.id, input->window.line, cursor_pos );
#endif

} /* displayLine */

static bool endColumn( input_buffer *input )
{
    int         width, left;
    int         column;

    column = strlen( input->buffer );
    width = input->window.width - strlen( input->prompt );
    left = input->left_column;
    if( column >= left + width || column < left ) {
        left = column - width + 1;
        if( left < 0 ) {
            left = 0;
        }
    }
    input->curr_pos = column;
    input->left_column = left;
    return( TRUE );

} /* endColumn */

static bool saveStr( input_buffer *input )
{
    strcpy( input->last_str, input->buffer );
    return( TRUE );

} /* saveStr */

static bool swapString( input_buffer *input )
{
    char        *tmp;

    tmp = alloca( strlen( input->last_str ) + 1 );
    strcpy( tmp, input->last_str );
    strcpy( input->last_str, input->buffer );
    strcpy( input->buffer, tmp );
    endColumn( input );
    return( TRUE );

} /* swapString */

static int cursorKeyFilter( input_buffer *input, int event )
{
    int         max_pos;

    max_pos = strlen( input->buffer );
    switch( event ) {
    case HANDLED:
        break;
    case VI_KEY( HOME ):
        input->curr_pos = 0;
        input->left_column = 0;
        break;
    case VI_KEY( END ):
        endColumn( input );
        break;
    case VI_KEY( RIGHT ):
        if( input->curr_pos < max_pos ) {
            input->curr_pos += 1;
            if( input->curr_pos > input->left_column + input->window.width ) {
                input->left_column += 1;
            }
        } else {
            MyBeep();
        }
        break;
    case VI_KEY( LEFT ):
        if( input->curr_pos > 0 ) {
            input->curr_pos -= 1;
            if( input->left_column > input->curr_pos ) {
                input->left_column = input->curr_pos;
            }
        }
        break;
    case VI_KEY( DEL ):
    case VI_KEY( BS ):
        saveStr( input );
        if( !deleteChar( input, event == VI_KEY( BS )
            || input->curr_pos == max_pos ) ) {
            MyBeep();
        }
        break;
    default:
        return( event );
    }
    return( HANDLED );

} /* cursorKeyFilter */

/*
 * History functions:
 *      getHistory( input_buffer * ) - replace the input buffer with the
 *          currently selected history line (input->curr_hist).
 *      addHistory( input_buffer * ) - adds the current buffer to the
 *          history list associated with the input_buffer.
 *      searchHistory( input_buffer *, char *, int ) - starts searching
 *          at the specified index and returns the index of the first
 *          matching line in the history buffer or -1 if there are none.
 *      historyFilter( input_buffer *, int ) - pick out and take care of
 *          events which deal with the command line history.
 */

static bool getHistory( input_buffer *input )
{
    int             offset;
    char            *cmd;

    offset = input->curr_hist % input->history->max;
    cmd = input->history->data[ offset ];
    if( cmd != NULL ) {
        saveStr( input );
        strcpy( input->buffer, cmd );
        endColumn( input );
        return( TRUE );
    }
    return( FALSE );

} /* getHistory */

static bool addHistory( input_buffer *input )
{
    history_data    *h;

    h = input->history;
    if( h != NULL && input->buffer[ 0 ] != 0 ) {
        AddString2( &(h->data[ h->curr % h->max ] ), input->buffer );
        h->curr += 1;
        return( TRUE );
    }
    return( FALSE );

} /* addHistory */

static int searchHistory( input_buffer *input, char *str, int curr )
{
    int             index, i, len;
    history_data    *h;

    h = input->history;
    len = strlen( str );
    for( i = 0; i < h->max; i++ ) {
        curr -= 1;
        if( curr < 0 || curr < h->curr - h->max ) {
            curr = h->curr - 1;
        }
        index = curr % h->max;
        if( !strnicmp( str, h->data[ index ], len ) ) {
            strcpy( input->buffer, h->data[ index ] );
            endColumn( input );
            return( curr );
        }
    }
    MyBeep();
    return( -1 );

} /* searchHistory */

static void doHistorySearch( input_buffer *input )
{
    int             curr;
    char            *str;
    int             event;

    curr = input->history->curr;
    str = alloca( strlen( input->buffer ) + 1 );
    strcpy( str, input->buffer );
    event = VI_KEY( CTRL_TAB );
    while( curr != -1 ) {
        if( event == VI_KEY( ALT_TAB ) || event == VI_KEY( CTRL_TAB ) ) {
            saveStr( input );
            curr = searchHistory( input, str, curr );
            displayLine( input );
            event = GetNextEvent( TRUE );
            continue;
        }
        KeyAdd( event );
        return;
    }

} /* doHistorySearch */

static int historyFilter( input_buffer *input, int event )
{
    history_data    *h;

    if( input->history == NULL || input->history->curr == 0 ) {
        return( event );
    }
    h = input->history;
    switch( event ) {
    case VI_KEY( UP ):
        input->curr_hist -= 1;
        if( input->curr_hist < 0 || input->curr_hist < h->curr - h->max ) {
            input->curr_hist = h->curr - 1;
        }
        getHistory( input );
        break;
    case VI_KEY( DOWN ):
        input->curr_hist += 1;
        if( input->curr_hist >= h->curr ) {
            input->curr_hist = h->curr - h->max;
            if( input->curr_hist < 0 ) {
                input->curr_hist = 0;
            }
        }
        getHistory( input );
        break;
    case VI_KEY( CTRL_TAB ):
    case VI_KEY( ALT_TAB ):
        doHistorySearch( input );
        break;
    default:
        return( event );
    }
    return( HANDLED );

} /* historyFilter */

/*
 * Special key (ALT_L etc... ) functions:
 *      insertString( input_buffer *, char * ) - insert the given string at
 *          the current location and bump the current position.
 *      specialKeyFilter( input_buffer *, int ) - pick out and handle any
 *          events which map to special keys.
 */

static bool insertString( input_buffer *input, char *str )
{
    while( *str ) {
        if( !insertChar( input, *str++ ) ) {
            return( FALSE );
        }
    }
    return( TRUE );

} /* insertString */

/*

⌨️ 快捷键说明

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