msgencod.c

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

C
1,536
字号
/****************************************************************************
*
*                            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 <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/stat.h>
#ifndef __UNIX__
#include <sys/utime.h>
#else
#include <sys/types.h>
#include <utime.h>
#endif
#ifdef __USE_BSD
#define stricmp strcasecmp
#endif

#include "lsspec.h"
#include "encodlng.h"

#define ALL_TAGS \
def_tag( msggrp ) \
def_tag( emsggrp ) \
def_tag( msggrptxt ) \
def_tag( msgjgrptxt ) \
def_tag( msggrpnum ) \
def_tag( msggrpstr ) \
def_tag( msgsym ) \
def_tag( msgtxt ) \
def_tag( msgjtxt ) \
def_tag( ansi ) \
def_tag( ansierr ) \
def_tag( ansiwarn ) \
def_tag( warning ) \
def_tag( info ) \
def_tag( ansicomp ) \
def_tag( errbad ) \
def_tag( eerrbad ) \
def_tag( errgood ) \
def_tag( eerrgood ) \
def_tag( errbreak ) \
def_tag( style ) \
def_tag( jck ) \

typedef enum {
#define def_tag( e ) TAG_##e,
    ALL_TAGS
#undef def_tag
    TAG_MAX
} tag_id;

static char *tagNames[] = {
#define def_tag( e ) #e "." ,
    ALL_TAGS
#undef def_tag
    NULL
};

#define ALL_MSG_TYPES \
def_msg_type( ERROR, "ERR_" ) \
def_msg_type( WARNING, "WARN_" ) \
def_msg_type( INFO, "INF_" ) \
def_msg_type( ANSI, "ANSI_" ) \
def_msg_type( ANSIERR, "ANSIERR_" ) \
def_msg_type( ANSIWARN, "ANSIWARN_" ) \
def_msg_type( STYLE, "WARN_" ) \
def_msg_type( JCK, "JCK_" ) \

typedef enum {
#define def_msg_type( e, p )    MSG_TYPE_##e,
    ALL_MSG_TYPES
    def_msg_type( END, "" )
#undef def_msg_type
} msg_type;

static char *msgTypeNames[] = {
#define def_msg_type( e, p )    "MSG_TYPE_" #e ,
    ALL_MSG_TYPES
#undef def_msg_type
};

static char *msgTypeNamesGP[] = {
#define def_msg_type( e, p )     #e ,
    ALL_MSG_TYPES
#undef def_msg_type
};

const char *langName[] = {
    #define LANG_DEF( id, dbcs )        #id ,
    LANG_DEFS
    #undef LANG_DEF
};

unsigned langTextCount[LANG_MAX];

typedef struct msggroup MSGGROUP;
typedef struct msgsym MSGSYM;
typedef struct word WORD;
typedef struct wordref WORDREF;

struct msggroup {
    MSGGROUP    *next;
    char        prefix[3];
    unsigned    msgIndex;    //first msg in group
    unsigned    emsgIndex;   //last message + 1
    unsigned    num;
    char        name[3];
};

struct msgsym {
    MSGSYM      *next;
    MSGSYM      *sortedByName[2];
    char        *lang_txt[LANG_MAX];
    char        *fname;
    unsigned    line;
    unsigned    index;
    unsigned    grpIndex;  //msg index in group
    msg_type    mtype;
    unsigned    level;
    unsigned    style : 1;
    MSGGROUP    *grp;
    WORDREF     *words;
    char        name[1];
};

struct word {
    WORD        *sortedByName[2];
    WORD        *sortedByRef[2];
    WORD        *all;
    unsigned    len;
    unsigned    index;
    unsigned    references;
    char        name[1];
};

struct wordref {
    WORDREF     *next;
    WORD        *word;
};

#define LINE_SIZE       (512)

static struct {
    unsigned    international:1;    // - dump internationalized data
    unsigned    quiet       : 1;    // - quiet mode
    unsigned    gen_pick    : 1;    // - generate pick macros unstead of #defines
    unsigned    grouped     : 1;    // - groups detected
    unsigned    have_msg    : 1;    // - have first message
    unsigned    gen_gpick   : 1;    // - generate generalized pick macros and tables
    unsigned    ignore_prefix : 1;  // - ignore matching XXX_ prefix with message type
    unsigned    warnings_always_rebuild:1;//- warnings gen files with old dates
                                    //   to constantly force rebuilds
} flags;

typedef enum {
    EK_NULL,
    EK_BAD,
    EK_GOOD,
} err_type;

static struct {
    unsigned    line;
    err_type    kind;
    unsigned    active : 1;
} examples;

static char *fname;
static FILE *i_gml;
static FILE *o_msgc;
static FILE *o_msgh;
static FILE *o_levh;

static WORD *allWords;
static WORD *nameWords;
static WORD *refWords;
static MSGSYM *messageSyms;
static MSGSYM **currMSGSYM = &messageSyms;
static MSGSYM *sortedSyms;
static MSGGROUP *allGroups;
static MSGGROUP *currGroup;

static unsigned groupIndex;
static unsigned groupCounter;
static unsigned messageIndex;
static unsigned messageCounter;
static unsigned line;
static unsigned errors;
static unsigned warnings;
static unsigned nextOutputFName;

static char *outputFNames[10];

static char *entireGML;
static char *currGML;
static char *ibuff;

// token buffers
static char tag[LINE_SIZE];
static char group[LINE_SIZE];
static char sym[LINE_SIZE];
static char word[LINE_SIZE];

// statistics
static unsigned uniqueWords;
static unsigned multiRefWords;
static unsigned maxWordLen;
static unsigned maxMsgLen;
static unsigned totalMsgLen;
static unsigned totalBytes;

// some local functions which need predefining
static void outputNum (FILE *fp, unsigned n);

// encoding
#define MAX_WORD_LEN    31
#define ENC_BIT         0x80
#define LARGE_BIT       0x40
#define USE_SMALL_ENC   0x3f

#define NO_INDEX        (-1)

static void error( char *f, ... ) {
    va_list args;

    ++errors;
    va_start( args, f );
    if( line ) {
        printf( "%s(%u): Error! E000: ", fname, line );
    }
    vprintf( f, args );
    va_end( args );
}

static void warn( char *f, ... ) {
    va_list args;

    ++warnings;
    va_start( args, f );
    if( line ) {
        printf( "%s(%u): Warning! W000: ", fname, line );
    }
    vprintf( f, args );
    va_end( args );
}

static void errorLocn( char *fn, unsigned ln, char *f, ... ) {
    va_list args;

    ++errors;
    va_start( args, f );
    if( ln ) {
        printf( "%s(%u): Error! E000: ", fn, ln );
    }
    vprintf( f, args );
    va_end( args );
}

static void fatal( char *m ) {
    error( "fatal: %s\n", m );
    exit( EXIT_FAILURE );
}

static void initFILE( FILE **f, char *n, char *m ) {
    *f = fopen( n, m );
    if( *f == NULL ) {
        fatal( "cannot open file" );
    }
    if( m[0] == 'r' ) {
        // read access
        fname = strdup( n );
    } else {
        // write access
        outputFNames[ nextOutputFName++ ] = n;
    }
}

static void processOptions( char **argv ) {
    if( strcmp( *argv, "-w" ) == 0 ) {
        flags.warnings_always_rebuild = 1;
        ++argv;
    }
    if( strcmp( *argv, "-i" ) == 0 ) {
        flags.international = 1;
        ++argv;
    }
    if( strcmp( *argv, "-ip" ) == 0 ) {
        flags.ignore_prefix = 1;
        ++argv;
    }
    if( strcmp( *argv, "-q" ) == 0 ) {
        flags.quiet = 1;
        ++argv;
    }
    if( strcmp( *argv, "-p" ) == 0 ) {
        flags.gen_pick = 1;
        ++argv;
    }
    if( strcmp( *argv, "-g" ) == 0 ) {
        flags.gen_gpick = 1;
        ++argv;
    }
    initFILE( &i_gml, *argv, "rb" );
    ++argv;
    initFILE( &o_msgc, *argv, "w" );
    ++argv;
    initFILE( &o_msgh, *argv, "w" );
    ++argv;
    initFILE( &o_levh, *argv, "w" );
    ++argv;
    if( *argv ) {
        fatal( "invalid argument" );
    }
}

static char *skipSpace( char *p ) {
    while( *p && isspace( *p ) ) {
        ++p;
    }
    return( p );
}

static char *skipNonSpace( char *t, char *p ) {
    while( *p && ! isspace( *p ) ) {
        *t = *p;
        ++t;
        ++p;
    }
    *t = '\0';
    return( p );
}

static tag_id getId( char *p, char **update_p ) {
    char *s;
    char **tc;

    s = skipNonSpace( tag, p );
    *update_p = skipSpace( s );
    if( s[-1] != '.' ) {
        error( "tag missing '.': %s\n", tag );
        return( TAG_MAX );
    }
    for( tc = tagNames; *tc; ++tc ) {
        if( stricmp( tag, *tc ) == 0 ) {
            return( tc - tagNames );
        }
    }
    error( "unknown tag: %s\n", tag );
    return( TAG_MAX );
}

static MSGSYM *mustBeProceededByMSGSYM( void ) {
    if( currMSGSYM == &messageSyms ) {
        error( "tag %s must be proceeded by :MSGSYM.\n", tag );
        fatal( "cannot continue" );
    }
    assert( offsetof( MSGSYM, next ) == 0 );
    return( (MSGSYM*)currMSGSYM );
}

static unsigned pickUpNum( char *p ) {
    unsigned num;

    p = skipSpace( p );
    num = 0;
    while( *p && isdigit( *p ) ) {
        num *= 10;
        num += *p - '0';
        ++p;
    }
    return( num );
}


static unsigned pickUpLevel( char *p ) {
    unsigned level;

    level = pickUpNum( p );
    if( level == 0 || level > 15 ) {
        error( "<level> can only be in the range 1-15\n" );
    }
    return( level );
}

static MSGSYM *addToSorted( MSGSYM *m ) {
    int s;
    MSGSYM **h;
    MSGSYM *c;
    char *name;

    name = m->name;
    h = &sortedSyms;
    for(;;) {
        c = *h;
        if( c == NULL ) break;
        s = strcmp( c->name, name );
        if( s < 0 ) {
            h = &(c->sortedByName[0]);
        } else if( s > 0 ) {
            h = &(c->sortedByName[1]);
        } else {
            return( c );
        }
    }
    *h = m;
    return( NULL );
}


#define do_msgjgrptxt   NULL
#define do_ansicomp     NULL
#define do_errbreak     NULL

static void noActive( err_type kind ) {
    if( examples.active ) {
        error( "example already active (started on line %u)\n", examples.line );
    }
    examples.active = 1;
    examples.kind = kind;
    examples.line = line;
}

static void yesActive( err_type check ) {
    if( ! examples.active ) {
        error( "no example active\n" );
    } else {
        if( examples.kind != check ) {
            error( "end example doesn't match start example on line %u\n", examples.line );
        }
    }
    examples.active = 0;
}

static void do_errbad( char *p ) {
    p = p;
    noActive( EK_BAD );
}

static void do_eerrbad( char *p ) {
    p = p;
    yesActive( EK_BAD );
}

static void do_errgood( char *p ) {
    p = p;
    noActive( EK_GOOD );
}

static void do_eerrgood( char *p ) {
    p = p;
    yesActive( EK_GOOD );
}

static void do_msggrptxt( char *p ) {
    p = p;
}

static void do_msggrpstr( char *p ) {
    MSGGROUP *grp;
    size_t len;

    grp = currGroup;
    p = skipNonSpace( group, p );
    len = strlen( group );
    if( len > 2 ) {
        error( ":msggrpstr value '%s' is too long\n", group );
        len = 2;
    }
    if( grp != NULL ){
        strncpy( grp->prefix, group, 2 ); //default
        grp->prefix[2] = '\0';
    }
}

static void do_msggrpnum( char *p ) {
    MSGGROUP *grp;
    grp = currGroup;
    groupIndex = pickUpNum( p );
    if( grp != NULL ){

⌨️ 快捷键说明

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