trie.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 275 行

C
275
字号
/****************************************************************************
*
*                            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 <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <sys/kernel.h>
#include <sys/dev.h>
#include <sys/sidinfo.h>
#include <errno.h>
#include <sys/psinfo.h>
#include <sys/proxy.h>
#include <sys/qioctl.h>
#include <sys/console.h>
#include <fcntl.h>
#include <assert.h>
#include <term.h>
#include <ctype.h>
#include "uidef.h"
#include "uishift.h"

#include "uivirt.h"
#include "qnxuiext.h"
#include "trie.h"

extern int      nextc( int n );
extern void     nextc_unget( char *, int );

/* The following types are for use with the keymap-trie. The keymap trie
 * is used to store all of the terminfo keypresses. The trie is fairly
 * compact, while also very fast. It also lends itself quite well to
 * key-lookup.
 */

#define EV_UNUSED ((EVENT)-1)

#define TRIE_ARRAY_GROWTH       4

#define TRIE_TOP                16

typedef struct eTrie eTrie;

typedef struct eNode{
    eTrie       *trie;          // the child sub-trie
    char        c;              // the character associated with it
    EVENT       ev;             // the event associated with the string
} eNode;

struct eTrie{
    eNode       *child;         // array of childeren
    int         num_child;      // number of children in array
    int         alc_child;      // allocated size of array
};

static eTrie    KeyTrie;
int             KeyTrieDepth=1;

int TrieInit(void)
{

    KeyTrie.child= malloc( TRIE_TOP * sizeof( eNode ) );
    if( KeyTrie.child == NULL ) return( FALSE );
    KeyTrie.alc_child = TRIE_TOP;
    KeyTrie.num_child = 0;
    return( TRUE );
}


static void free_subtrie( eNode *subt )
{
    int         i;

    if( subt==NULL ) return;

    if( subt->trie!=NULL ){
        for( i=0; i<subt->trie->num_child; i++ ){
            free_subtrie( &(subt->trie->child[i]) );
        }
        free( subt->trie );
    }
    free( subt );
}

/* frees the trie.
 */
void TrieFini( void )
{
    int         i;

    for( i=0; i<KeyTrie.num_child; i++ ){
        free_subtrie( &(KeyTrie.child[i]) );
    }
}

/* Search for children. Will return position
 * where child *should* be (this is why bsearch isn't good enough).
 * Currently only linear, but seems to be good enough. Note that
 * this is only used in initialization. Bsearch *is* used during
 * actual key parsing.
 */
static int child_search( char key, eTrie *trie )
{
    int         num;
    int         x;
    eNode       *ary;

    num= trie->num_child;
    if( num<1 )return(0);

    ary= trie->child;
    if( key>ary[num-1].c ) return(num);

    for( x=0; x < num; x++ ) {
        if(ary[x].c>=key) return(x);
    }

    return(num);
}

/* This function will add a string and matching event to KeyTrie. It adds
 * with the trie arrays sorted using linear insertion. It may be possible
 * to improve the performance, but I think any improvements would be slight,
 * as this function is only called at initialization.
 */
int TrieAdd( EVENT event, const char *str )
{
    eTrie       *trie=&KeyTrie;
    int         i;
    int         depth=1;

    if( *str == '\0' ) return( TRUE );

    for( ;; ) {
        i= child_search( *str, trie );

        if( i==trie->num_child || trie->child[i].c!=*str ) {
            // the char's not in the list, so we'd better add it

            trie->num_child++;

            if( trie->alc_child<trie->num_child ){
                //eNode                 *tmp;

                // the array isn't big enough, expand it a bit
                trie->alc_child+= TRIE_ARRAY_GROWTH;
                trie->child= realloc( trie->child, trie->alc_child*sizeof( eNode ) );
                if( trie->child== NULL ){
                    trie->alc_child= 0;
                    return( FALSE );
                }
            }

            if( i<(trie->num_child-1) ){
                // We're in the middle of the list, so clear a spot
                memmove( &(trie->child[i+1]), &(trie->child[i]),
                                (trie->num_child-i-1)*sizeof(eNode) );
            }

            trie->child[i].c = *str;
            trie->child[i].ev = EV_UNUSED;
            trie->child[i].trie = NULL;
        }

        // advance current char pointer
        str++;

        // by this point, "i" is set to the index of a matching sub-trie.
        if( *str=='\0' ) {
            // at the end of the string, so insert the event
            trie->child[i].ev= event;
            return( TRUE );
        }

        if( trie->child[i].trie==NULL ){
            // our "matching sub-trie" does not yet exist...
            trie->child[i].trie= calloc( 1, sizeof( eTrie ) );
            if( trie->child[i].trie==NULL ){
                return( FALSE );
            }
        }

        // go down a level, and work on the next char
        trie= trie->child[i].trie;
        depth++;
        if( depth > KeyTrieDepth ) KeyTrieDepth = depth;
    }
}

static int child_comp( const int *pkey, const eNode *pbase )
{
    return( *pkey - pbase->c );
}

EVENT TrieRead()
{
    eTrie       *trie;
    char        *buf;
    int         c;
    int         cpos=0;
    EVENT       ev = EV_UNUSED;
    int         ev_pos = 0;
    eNode       *node;
    int         timeout;

    buf = __alloca( KeyTrieDepth + 1 );

    trie = &KeyTrie;
    buf[0] = '\0';
    timeout = 0;
    for( ;; ) {
        c = nextc(timeout);
        if( c <= 0 ) break;
        buf[cpos++] = c;

        if( trie->num_child == 0 ) break;
        node = bsearch( &c, trie->child, trie->num_child, sizeof(eNode),
                            child_comp );
        if( node == NULL ) break;
        if( node->ev != EV_UNUSED ) {
            ev = node->ev;
            ev_pos = cpos;
        }
        trie = node->trie;
        if( trie == NULL ) break;
        timeout = 3;
    }
    if( ev == EV_UNUSED ) {
        ev = buf[0];
        ev_pos = 1;
    }

    // when we get down here cpos will be the number of chars in buf
    // note that the nul-char is not considered to actually be there
    // (the nul is sent on time-outs, and is guaranteed to never appear
    // in a terminfo keysequence as they are all nul-terminated.)

    if( cpos > ev_pos ) {
        nextc_unget( &buf[ev_pos], cpos-ev_pos );
    }
    return( ev );
}

⌨️ 快捷键说明

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