Beispiel #1
0
/* `end' points to the equal sign.  Parse from right to left to get the
 * identifier.  Assume we're dealing with something of form \s*\w+\s*=>
 */
static void makeTagFromLeftSide (const char *begin, const char *end,
	vString *name, vString *package)
{
	tagEntryInfo entry;
	const char *b, *e;
	if (! PerlKinds[K_CONSTANT].enabled)
		return;
	for (e = end - 1; e > begin && isspace(*e); --e)
		;
	if (e < begin)
		return;
	for (b = e; b >= begin && isIdentifier(*b); --b)
		;
	/* Identifier must be either beginning of line of have some whitespace
	 * on its left:
	 */
	if (b < begin || isspace(*b) || ',' == *b)
		++b;
	else if (b != begin)
		return;
	if (e - b + 1 <= 0)
		return;			/* Left side of => has an invalid identifier. */
	vStringClear(name);
	vStringNCatS(name, b, e - b + 1);
	initTagEntry(&entry, vStringValue(name), &(PerlKinds[K_CONSTANT]));
	makeTagEntry(&entry);
	if (Option.include.qualifiedTags && package && vStringLength(package)) {
		vStringClear(name);
		vStringCopy(name, package);
		vStringNCatS(name, b, e - b + 1);
		initTagEntry(&entry, vStringValue(name), &(PerlKinds[K_CONSTANT]));
		makeTagEntry(&entry);
	}
}
Beispiel #2
0
static void parseAutogroup (const unsigned char *line)
{
	vString *name = vStringNew ();

	/* Found Autocommand Group (augroup) */
	const unsigned char *cp = line;
	if (isspace ((int) *cp))
	{
		while (*cp && isspace ((int) *cp))
			++cp; 

		if (*cp)
		{
			const unsigned char *end = skipWord (cp);

			/* "end" (caseless) has a special meaning and should not generate a tag */
			if (end > cp && strncasecmp ((const char *) cp, "end", end - cp) != 0)
			{
				vStringNCatS (name, (const char *) cp, end - cp);
				vStringTerminate (name);
				makeSimpleTag (name, VimKinds, K_AUGROUP);
				vStringClear (name);
			}
		}
	}
	vStringDelete (name);
}
Beispiel #3
0
static void makeJsTag (tokenInfo *const token, const jsKind kind, vString *const signature)
{
	if (JsKinds [kind].enabled && ! token->ignoreTag )
	{
		const char *name = vStringValue (token->string);
		vString *fullscope = vStringNewCopy (token->scope);
		const char *p;
		tagEntryInfo e;

		if ( (p = strrchr (name, '.')) != NULL )
		{
			if (vStringLength (fullscope) > 0)
				vStringPut (fullscope, '.');
			vStringNCatS (fullscope, name, (size_t) (p - name));
			name = p + 1;
		}

		initTagEntry (&e, name);

		e.lineNumber   = token->lineNumber;
		e.filePosition = token->filePosition;
		e.kindName	   = JsKinds [kind].name;
		e.kind		   = JsKinds [kind].letter;

		if ( vStringLength(fullscope) > 0 )
		{
			jsKind parent_kind = JSTAG_CLASS;

			/*
			 * If we're creating a function (and not a method),
			 * guess we're inside another function
			 */
			if (kind == JSTAG_FUNCTION)
				parent_kind = JSTAG_FUNCTION;

			e.extensionFields.scope[0] = JsKinds [parent_kind].name;
			e.extensionFields.scope[1] = vStringValue (fullscope);
		}

		if (signature && vStringLength(signature))
		{
			size_t i;
			/* sanitize signature by replacing all control characters with a
			 * space (because it's simple).
			 * there should never be any junk in a valid signature, but who
			 * knows what the user wrote and CTags doesn't cope well with weird
			 * characters. */
			for (i = 0; i < signature->length; i++)
			{
				unsigned char c = (unsigned char) signature->buffer[i];
				if (c < 0x20 /* below space */ || c == 0x7F /* DEL */)
					signature->buffer[i] = ' ';
			}
			e.extensionFields.signature = vStringValue(signature);
		}

		makeTagEntry (&e);
		vStringDelete (fullscope);
	}
}
Beispiel #4
0
/*
* Emits a tag for the given 'name' of kind 'kind' at the current nesting.
*/
static void emitRubyTag (vString* name, rubyKind kind)
{
	tagEntryInfo tag;
	vString* scope;
	tagEntryInfo *parent;
	rubyKind parent_kind = K_UNDEFINED;
	NestingLevel *lvl;
	const char *unqualified_name;
	const char *qualified_name;
	int r;

        if (!RubyKinds[kind].enabled) {
            return;
        }

	vStringTerminate (name);
	scope = nestingLevelsToScope (nesting);
	lvl = nestingLevelsGetCurrent (nesting);
	parent = getEntryOfNestingLevel (lvl);
	if (parent)
		parent_kind =  parent->kind - RubyKinds;

	qualified_name = vStringValue (name);
	unqualified_name = strrchr (qualified_name, SCOPE_SEPARATOR);
	if (unqualified_name && unqualified_name[1])
	{
		if (unqualified_name > qualified_name)
		{
			if (vStringLength (scope) > 0)
				vStringPut (scope, SCOPE_SEPARATOR);
			vStringNCatS (scope, qualified_name,
			              unqualified_name - qualified_name);
			/* assume module parent type for a lack of a better option */
			parent_kind = K_MODULE;
		}
		unqualified_name++;
	}
	else
		unqualified_name = qualified_name;

	initTagEntry (&tag, unqualified_name, &(RubyKinds [kind]));
	if (vStringLength (scope) > 0) {
		Assert (0 <= parent_kind &&
		        (size_t) parent_kind < (ARRAY_SIZE (RubyKinds)));

		tag.extensionFields.scopeKind = &(RubyKinds [parent_kind]);
		tag.extensionFields.scopeName = vStringValue (scope);
	}
	r = makeTagEntry (&tag);

	nestingLevelsPush (nesting, r);

	vStringClear (name);
	vStringDelete (scope);
}
Beispiel #5
0
/* Match a "label:" style label. */
static void match_colon_label (char const *p)
{
	char const *end = p + strlen (p) - 1;
	while (isspace (*end))
		end--;
	if (*end == ':')
	{
		vString *name = vStringNew ();
		vStringNCatS (name, p, end - p);
		makeSimpleTag (name, BasicKinds, K_LABEL);
		vStringDelete (name);
	}
}
Beispiel #6
0
static void makeJsTag (tokenInfo *const token, const jsKind kind)
{
	if (JsKinds [kind].enabled && ! token->ignoreTag )
	{
		const char *name = vStringValue (token->string);
		vString *fullscope = vStringNewCopy (token->scope);
		const char *p;
		tagEntryInfo e;

		if ( (p = strrchr (name, '.')) != NULL )
		{
			if (vStringLength (fullscope) > 0)
				vStringPut (fullscope, '.');
			vStringNCatS (fullscope, name, (size_t) (p - name));
			name = p + 1;
		}

		initTagEntry (&e, name);

		e.lineNumber   = token->lineNumber;
		e.filePosition = token->filePosition;
		e.kindName	   = JsKinds [kind].name;
		e.kind		   = JsKinds [kind].letter;

		if ( vStringLength(fullscope) > 0 )
		{
			jsKind parent_kind = JSTAG_CLASS;

			/*
			 * If we're creating a function (and not a method),
			 * guess we're inside another function
			 */
			if (kind == JSTAG_FUNCTION)
				parent_kind = JSTAG_FUNCTION;

			e.extensionFields.scope[0] = JsKinds [parent_kind].name;
			e.extensionFields.scope[1] = vStringValue (fullscope);
		}

		makeTagEntry (&e);
		vStringDelete (fullscope);
	}
}
Beispiel #7
0
static vString* substitute (
		const char* const in, const char* out,
		const int nmatch, const regmatch_t* const pmatch)
{
	vString* result = vStringNew ();
	const char* p;
	for (p = out  ;  *p != '\0'  ;  p++)
	{
		if (*p == '\\'  &&  isdigit ((int) *++p))
		{
			const int dig = *p - '0';
			if (0 < dig  &&  dig < nmatch  &&  pmatch [dig].rm_so != -1)
			{
				const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
				vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
			}
		}
		else if (*p != '\n'  &&  *p != '\r')
			vStringPut (result, *p);
	}
	vStringTerminate (result);
	return result;
}
Beispiel #8
0
/* reads an HereDoc or a NowDoc (the part after the <<<).
 * 	<<<[ \t]*(ID|'ID'|"ID")
 * 	...
 * 	ID;?
 *
 * note that:
 *  1) starting ID must be immediately followed by a newline;
 *  2) closing ID is the same as opening one;
 *  3) closing ID must be immediately followed by a newline or a semicolon
 *     then a newline.
 *
 * Example of a *single* valid heredoc:
 * 	<<< FOO
 * 	something
 * 	something else
 * 	FOO this is not an end
 * 	FOO; this isn't either
 * 	FOO; # neither this is
 * 	FOO;
 * 	# previous line was the end, but the semicolon wasn't required
 */
static void parseHeredoc (vString *const string)
{
	int c;
	unsigned int len;
	char delimiter[64]; /* arbitrary limit, but more is crazy anyway */
	int quote = 0;

	do
	{
		c = getcFromInputFile ();
	}
	while (c == ' ' || c == '\t');

	if (c == '\'' || c == '"')
	{
		quote = c;
		c = getcFromInputFile ();
	}
	for (len = 0; len < ARRAY_SIZE (delimiter) - 1; len++)
	{
		if (! isIdentChar (c))
			break;
		delimiter[len] = (char) c;
		c = getcFromInputFile ();
	}
	delimiter[len] = 0;

	if (len == 0) /* no delimiter, give up */
		goto error;
	if (quote)
	{
		if (c != quote) /* no closing quote for quoted identifier, give up */
			goto error;
		c = getcFromInputFile ();
	}
	if (c != '\r' && c != '\n') /* missing newline, give up */
		goto error;

	do
	{
		c = getcFromInputFile ();

		if (c != '\r' && c != '\n')
			vStringPut (string, (char) c);
		else
		{
			/* new line, check for a delimiter right after */
			int nl = c;
			int extra = EOF;

			c = getcFromInputFile ();
			for (len = 0; c != 0 && (c - delimiter[len]) == 0; len++)
				c = getcFromInputFile ();

			if (delimiter[len] != 0)
				ungetcToInputFile (c);
			else
			{
				/* line start matched the delimiter, now check whether there
				 * is anything after it */
				if (c == '\r' || c == '\n')
				{
					ungetcToInputFile (c);
					break;
				}
				else if (c == ';')
				{
					int d = getcFromInputFile ();
					if (d == '\r' || d == '\n')
					{
						/* put back the semicolon since it's not part of the
						 * string.  we can't put back the newline, but it's a
						 * whitespace character nobody cares about it anyway */
						ungetcToInputFile (';');
						break;
					}
					else
					{
						/* put semicolon in the string and continue */
						extra = ';';
						ungetcToInputFile (d);
					}
				}
			}
			/* if we are here it wasn't a delimiter, so put everything in the
			 * string */
			vStringPut (string, (char) nl);
			vStringNCatS (string, delimiter, len);
			if (extra != EOF)
				vStringPut (string, (char) extra);
		}
	}
	while (c != EOF);

	vStringTerminate (string);

	return;

error:
	ungetcToInputFile (c);
}
Beispiel #9
0
static void findAsciidocTags(void)
{
	vString *name = vStringNew();
	const unsigned char *line;
	unsigned char in_block = '\0';  /* holds the block marking char or \0 if not in block */

	nestingLevels = nestingLevelsNew();

	while ((line = readLineFromInputFile()) != NULL)
	{
		int line_len = strlen((const char*) line);
		int name_len_bytes = vStringLength(name);
		int name_len = utf8_strlen(vStringValue(name), name_len_bytes);

		/* if the name doesn't look like UTF-8, assume one-byte charset */
		if (name_len < 0) name_len = name_len_bytes;
		
		/* if its a title underline, or a delimited block marking character */
		if (line[0] == '=' || line[0] == '-' || line[0] == '~' ||
			line[0] == '^' || line[0] == '+' || line[0] == '.' ||
			line[0] == '*' || line[0] == '_' || line[0] == '/')
		{
			int n_same;
			for (n_same = 1; line[n_same] == line[0]; ++n_same);
			
			/* is it a two line title or a delimited block */
			if (n_same == line_len)
			{
				/* if in a block, can't be block start or title, look for block end */
				if (in_block)
				{
					if (line[0] == in_block) in_block = '\0';
				}
				
				/* if its a =_~^+ and the same length +-2 as the line before then its a title */
				/* (except in the special case its a -- open block start line) */
				else if ((line[0] == '=' || line[0] == '-' || line[0] == '~' ||
							line[0] == '^' || line[0] == '+') &&
						line_len <= name_len + 2 && line_len >= name_len - 2 &&
						!(line_len == 2 && line[0] == '-'))
				{
					int kind = get_kind((char)(line[0]));
					if (kind >= 0)
					{
						makeAsciidocTag(name, kind);
						continue;
					}
				}
				
				/* else if its 4 or more /+-.*_= (plus the -- special case) its a block start */
				else if (((line[0] == '/' || line[0] == '+' || line[0] == '-' ||
						   line[0] == '.' || line[0] == '*' || line[0] == '_' ||
						   line[0] == '=') && line_len >= 4 )
						 || (line[0] == '-' && line_len == 2))
				{
					in_block = line[0];
				}
			}
			
			/* otherwise is it a one line title */
			else if (line[0] == '=' && n_same <= 5 && isspace(line[n_same]) &&
					!in_block)
			{
				int kind = n_same - 1;
				int start = n_same;
				int end = line_len - 1;
				while (line[end] == line[0])--end;
				while (isspace(line[start]))++start;
				while (isspace(line[end]))--end;
				vStringClear(name);
				vStringNCatS(name, (const char*)(&(line[start])), end - start + 1);
				vStringTerminate(name);
				makeAsciidocTag(name, kind);
				continue;
			}
		}
		vStringClear(name);
		if (! isspace(*line))
			vStringCatS(name, (const char*) line);
		vStringTerminate(name);
	}
	vStringDelete(name);
	nestingLevelsFree(nestingLevels);
}