optencod.c

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

C
1,981
字号
/****************************************************************************
*
*                            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:  Generate scaffolding for autogenerated option parsing.
*
****************************************************************************/


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

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

// functions that are supplied by the host environment
#define FN_UNGET        "OPT_UNGET"         // void ( void )
#define FN_GET_LOWER    "OPT_GET_LOWER"     // int ( void )
#define FN_RECOG        "OPT_RECOG"         // int ( int )
#define FN_RECOG_LOWER  "OPT_RECOG_LOWER"   // int ( int )
#define FN_END          "OPT_END"           // int ( void )

#define FN_NUMBER       "OPT_GET_NUMBER"    // int ( unsigned * )
#define FN_NUMBER_DEFAULT "OPT_GET_NUMBER_DEFAULT"  // int ( unsigned *, unsigned )
#define FN_NUMBER_MULTIPLE "OPT_GET_NUMBER_MULTIPLE"    // int ( OPT_NUMBER ** )
#define FN_CHAR         "OPT_GET_CHAR"      // int ( int * )
#define FN_CHAR_OPT     "OPT_GET_CHAR_OPT"  // int ( int * )
#define FN_ID           "OPT_GET_ID"        // int ( OPT_STRING ** )
#define FN_ID_OPT       "OPT_GET_ID_OPT"    // int ( OPT_STRING ** )
#define FN_FILE         "OPT_GET_FILE"      // int ( OPT_STRING ** )
#define FN_FILE_OPT     "OPT_GET_FILE_OPT"  // int ( OPT_STRING ** )
#define FN_DIR          "OPT_GET_DIR"       // int ( OPT_STRING ** )
#define FN_DIR_OPT      "OPT_GET_DIR_OPT"   // int ( OPT_STRING ** )
#define FN_PATH         "OPT_GET_PATH"      // int ( OPT_STRING ** )
#define FN_PATH_OPT     "OPT_GET_PATH_OPT"  // int ( OPT_STRING ** )

#define FN_CLEAN_STRING "OPT_CLEAN_STRING"    // void ( OPT_STRING ** )
#define FN_CLEAN_NUMBER "OPT_CLEAN_NUMBER"    // void ( OPT_NUMBER ** )

#define FN_PROCESS      "OPT_PROCESS"       // int ( OPT_STORAGE * )
#define FN_INIT         "OPT_INIT"          // void ( OPT_STORAGE * )
#define FN_FINI         "OPT_FINI"          // void ( OPT_STORAGE * )

#define USE_SWITCH_THRESHOLD    (4)
#define CONSOLE_WIDTH           (79)

unsigned line;
FILE *gfp;
FILE *ofp;
FILE *pfp;
FILE *ufp;
FILE *mfp;
FILE *bfp;

#define BUFF_SIZE       1024
static char ibuff[BUFF_SIZE];
static char tagbuff[BUFF_SIZE];
static char tokbuff[BUFF_SIZE];
static char enumbuff[BUFF_SIZE];
static char hdrbuff[BUFF_SIZE];
static char maxusgbuff[BUFF_SIZE];

typedef struct option OPTION;
typedef struct codeseq CODESEQ;

#define CHAIN_YES       0x01
#define CHAIN_USAGE     0x02
static char alternateEqual;
static char chainOption[256];
static char *chainUsage[256][LANG_MAX];
static char lastChain;
static unsigned maxUsageLen;
static char *pageUsage[LANG_MAX];
static unsigned targetMask;
static unsigned targetAnyMask;
static unsigned targetDbgMask;
static unsigned nextTargetMask = 1;

typedef enum tag_id {
#define TAG( s )        TAG_##s ,
#include "opttags.h"
    TAG_UNKNOWN,
    TAG_NULL
} tag_id;

static tag_id getsUsage = TAG_NULL;

#define TAG( s )        #s ,
char *tagNames[] = {
#include "opttags.h"
    NULL };

#define TAG( s )        static void do##s( char * );
#include "opttags.h"

#define TAG( s )        do##s ,
void (*processTag[])( char * ) = {
#include "opttags.h"
    NULL };

static char *validTargets[] = {
    "any",
    "i86",
    "386",
    "axp",
    "ppc",
    "dbg",
    "linux",
    "qnx",
    "sparc",
    NULL
};

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

static uint_8 const langMaxChar[] = {
    #define LANG_DEF( id, dbcs )        dbcs ,
    LANG_DEFS
    #undef LANG_DEF
};

static char *usageMsg[] = {
    "optencod [-i] [-q] [-u <usage-u>] <gml-file> <option-h> <parse-c> <usage-h> <target>*",
    "where:",
    "    <gml-file> is the tagged input GML file",
    "    <parse-h> is the output file for the command line parser",
    "    <usage-h> is the output file for the usage message",
    "    <usage-u> is the output file for the QNX usage file",
    "    <target> can be chosen from:",
    NULL
};

static struct {
    unsigned    international : 1;
    unsigned    quiet : 1;
    unsigned    no_equal : 1;
    unsigned    alternate_equal : 1;
} optFlag;

typedef struct target TARGET;
struct target {
    TARGET      *next;
    unsigned    mask;
    char        name[1];
};
static TARGET *targetList;

typedef struct name NAME;
struct name {
    NAME        *next;
    unsigned    is_timestamp : 1;
    char        name[1];
};

static NAME *enumList;
static NAME *enumeratorList;

struct option {
    OPTION      *next;
    OPTION      *synonym;
    char        *lang_usage[LANG_MAX];
    char        *check;
    char        *special;
    char        *special_arg_usage;
    char        *field_name;
    char        *value_field_name;
    NAME        *enumerate;
    char        *immediate;
    char        *code;
    unsigned    number_default;
    unsigned    target;
    unsigned    ntarget;
    unsigned    default_specified : 1;
    unsigned    is_simple : 1;
    unsigned    is_immediate : 1;
    unsigned    is_code : 1;
    unsigned    is_internal : 1;
    unsigned    is_multiple : 1;
    unsigned    is_number : 1;
    unsigned    is_id : 1;
    unsigned    is_char : 1;
    unsigned    is_file : 1;
    unsigned    is_dir : 1;
    unsigned    is_optional : 1;
    unsigned    is_path : 1;
    unsigned    is_special : 1;
    unsigned    is_prefix : 1;
    unsigned    is_timestamp : 1;
    unsigned    is_negate : 1;
    unsigned    nochain : 1;
    char        name[1];
};
static OPTION *optionList;
static OPTION *uselessOptionList;

#define HAS_OPT_STRING( o ) ( (o)->is_id || (o)->is_file || (o)->is_dir || (o)->is_path || (o)->is_special )
#define HAS_OPT_NUMBER( o ) ( (o)->is_number && (o)->is_multiple )

struct codeseq {
    CODESEQ     *sibling;
    CODESEQ     *children;
    OPTION      *option;
    int         c;
    unsigned    sensitive : 1;
    unsigned    accept : 1;
    unsigned    chain : 1;
};

typedef struct title TITLE;
struct title {
    TITLE       *next;
    unsigned    target;
    unsigned    ntarget;
    char        *lang_title[LANG_MAX];
};
static TITLE *titleList;
static TITLE *targetTitle;

enum {
    EC_CONTINUE         = 0x01,
    EC_NULL             = 0
};

static void fail( char *msg, ... )
{
    va_list args;

    if( line ) {
        fprintf( stderr, "error on line %u\n", line );
    }
    va_start( args, msg );
    vfprintf( stderr, msg, args );
    va_end( args );
    exit( EXIT_FAILURE );
}

static void dumpUsage( void )
{
    char **p;

    for( p = usageMsg; *p; ++p ) {
        fprintf( stderr, "%s\n", *p );
    }
    fprintf( stderr, "        " );
    for( p = validTargets; *p; ++p ) {
        fprintf( stderr, "%s ", *p );
    }
    fprintf( stderr, "\n", *p );
}

static void emitPrintf( unsigned depth, char *msg, ... )
{
    va_list args;
    unsigned i;

    for( i = ( depth >> 1 ); i != 0; --i ) {
        fprintf( pfp, "\t" );
    }
    if( depth & 1 ) {
        fprintf( pfp, "    " );
    }
    va_start( args, msg );
    vfprintf( pfp, msg, args );
    va_end( args );
}

static void addTarget( char *t )
{
    size_t len;
    TARGET *p;

    len = strlen( t );
    p = malloc( sizeof( *p ) + len );
    p->mask = nextTargetMask;
    p->next = targetList;
    targetList = p;
    strcpy( p->name, t );
    nextTargetMask <<= 1;
    if( nextTargetMask == 0 ) {
        fail( "too many targets defined\n" );
    }
}

static unsigned findTarget( char *t )
{
    TARGET *p;

    for( p = targetList; p != NULL; p = p->next ) {
        if( strcmp( t, p->name ) == 0 ) {
            return( p->mask );
        }
    }
    fail( "invalid target name '%s'\n", t );
    return( 0 );
}

static NAME *findName( NAME **h, char *n )
{
    NAME *p;

    for( p = *h; p != NULL; p = p->next ) {
        if( strcmp( n, p->name ) == 0 ) {
            return( p );
        }
    }
    return( NULL );
}

static NAME *addName( NAME **h, char *n )
{
    size_t len;
    NAME *p;

    len = strlen( n );
    p = malloc( sizeof(*p) + len );
    strcpy( p->name, n );
    p->next = *h;
    *h = p;
    return( p );
}

static NAME *addEnumerator( char *enumerate, char *field_name )
{
    NAME *n;

    strcpy( enumbuff, "OPT_" );
    strcat( enumbuff, enumerate );
    strcat( enumbuff, "_" );
    strcat( enumbuff, field_name );
    n = findName( &enumeratorList, enumbuff );
    if( n == NULL ) {
        n = addName( &enumeratorList, enumbuff );
    }
    return( n );
}

static void procCmdLine( int argc, char **argv )
{
    char **t;
    unsigned mask;

    if( argc < 5 ) {
        dumpUsage();
        exit( EXIT_FAILURE );
    }
    if( strcmp( argv[1], "-i" ) == 0 ) {
        optFlag.international = 1;
        --argc;
        ++argv;
    }
    if( strcmp( argv[1], "-q" ) == 0 ) {
        optFlag.quiet = 1;
        --argc;
        ++argv;
    }
    if( strcmp( argv[1], "-u" ) == 0 ) {
        mfp = fopen( argv[2], "wb" );
        if( !mfp ) fail( "cannot open '%s' for output", argv[2] );
        argc -= 2;
        argv += 2;
    }
    if( argc < 5 ) {
        dumpUsage();
        exit( EXIT_FAILURE );
    }
    ++argv;
    gfp = fopen( argv[0], "r" );
    if( !gfp ) fail( "cannot open '%s' for input", argv[0] );
    ++argv;
    ofp = fopen( argv[0], "w" );
    if( !ofp ) fail( "cannot open '%s' for output", argv[0] );
    ++argv;
    pfp = fopen( argv[0], "w" );
    if( !pfp ) fail( "cannot open '%s' for output", argv[0] );
    ++argv;
    ufp = fopen( argv[0], "w" );
    if( !ufp ) fail( "cannot open '%s' for output", argv[0] );
    ++argv;
    for( t = validTargets; *t; ++t ) {
        addTarget( *t );
    }
    targetAnyMask = findTarget( "any" );
    targetDbgMask = findTarget( "dbg" );
    targetMask |= targetAnyMask;
    while( *argv ) {
        mask = findTarget( *argv );
        targetMask |= mask;
        ++argv;
    }
}

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

static char *copyNonSpaceUntil( char *i, char *o, char t )
{
    for( ; *i; ++i ) {
        if( isspace( *i ) ) break;
        if( *i == t ) {
            ++i;
            break;
        }
        *o = *i;
        ++o;
    }
    *o = '\0';
    return( i );
}

static tag_id findTag( char *t )
{
    char **c;

    for( c = tagNames; *c; ++c ) {
        if( stricmp( t, *c ) == 0 ) {
            return( c - tagNames );
        }
    }
    fail( "unknown tag: %s\n", t );
    return( TAG_UNKNOWN );
}

static tag_id isTag( char **eot )
{
    tag_id tag;
    char *p;

    p = ibuff;
    p = skipSpace( p );
    if( *p == ':' ) {
        ++p;
        p = copyNonSpaceUntil( p, tagbuff, '.' );
        tag = findTag( tagbuff );
        if( tag != TAG_UNKNOWN ) {
            *eot = p;
            return( tag );
        }
    }
    return( TAG_NULL );
}

static OPTION *pushNewOption( char *name, OPTION *same )
{
    size_t len;
    OPTION *p;

    len = strlen( name );
    p = calloc( 1, sizeof( *p ) + len );
    p->synonym = same;
    strcpy( p->name, name );
    p->is_simple = 1;
    p->next = optionList;
    optionList = p;
    return( p );
}

static char *pickUpRest( char *p )
{
    size_t len;

    len = strlen( p );
    if( len != 0 ) {

⌨️ 快捷键说明

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