Page MenuHomeSoftware Heritage

lxcmd.c
No OneTemporary

/*
*
* Copyright (c) 1996-2003, Darren Hiebert
* Copyright (c) 2014, Red Hat, Inc.
* Copyright (c) 2014, Masatake YAMATO
*
* This source code is released for free distribution under the terms of the
* GNU General Public License version 2 or (at your option) any later version.
*
* This module contains functions for invoking external command.
* Half of codes are derived from lregex.c.
* Core data structure is taken from readtags.h.
*
*/
/*
XCMD PROTOCOL (version 2.1)
==================================================================
When invoking xcmd just only with --lint-kinds=LANG option,
xcmd must write lines matching one of following patterns
to stdout.
patterns
--------
^([^ \t])[ \t]+([^\t]+)([ \t]+(\[off\]))?$
\1 => letter
\2 => name
\4 => \[off\] is optional.
exit code
---------
If xcmd itself recognizes it cannot run, it should exit with
XCMD_NOT_AVAILABLE_STATUS exit code. ctags may ignore the xcmd.
*/
#define XCMD_NOT_AVAILABLE_STATUS 127
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#define _GNU_SOURCE /* for WIFEXITED and WEXITSTATUS */
#include <errno.h>
#include <ctype.h>
#include <stdlib.h> /* for WIFEXITED and WEXITSTATUS */
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include "debug.h"
#include "main.h"
#include "options.h"
#include "parse.h"
#include "ptag.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
#include "pcoproc.h"
#include "flags.h"
#include "xtag.h"
#include "ptag.h"
/*
* MACROS
*/
#define XCMD_LIST_KIND_OPTION "--list-kinds"
/*
* DATA DECLARATIONS
*/
typedef struct {
/* the key of the extension field */
const char *key;
/* the value of the extension field (may be an empty string) */
const char *value;
int pull_count;
} tagExtensionField;
/* This structure contains information about a specific tag. */
typedef struct {
/* name of tag */
const char *name;
/* path of input file containing definition of tag */
const char *file;
/* address for locating tag in input file */
struct {
/* pattern for locating input line
* (may be NULL if not present) */
const char *pattern;
/* line number in input file of tag definition
* (may be zero if not known) */
unsigned long lineNumber;
} address;
const kindOption* kind;
/* is tag of file-limited scope? */
short fileScope;
/* miscellaneous extension fields */
struct {
/* number of entries in `list' */
unsigned short count;
/* list of key value pairs */
tagExtensionField *list;
} fields;
} tagEntry;
typedef struct {
vString *path;
kindOption *kinds;
unsigned int n_kinds;
boolean available;
unsigned int id; /* not used yet */
int not_available_status;
} xcmdPath;
typedef struct {
xcmdPath *paths;
unsigned int count;
} pathSet;
#ifdef HAVE_COPROC
static pathSet* Sets = NULL;
static int SetUpper = -1; /* upper language index in list */
static void clearPathSet (const langType language)
{
if (language <= SetUpper)
{
pathSet* const set = Sets + language;
unsigned int i, k;
for (i = 0 ; i < set->count ; ++i)
{
xcmdPath *p = &set->paths [i];
vStringDelete (p->path);
p->path = NULL;
p->available = FALSE;
for (k = 0; k < p->n_kinds; k++)
{
kindOption* kind = &(p->kinds[k]);
eFree ((void *)kind->name);
kind->name = NULL;
eFree ((void *)kind->description);
kind->description = NULL;
}
if (p->kinds)
{
eFree (p->kinds);
p->kinds = NULL;
}
}
if (set->paths != NULL)
eFree (set->paths);
set->paths = NULL;
set->count = 0;
}
}
static boolean loadPathKind (xcmdPath *const path, char* line, char *args[])
{
const char* backup = line;
char* off;
vString *desc;
kindOption *kind;
if (line[0] == '\0')
return FALSE;
else if (!isblank(line[1]))
{
error (WARNING, "[%s] a space after letter is not found in kind description line: %s", args[0], backup);
return FALSE;
}
path->kinds = xRealloc (path->kinds, path->n_kinds + 1, kindOption);
kind = &path->kinds [path->n_kinds];
memset (kind, 0, sizeof (*kind));
kind->enabled = TRUE;
kind->letter = line[0];
kind->name = NULL;
kind->description = NULL;
kind->referenceOnly = FALSE;
kind->nRoles = 0;
kind->roles = NULL;
verbose (" kind letter: <%c>\n", kind->letter);
for (line++; isblank(*line); line++)
; /* do nothing */
if (*line == '\0')
{
error (WARNING, "[%s] unexpectedly a kind description line is terminated: %s",
args[0], backup);
return FALSE;
}
Assert (!isblank (*line));
off = strrstr(line, "[off]");
if (off == line)
{
error (WARNING, "[%s] [off] is given but no kind description is found: %s",
args[0], backup);
return FALSE;
}
else if (off)
{
if (!isblank (*(off - 1)))
{
error (WARNING, "[%s] a whitespace must precede [off] flag: %s",
args[0], backup);
return FALSE;
}
kind->enabled = FALSE;
*off = '\0';
}
desc = vStringNewInit (line);
vStringStripTrailing (desc);
Assert (vStringLength (desc) > 0);
kind->description = vStringDeleteUnwrap (desc);
/* TODO: This conversion should be part of protocol. */
{
char *tmp = eStrdup (kind->description);
char *c;
for (c = tmp; *c != '\0'; c++)
{
if (*c == ' ' || *c == '\t')
*c = '_';
}
kind->name = tmp;
}
path->n_kinds += 1;
return TRUE;
}
static boolean isSafeExecutable (const char* path)
{
fileStatus *file;
boolean r;
Assert (path);
file = eStat (path);
if (!file->exists)
{
/* The file doesn't exist. So I cannot say
it is unsafe. The caller should
handle this case. */
r = TRUE;
}
else if (file->isSetuid)
{
error (WARNING, "xcmd doesn't run a setuid executable: %s", path);
r = FALSE;
}
else if (file->isSetgid)
{
error (WARNING, "xcmd doesn't run a setgid executable: %s", path);
r = FALSE;
}
else
r = TRUE;
eStatFree (file);
return r;
}
static boolean loadPathKinds (xcmdPath *const path, const langType language)
{
enum pcoprocError r;
FILE* pp = NULL;
char * argv[3];
int status;
vString * opt;
char file_kind = getLanguageFileKind (language)->letter;
opt = vStringNewInit(XCMD_LIST_KIND_OPTION);
vStringCatS (opt, "=");
vStringCatS (opt, getLanguageName(language));
argv[2] = NULL;
argv[1] = vStringValue (opt);
argv[0] = vStringValue (path->path);
errno = 0;
if (getuid() == 0 || geteuid() == 0)
{
verbose ("all xcmd feature is disabled when running ctags in root privilege\n");
vStringDelete (opt);
return FALSE;
}
if (! isSafeExecutable (argv [0]))
{
vStringDelete (opt);
return FALSE;
}
verbose ("loading path kinds of %s from [%s %s]\n", getLanguageName(language), argv[0], argv[1]);
r = pcoprocOpen (vStringValue (path->path), argv, &pp, NULL);
switch (r) {
case PCOPROC_ERROR_WPIPE:
error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_ERROR_RPIPE:
error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_ERROR_FORK:
error (WARNING | PERROR, "failed to do fork: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_SUCCESSFUL:
break;
}
if (pp)
{
vString* vline = vStringNew();
while (readLineRawWithNoSeek (vline, pp))
{
char* line;
char kind_letter;
vStringStripNewline (vline);
line = vStringValue (vline);
if (!loadPathKind (path, line, argv))
break;
kind_letter = path->kinds [path->n_kinds - 1].letter;
if (kind_letter == file_kind)
error (FATAL,
"Kind letter \'%c\' returned from xcmd %s of %s language is reserved in ctags main",
kind_letter,
vStringValue (path->path),
getLanguageName (language));
}
vStringDelete (vline);
status = pcoprocClose (pp);
/* TODO: Decode status */
verbose(" status: %d\n", status);
if (status != 0)
{
if (status > 0
&& WIFEXITED (status)
&& (WEXITSTATUS (status) == path->not_available_status))
verbose ("xcmd: the %s backend is not available\n", argv[0]);
else
error (WARNING, "xcmd exits abnormally status(%d): [%s %s]",
status, argv[0], argv[1]);
vStringDelete (opt);
return FALSE;
}
}
else
{
error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]",
argv[0], argv[1]);
}
vStringDelete (opt);
return path->kinds == NULL? FALSE: TRUE;
}
#endif /* HAVE_COPROC */
static void foreachXcmdKinds (const langType language,
boolean (*func) (kindOption *, void *),
void *data)
{
#ifdef HAVE_COPROC
if (language <= SetUpper && Sets [language].count > 0)
{
pathSet* const set = Sets + language;
xcmdPath * path = set->paths;
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
{
unsigned int k;
if (!path[i].available)
continue;
for (k = 0; k < path[i].n_kinds; k++)
if (func (& (path[i].kinds[k]), data))
break;
}
}
#endif
}
static boolean kind_reset_cb (kindOption *kind, void *data)
{
kind->enabled = *(boolean *)data;
return FALSE; /* continue */
}
extern void resetXcmdKinds (const langType language, boolean mode)
{
foreachXcmdKinds (language, kind_reset_cb, &mode);
}
struct kind_and_mode_and_result
{
int kind;
boolean mode;
boolean result;
};
static boolean enable_kind_cb (kindOption *kind, void *data)
{
struct kind_and_mode_and_result *kmr = data;
if (kind->letter == kmr->kind)
{
kind->enabled = kmr->mode;
kmr->result = TRUE;
}
/* conitnue:
There can be more than one paths which deals this kind.
Consider /bin/X and /bin/Y are both parser for a language L.
ctags --langdef=L --xcmd-L=/bin/X --xcmd-L=/bin/Y ... */
return FALSE;
}
extern boolean enableXcmdKind (const langType language, const int kind,
const boolean mode)
{
struct kind_and_mode_and_result kmr;
kmr.kind = kind;
kmr.mode = mode;
kmr.result = FALSE;
foreachXcmdKinds (language, enable_kind_cb, &kmr);
return kmr.result;
}
struct kind_and_result
{
int kind;
boolean result;
};
static boolean is_kind_enabled_cb (kindOption *kind, void *data)
{
boolean r = FALSE;
struct kind_and_result *kr = data;
if (kind->letter == kr->kind)
{
kr->result = kind->enabled;
r = TRUE;
}
return r;
}
static boolean does_kind_exist_cb (kindOption *kind, void *data)
{
boolean r = FALSE;
struct kind_and_result *kr = data;
if (kind->letter == kr->kind)
{
kr->result = TRUE;
r = TRUE;
}
return r;
}
extern boolean isXcmdKindEnabled (const langType language, const int kind)
{
struct kind_and_result d;
d.kind = kind;
d.result = FALSE;
foreachXcmdKinds (language, is_kind_enabled_cb, &d);
return d.result;
}
extern boolean hasXcmdKind (const langType language, const int kind)
{
struct kind_and_result d;
d.kind = kind;
d.result = FALSE;
foreachXcmdKinds (language, does_kind_exist_cb, &d);
return d.result;
}
#ifdef HAVE_COPROC
static void printXcmdKind (xcmdPath *path, unsigned int i,
const char* const langName, boolean allKindFields, boolean indent)
{
unsigned int k;
if (!path[i].available)
return;
if (allKindFields && indent)
printf ("%s", langName);
for (k = 0; k < path[i].n_kinds; k++)
printKind (path[i].kinds + k, allKindFields, indent);
}
#endif
extern void printXcmdKinds (const langType language __unused__,
boolean allKindFields __unused__,
boolean indent __unused__)
{
#ifdef HAVE_COPROC
if (language <= SetUpper && Sets [language].count > 0)
{
pathSet* const set = Sets + language;
const char* const langName = getLanguageName(language);
unsigned int i;
for (i = 0 ; i < set->count ; ++i)
printXcmdKind (set->paths, i, langName, allKindFields, indent);
}
#endif
}
extern void freeXcmdResources (void)
{
#ifdef HAVE_COPROC
int i;
for (i = 0 ; i <= SetUpper ; ++i)
clearPathSet (i);
if (Sets != NULL)
eFree (Sets);
Sets = NULL;
SetUpper = -1;
#endif
}
#ifdef HAVE_COPROC
static void xcmd_flag_not_avaible_status_long (const char* const s __unused__, const char* const v, void* data)
{
xcmdPath *path = data;
path->not_available_status = strtol ((const char *)v, NULL, 0);
}
#endif
extern void addTagXcmd (const langType language, vString* pathvstr, const char* flags)
{
#ifdef HAVE_COPROC
pathSet* set;
xcmdPath *path;
flagDefinition xcmdFlagDefs[] = {
{ '\0', "notAvailableStatus", NULL, xcmd_flag_not_avaible_status_long },
};
Assert (pathvstr != NULL);
if (language > SetUpper)
{
int i;
Sets = xRealloc (Sets, (language + 1), pathSet);
for (i = SetUpper + 1 ; i <= language ; ++i)
{
Sets [i].paths = NULL;
Sets [i].count = 0;
}
SetUpper = language;
}
set = Sets + language;
set->paths = xRealloc (set->paths, (set->count + 1), xcmdPath);
path = &set->paths [set->count];
path->path = pathvstr;
path->kinds = NULL;
path->n_kinds = 0;
path->id = set->count;
path->not_available_status = XCMD_NOT_AVAILABLE_STATUS;
set->count += 1;
flagsEval (flags, xcmdFlagDefs, ARRAY_SIZE(xcmdFlagDefs), path);
path->available = (loadPathKinds (path, language));
useXcmdMethod (language);
if (path->available)
notifyAvailabilityXcmdMethod (language);
#endif
}
extern void addLanguageXcmd (
const langType language __unused__, const char* const parameter __unused__)
{
#ifdef HAVE_COPROC
char *path;
vString* vpath;
const char* flags;
flags = strchr (parameter, LONG_FLAGS_OPEN);
if (flags)
path = eStrndup (parameter, flags - parameter);
else
path = eStrdup (parameter);
if (parameter [0] != '/' && parameter [0] != '.')
{
vpath = expandOnDriversPathList (path);
vpath = vpath? vpath: vStringNewInit(path);
}
else
vpath = vStringNewInit(path);
eFree (path);
addTagXcmd (language, vpath, flags);
#endif
}
#ifdef HAVE_COPROC
static void processLanguageXcmd (const langType language,
const char* const parameter)
{
if (parameter == NULL || parameter [0] == '\0')
clearPathSet (language);
else
addLanguageXcmd (language, parameter);
}
#endif
extern boolean processXcmdOption (const char *const option, const char *const parameter,
OptionLoadingStage stage)
{
langType language;
language = getLanguageComponentInOption (option, "xcmd-");
if (language == LANG_IGNORE)
return FALSE;
if (stage == OptionLoadingStageCurrentRecursive)
{
error (WARNING, "Don't use --xcmd-<LANG> option in ./.ctags nor ./.ctags/*: %s",
option);
/* Consume it here. */
return TRUE;
}
else if (stage == OptionLoadingStageHomeRecursive && (!Option.allowXcmdInHomeDir))
{
error (WARNING, "Don't use --xcmd-<LANG> option in ~/.ctags and/or ~/.ctags/*: %s",
option);
/* Consume it here. */
return TRUE;
}
#ifdef HAVE_COPROC
processLanguageXcmd (language, parameter);
#else
error (WARNING, "coproc feature is not available; required for --%s option",
option);
#endif
return TRUE;
}
#ifdef HAVE_COPROC
static const kindOption* lookupKindFromLetter (const xcmdPath* const path, char kind_letter)
{
unsigned int k;
kindOption *kind;
for (k = 0; k < path->n_kinds; k++)
{
kind = path->kinds + k;
if (kind->letter == kind_letter)
return kind;
}
return NULL;
}
static const kindOption* lookupKindFromName (const xcmdPath* const path, const char* const kind_name)
{
unsigned int k;
kindOption *kind;
for (k = 0; k < path->n_kinds; k++)
{
kind = path->kinds + k;
if (kind->name && (!strcmp(kind->name, kind_name)))
return kind;
}
return NULL;
}
static const char* entryLookupField (tagEntry *const entry, const char *const kind, boolean pulling)
{
int i;
for (i = 0; i < entry->fields.count; i++)
{
if (!strcmp (entry->fields.list [i].key, kind))
{
if (pulling)
entry->fields.list [i].pull_count++;
return entry->fields.list [i].value;
}
}
return NULL;
}
static const char* entryGetAnyUnpulledField (tagEntry *const entry, const char **const kind, boolean pulling)
{
int i;
for (i = 0; i < entry->fields.count; i++)
{
if (entry->fields.list [i].pull_count == 0)
{
*kind = entry->fields.list [i].key;
if (pulling)
entry->fields.list [i].pull_count++;
return entry->fields.list [i].value;
}
}
return NULL;
}
static boolean isKindEnabled (xcmdPath* path, const char* value)
{
unsigned int k;
kindOption *kind;
Assert (path->kinds);
Assert (value);
Assert (*value);
for (k = 0; k < path->n_kinds; k++)
{
kind = path->kinds + k;
if (!kind->enabled)
{
if (value[1] == '\0' && value[0] == kind->letter)
return FALSE;
if (!strcmp(value, kind->name))
return FALSE;
if (!strcmp(value, kind->description))
return FALSE;
}
}
return TRUE;
}
static void entryAddField (tagEntry *const entry, const char *const key, const char *const value)
{
entry->fields.list = xRealloc (entry->fields.list,
entry->fields.count + 1,
tagExtensionField);
entry->fields.list [entry->fields.count].key = key;
entry->fields.list [entry->fields.count].value = value;
entry->fields.list [entry->fields.count].pull_count = 0;
++entry->fields.count;
}
static boolean parseExtensionFields (tagEntry *const entry, char *const string, xcmdPath* path)
{
char *p = string;
while (p != NULL && *p != '\0')
{
while (*p == TAB)
*p++ = '\0';
if (*p != '\0')
{
char *colon;
char *field = p;
p = strchr (p, TAB);
if (p != NULL)
*p++ = '\0';
colon = strchr (field, ':');
if (colon == NULL)
{
if (isKindEnabled (path, field))
{
if (entry->kind == NULL)
{
entry->kind = lookupKindFromLetter (path, field[0]);
if (entry->kind == NULL)
{
kindOption *fileKind = getInputLanguageFileKind ();
if (fileKind && fileKind->letter == field[0])
/* ctags will make a tag for file. */
goto reject;
}
}
else {
; /* TODO Handle warning */
}
Assert (entry->kind);
}
else
goto reject;
}
else
{
const char *key = field;
const char *value = colon + 1;
*colon = '\0';
if (strcmp (key, "kind") == 0)
{
if (*value == '\0')
goto reject;
else if (isKindEnabled (path, value))
{
if (entry->kind == NULL)
{
entry->kind = lookupKindFromName (path, value);
if (entry->kind == NULL)
{
kindOption *fileKind = getInputLanguageFileKind ();
if (fileKind && (strcmp(fileKind->name, value) == 0))
/* ctags will make a tag for file. */
goto reject;
}
}
else {
; /*TODO Handle warning*/
}
Assert (entry->kind);
}
else
goto reject;
}
else if (strcmp (key, "file") == 0)
entry->fileScope = 1;
else if (strcmp (key, "line") == 0)
entry->address.lineNumber = atol (value);
else if (strcmp (key, "language") == 0)
continue;
else
entryAddField (entry, key, value);
}
}
}
return TRUE;
reject:
if (entry->fields.list)
{
eFree (entry->fields.list);
entry->fields.list = NULL;
}
entry->fields.count = 0;
return FALSE;
}
static const char *const PseudoTagPrefix = "!_";
static boolean hasPseudoTagPrefix (const char* const name)
{
const size_t prefixLength = strlen (PseudoTagPrefix);
return !strncmp (name, PseudoTagPrefix, prefixLength);
}
static boolean parseXcmdPath (char* line, xcmdPath* path, tagEntry* entry)
{
char *p = line;
char *tab = strchr (p, TAB);
boolean pseudoTag = FALSE;
// verbose("<%s>line: %s\n", vStringValue (path->path), line);
entry->name = p;
if (tab != NULL)
{
*tab = '\0';
pseudoTag = hasPseudoTagPrefix (entry->name);
p = tab + 1;
entry->file = p;
tab = strchr (p, TAB);
if (tab != NULL)
{
int fieldsPresent;
*tab = '\0';
p = tab + 1;
if (*p == '/' || *p == '?')
{
/* parse pattern */
int delimiter = *(unsigned char*) p;
entry->address.lineNumber = 0;
entry->address.pattern = p;
do
{
p = strchr (p + 1, delimiter);
} while (p != NULL && *(p - 1) == '\\');
if (p == NULL)
{
*tab = '\t';
error (WARNING, "pattern from %s is not ended with `%c': %s",
vStringValue (path->path),
(char)delimiter,
line);
return FALSE;
}
else
++p;
}
else if (isdigit ((int) *(unsigned char*) p))
{
/* parse line number */
entry->address.pattern = p;
entry->address.lineNumber = atol (p);
while (isdigit ((int) *(unsigned char*) p))
++p;
}
else
{
*tab = '\t';
error (WARNING, "cannot parse as ctags output from %s: %s",
vStringValue (path->path), line);
return FALSE;
}
fieldsPresent = (strncmp (p, ";\"", 2) == 0);
*p = '\0';
if (pseudoTag)
return TRUE;
if (fieldsPresent)
{
if (!parseExtensionFields (entry, p + 2, path))
return FALSE;
return TRUE;
}
}
}
return FALSE;
}
static void freeTagEntry (tagEntry* entry)
{
if (entry->fields.list)
{
eFree (entry->fields.list);
entry->fields.list = NULL;
}
entry->fields.count = 0;
}
static boolean makePseudoTagEntryFromTagEntry (tagEntry* entry)
{
const char *tagName, *fileName, *pattern;
const size_t prefixLength = strlen (PseudoTagPrefix);
ptagType t = PTAG_UNKNOWN;
tagName = entry->name + prefixLength;
fileName = entry->file;
pattern = entry->address.pattern;
if (strcmp (tagName, "TAG_FILE_SORTED") == 0)
return FALSE;
else if (strcmp (tagName, "TAG_FILE_FORMAT") == 0)
return FALSE; /* ??? */
else if (strcmp (tagName, "TAG_PROGRAM_AUTHOR") == 0)
t = PTAG_PROGRAM_AUTHOR;
else if (strcmp (tagName, "TAG_PROGRAM_NAME") == 0)
t = PTAG_PROGRAM_NAME;
else if (strcmp (tagName, "TAG_PROGRAM_URL") == 0)
t = PTAG_PROGRAM_URL;
else if (strcmp (tagName, "TAG_PROGRAM_VERSION") == 0)
t = PTAG_PROGRAM_VERSION;
if (t == PTAG_UNKNOWN)
return FALSE;
else
{
struct ptagXcmdData data = {
.fileName = fileName,
.pattern = pattern,
.language = entryLookupField(entry,
"language",
FALSE),
};
return makePtagIfEnabled (t, &data);
}
}
static boolean makeTagEntryFromTagEntry (xcmdPath* path, tagEntry* entry)
{
tagEntryInfo tag;
fpos_t filePosition;
if (hasPseudoTagPrefix (entry->name))
{
if ((! isXtagEnabled (XTAG_PSEUDO_TAGS))
|| (Option.xref)
|| (Option.etags))
return FALSE;
return makePseudoTagEntryFromTagEntry (entry);
}
memset(&filePosition, 0, sizeof(filePosition));
// pseudo if (entry->name...);
initTagEntryFull (&tag, entry->name,
entry->address.lineNumber,
entryLookupField(entry, "language", TRUE),
filePosition,
entry->file,
entry->kind,
ROLE_INDEX_DEFINITION,
NULL,
NULL,
0);
tag.pattern = entry->address.pattern;
tag.isFileScope = (boolean)entry->fileScope;
tag.extensionFields.access = entryLookupField(entry, "access", TRUE);
tag.extensionFields.implementation = entryLookupField(entry, "implementation", TRUE);
tag.extensionFields.inheritance = entryLookupField(entry, "inherits", TRUE);
tag.extensionFields.signature = entryLookupField(entry, "signature", TRUE);
tag.extensionFields.typeRef[0] = entryLookupField(entry, "typeref", TRUE);
if (tag.extensionFields.typeRef[0])
{
char *tmp;
tmp = strchr (tag.extensionFields.typeRef[0], ':');
if (tmp)
{
*tmp = '\0';
tag.extensionFields.typeRef[1] = tmp + 1;
}
}
const char *kindName = NULL;
tag.extensionFields.scopeName = entryGetAnyUnpulledField (entry, &kindName, TRUE);
if (tag.extensionFields.scopeName && kindName)
tag.extensionFields.scopeKind = lookupKindFromName (path, kindName);
/* TODO: role */
makeTagEntry (&tag);
return TRUE;
}
static boolean invokeXcmdPath (const char* const fileName, xcmdPath* path, const langType language)
{
enum pcoprocError r;
boolean result = FALSE;
char* argv[4];
FILE* pp = NULL;
if (!path->available)
return FALSE;
argv[2] = NULL;
argv[1] = (char * const)fileName;
argv[0] = vStringValue (path->path);
Assert (!(getuid() == 0 || geteuid() == 0));
if (! isSafeExecutable (argv [0]))
return FALSE;
verbose ("getting tags of %s language from [%s %s]\n", getLanguageName(language), argv[0], argv[1]);
r = pcoprocOpen (vStringValue (path->path), argv, &pp, NULL);
switch (r) {
case PCOPROC_ERROR_WPIPE:
error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_ERROR_RPIPE:
error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_ERROR_FORK:
error (WARNING | PERROR, "failed to do fork: [%s %s]",
argv[0], argv[1]);
break;
case PCOPROC_SUCCESSFUL:
break;
}
if (pp)
{
vString* vline = vStringNew();
int status;
while (readLineRawWithNoSeek (vline, pp))
{
char* line;
tagEntry entry;
memset(&entry, 0, sizeof(entry));
vStringStripNewline (vline);
line = vStringValue (vline);
if (parseXcmdPath (line, path, &entry) )
{
entryAddField (&entry, "language", getLanguageName (language));
if (makeTagEntryFromTagEntry (path, &entry))
result = TRUE;
freeTagEntry (&entry);
}
}
vStringDelete (vline);
status = pcoprocClose (pp);
verbose(" status: %d\n", status);
if (status)
{
error (WARNING | PERROR, "xcmd exits abnormally status(%d): [%s %s]",
status, argv[0], argv[1]);
return FALSE;
}
}
else
{
error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]",
argv[0], argv[1]);
}
return result;
}
#endif
#ifdef HAVE_COPROC
extern boolean invokeXcmd (const char* const fileName, const langType language)
{
boolean result = FALSE;
if (language != LANG_IGNORE && language <= SetUpper &&
Sets [language].count > 0)
{
const pathSet* const set = Sets + language;
unsigned int i;
for (i = 0; i < set->count ; ++i)
{
xcmdPath* path = set->paths + i;
if (invokeXcmdPath (fileName, path, language))
result = TRUE;
}
}
return result;
}
#endif

File Metadata

Mime Type
text/x-c
Expires
Jun 4 2025, 6:41 PM (14 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3398698

Event Timeline