⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 options.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*
*   $Id: options.c,v 1.25 2004/02/28 15:19:45 darren Exp $
*
*   Copyright (c) 1996-2003, Darren Hiebert
*
*   This source code is released for free distribution under the terms of the
*   GNU General Public License.
*
*   This module contains functions to process command line options.
*/

/*
*   INCLUDE FILES
*/
#include "general.h"	/* must always come first */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>	/* to declare isspace () */

#include "ctags.h"
#include "debug.h"
#include "main.h"
#define OPTION_WRITE
#include "options.h"
#include "parse.h"
#include "routines.h"

/*
*   MACROS
*/
#define INVOCATION  "Usage: %s [options] [file(s)]\n"

#define CTAGS_ENVIRONMENT	"CTAGS"
#define ETAGS_ENVIRONMENT	"ETAGS"

#define CTAGS_FILE	"tags"
#define ETAGS_FILE	"TAGS"

#ifndef ETAGS
# define ETAGS	"etags"		/* name which causes default use of to -e */
#endif

/*  The following separators are permitted for list options.
 */
#define EXTENSION_SEPARATOR '.'
#define PATTERN_START '('
#define PATTERN_STOP  ')'
#define IGNORE_SEPARATORS   ", \t\n"

#ifndef DEFAULT_FILE_FORMAT
# define DEFAULT_FILE_FORMAT	2
#endif

#if defined (HAVE_OPENDIR) || defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) || defined (AMIGA)
# define RECURSE_SUPPORTED
#endif

#define isCompoundOption(c)	(boolean) (strchr ("fohiILpDb", (c)) != NULL)

/*
*   Data declarations
*/

enum eOptionLimits {
    MaxHeaderExtensions	= 100,	/* maximum number of extensions in -h option */
    MaxSupportedTagFormat = 2
};

typedef struct sOptionDescription {
    int usedByEtags;
    const char *description;
} optionDescription;

typedef void (*parametricOptionHandler) (const char *const option, const char *const parameter);

typedef const struct {
    const char* name;		/* name of option as specified by user */
    parametricOptionHandler handler;	/* routine to handle option */
    boolean initOnly;		/* option must be specified before any files */
} parametricOption;

typedef const struct {
    const char* name;		/* name of option as specified by user */
    boolean* pValue;		/* pointer to option value */
    boolean initOnly;		/* option must be specified before any files */
} booleanOption;

/*
*   DATA DEFINITIONS
*/

static boolean NonOptionEncountered;
static stringList *OptionFiles;
static stringList* Excluded;
static boolean FilesRequired = TRUE;
static boolean SkipConfiguration;

static const char *const HeaderExtensions [] = {
    "h", "H", "hh", "hpp", "hxx", "h++", "inc", "def", NULL
};

optionValues Option = {
    {
	FALSE,		/* --extra=f */
	FALSE,		/* --extra=q */
	TRUE,		/* --file-scope */
    },
    {
	FALSE,		/* -fields=a */
	TRUE,		/* -fields=f */
	FALSE,		/* -fields=m */
	FALSE,		/* -fields=i */
	TRUE,		/* -fields=k */
	FALSE,		/* -fields=z */
	FALSE,		/* -fields=K */
	FALSE,		/* -fields=l */
	FALSE,		/* -fields=n */
	TRUE,		/* -fields=s */
	FALSE		/* -fields=S */
    },
    NULL,		/* -I */
    FALSE,		/* -a */
    FALSE,		/* -B */
    FALSE,		/* -e */
#ifdef MACROS_USE_PATTERNS
    EX_PATTERN,		/* -n, --excmd */
#else
    EX_MIX,		/* -n, --excmd */
#endif
    FALSE,		/* -R */
    SO_SORTED,		/* -u, --sort */
    FALSE,		/* -V */
    FALSE,		/* -x */
    NULL,		/* -L */
    NULL,		/* -o */
    NULL,		/* -h */
    NULL,		/* --etags-include */
    DEFAULT_FILE_FORMAT,/* --format */
    FALSE,		/* --if0 */
    FALSE,		/* --kind-long */
    LANG_AUTO,		/* --lang */
    TRUE,		/* --links */
    FALSE,		/* --filter */
    NULL,		/* --filter-terminator */
    FALSE,		/* --tag-relative */
    FALSE,		/* --totals */
    FALSE,		/* --line-directives */
#ifdef DEBUG
    0, 0		/* -D, -b */
#endif
};

/*
-   Locally used only
*/

static optionDescription LongOptionDescription [] = {
 {1,"  -a   Append the tags to an existing tag file."},
#ifdef DEBUG
 {1,"  -b <line>"},
 {1,"       Set break line."},
#endif
 {0,"  -B   Use backward searching patterns (?...?)."},
#ifdef DEBUG
 {1,"  -D <level>"},
 {1,"       Set debug level."},
#endif
 {0,"  -e   Output tag file for use with Emacs."},
 {1,"  -f <name>"},
 {1,"       Write tags to specified file. Value of \"-\" writes tags to stdout"},
 {1,"       [\"tags\"; or \"TAGS\" when -e supplied]."},
 {0,"  -F   Use forward searching patterns (/.../) (default)."},
 {1,"  -h <list>"},
 {1,"       Specify list of file extensions to be treated as include files."},
 {1,"       [\".h.H.hh.hpp.hxx.h++\"]."},
 {1,"  -I <list|@file>"},
 {1,"       A list of tokens to be specially handled is read from either the"},
 {1,"       command line or the specified file."},
 {1,"  -L <file>"},
 {1,"       A list of source file names are read from the specified file."},
 {1,"       If specified as \"-\", then standard input is read."},
 {0,"  -n   Equivalent to --excmd=number."},
 {0,"  -N   Equivalent to --excmd=pattern."},
 {1,"  -o   Alternative for -f."},
#ifdef RECURSE_SUPPORTED
 {1,"  -R   Equivalent to --recurse."},
#else
 {1,"  -R   Not supported on this platform."},
#endif
 {0,"  -u   Equivalent to --sort=no."},
 {1,"  -V   Equivalent to --verbose."},
 {1,"  -x   Print a tabular cross reference file to standard output."},
 {1,"  --append=[yes|no]"},
 {1,"       Should tags should be appended to existing tag file [no]?"},
 {1,"  --etags-include=file"},
 {1,"      Include reference to 'file' in Emacs-style tag file (requires -e)."},
 {1,"  --exclude=pattern"},
 {1,"      Exclude files and directories matching 'pattern'."},
 {0,"  --excmd=number|pattern|mix"},
#ifdef MACROS_USE_PATTERNS
 {0,"       Uses the specified type of EX command to locate tags [pattern]."},
#else
 {0,"       Uses the specified type of EX command to locate tags [mix]."},
#endif
 {1,"  --extra=[+|-]flags"},
 {1,"      Include extra tag entries for selected information (flags: \"fq\")."},
 {1,"  --fields=[+|-]flags"},
 {1,"      Include selected extension fields (flags: \"afmikKlnsSz\") [fks]."},
 {1,"  --file-scope=[yes|no]"},
 {1,"       Should tags scoped only for a single file (e.g. \"static\" tags"},
 {1,"       be included in the output [yes]?"},
 {1,"  --filter=[yes|no]"},
 {1,"       Behave as a filter, reading file names from standard input and"},
 {1,"       writing tags to standard output [no]."},
 {1,"  --filter-terminator=string"},
 {1,"       Specify string to print to stdout following the tags for each file"},
 {1,"       parsed when --filter is enabled."},
 {0,"  --format=level"},
#if DEFAULT_FILE_FORMAT == 1
 {0,"       Force output of specified tag file format [1]."},
#else
 {0,"       Force output of specified tag file format [2]."},
#endif
 {1,"  --help"},
 {1,"       Print this option summary."},
 {1,"  --if0=[yes|no]"},
 {1,"       Should C code within #if 0 conditional branches be parsed [no]?"},
 {1,"  --<LANG>-kinds=[+|-]kinds"},
 {1,"       Enable/disable tag kinds for language <LANG>."},
 {1,"  --langdef=name"},
 {1,"       Define a new language to be parsed with regular expressions."},
 {1,"  --langmap=map(s)"},
 {1,"       Override default mapping of language to source file extension."},
 {1,"  --language-force=language"},
 {1,"       Force all files to be interpreted using specified language."},
 {1,"  --languages=[+|-]list"},
 {1,"       Restrict files scanned for tags to those mapped to langauges"},
 {1,"       specified in the comma-separated 'list'. The list can contain any"},
 {1,"       built-in or user-defined language [all]."},
 {1,"  --license"},
 {1,"       Print details of software license."},
 {0,"  --line-directives=[yes|no]"},
 {0,"       Should #line directives be processed [no]?"},
 {1,"  --links=[yes|no]"},
 {1,"       Indicate whether symbolic links should be followed [yes]."},
 {1,"  --list-kinds=language|all"},
 {1,"       Output a list of all tag kinds for specified language or all."},
 {1,"  --list-languages"},
 {1,"       Output list of supported languages."},
 {1,"  --options=file"},
 {1,"       Specify file from which command line options should be read."},
 {1,"  --recurse=[yes|no]"},
#ifdef RECURSE_SUPPORTED
 {1,"       Recurse into directories supplied on command line [no]."},
#else
 {1,"       Not supported on this platform."},
#endif
#ifdef HAVE_REGEX
 {1,"  --regex-<LANG>=/line_pattern/name_pattern/[flags]"},
 {1,"       Define regular expression for locating tags in specific language."},
#endif
 {0,"  --sort=[yes|no|foldcase]"},
 {0,"       Should tags be sorted (optionally ignoring case) [yes]?."},
 {0,"  --tag-relative=[yes|no]"},
 {0,"       Should paths be relative to location of tag file [no; yes when -e]?"},
 {1,"  --totals=[yes|no]"},
 {1,"       Print statistics about source and tag files [no]."},
 {1,"  --verbose=[yes|no]"},
 {1,"       Enable verbose messages describing actions on each source file."},
 {1,"  --version"},
 {1,"       Print version identifier to standard output."},
 {1, NULL}
};

static const char* const License1 =
"This program is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU General Public License\n"
"as published by the Free Software Foundation; either version 2\n"
"of the License, or (at your option) any later version.\n"
"\n";
static const char* const License2 =
"This program is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
"GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n";

/*  Contains a set of strings describing the set of "features" compiled into
 *  the code.
 */
static const char *const Features [] = {
#ifdef WIN32
    "win32",
#endif
#ifdef DJGPP
    "msdos_32",
#else
# ifdef MSDOS
    "msdos_16",
# endif
#endif
#ifdef OS2
    "os2",
#endif
#ifdef AMIGA
    "amiga",
#endif
#ifdef VMS
    "vms",
#endif
#ifdef HAVE_FNMATCH
    "wildcards",
#endif
#ifdef HAVE_REGEX
    "regex",
#endif
#ifndef EXTERNAL_SORT
    "internal-sort",
#endif
#ifdef CUSTOM_CONFIGURATION_FILE
    "custom-conf",
#endif
#if (defined (MSDOS) || defined (WIN32) || defined (OS2)) && defined (UNIX_PATH_SEPARATOR)
    "unix-path-separator",
#endif
#ifdef DEBUG
    "debug",
#endif
    NULL
};

/*
*   FUNCTION PROTOTYPES
*/
static boolean parseFileOptions (const char *const fileName);

/*
*   FUNCTION DEFINITIONS
*/

extern void verbose (const char *const format, ...)
{
    if (Option.verbose)
    {
	va_list ap;
	va_start (ap, format);
	vprintf (format, ap);
	va_end (ap);
    }
}

static char *stringCopy (const char *const string)
{
    char* result = NULL;
    if (string != NULL)
	result = eStrdup (string);
    return result;
}

static void freeString (char **const pString)
{
    if (*pString != NULL)
    {
	eFree (*pString);
	*pString = NULL;
    }
}

extern void freeList (stringList** const pList)
{
    if (*pList != NULL)
    {
	stringListDelete (*pList);
	*pList = NULL;
    }
}

extern void setDefaultTagFileName (void)
{
    if (Option.tagFileName != NULL)
	;		/* accept given name */
    else if (Option.etags)
	Option.tagFileName = stringCopy (ETAGS_FILE);
    else
	Option.tagFileName = stringCopy (CTAGS_FILE);
}

extern boolean filesRequired (void)
{
    boolean result = FilesRequired;
    if (Option.recurse)
	result = FALSE;
    return result;
}

extern void checkOptions (void)
{
    const char* notice;
    if (Option.xref)
    {
	notice = "xref output";
	if (Option.include.fileNames)
	{
	    error (WARNING, "%s disables file name tags", notice);
	    Option.include.fileNames = FALSE;
	}
    }
    if (Option.append)
    {
	notice = "append mode is not compatible with";
	if (isDestinationStdout ())
	    error (FATAL, "%s tags to stdout", notice);
    }
    if (Option.filter)
    {
	notice = "filter mode";
	if (Option.printTotals)
	{
	    error (WARNING, "%s disables totals", notice);
	    Option.printTotals = FALSE;
	}
	if (Option.tagFileName != NULL)
	    error (WARNING, "%s ignores output tag file name", notice);
    }
}

static void setEtagsMode (void)
{
    Option.etags = TRUE;
    Option.sorted = SO_UNSORTED;
    Option.lineDirectives = FALSE;
    Option.tagRelative = TRUE;
}

extern void testEtagsInvocation (void)
{
    char* const execName = eStrdup (getExecutableName ());
    char* const etags = eStrdup (ETAGS);
#ifdef CASE_INSENSITIVE_FILENAMES
    toLowerString (execName);

⌨️ 快捷键说明

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