示例#1
0
文件: scheme.c 项目: qzhuyan/ctags
/* Algorithm adapted from from GNU etags.
 * Scheme tag functions
 * look for (def... xyzzy
 * look for (def... (xyzzy
 * look for (def ... ((... (xyzzy ....
 * look for (set! xyzzy
 */
static void readIdentifier (vString *const name, const unsigned char *cp)
{
	const unsigned char *p;
	vStringClear (name);
	/* Go till you get to white space or a syntactic break */
	for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++)
		vStringPut (name, (int) *p);
}
示例#2
0
文件: ocaml.c 项目: b4n/fishman-ctags
static void readIdentifier (lexingState * st)
{
	const unsigned char *p;
	vStringClear (st->name);

	/* first char is a simple letter */
	if (isAlpha (*st->cp) || *st->cp == '_')
		vStringPut (st->name, (int) *st->cp);

	/* Go till you get identifier chars */
	for (p = st->cp + 1; isIdent (*p); p++)
		vStringPut (st->name, (int) *p);

	st->cp = p;

	vStringTerminate (st->name);
}
示例#3
0
文件: vim.c 项目: Monits/ctags
static void parseLet (const unsigned char *line, int infunction)
{
	vString *name = vStringNew ();

	const unsigned char *cp = line;
	const unsigned char *np = line;
	/* get the name */
	if (isspace ((int) *cp))
	{
		while (*cp && isspace ((int) *cp))
			++cp;

		/* 
		 * Ignore lets which set:
		 *    &  - local buffer vim settings
		 *    @  - registers
		 *    [  - Lists or Dictionaries
		 */
		if (!*cp || *cp == '&' || *cp == '@' || *cp == '[' )
			goto cleanUp;

		/* 
		 * Ignore vim variables which are read only
		 *    v: - Vim variables.
		 */
		np = cp;
		++np;
		if ((int) *cp == 'v' && (int) *np == ':' )
			goto cleanUp;

		/* Skip non-global vars in functions */
		if (infunction && (int) *cp != 'g')
			goto cleanUp;

		/* deal with spaces, $, @ and & */
		while (*cp && *cp != '$' && !isalnum ((int) *cp))
			++cp;

		if (!*cp)
			goto cleanUp;

		/* cp = skipPrefix (cp, &scope); */
		do
		{
			if (!*cp)
				break;

			vStringPut (name, (int) *cp);
			++cp;
		} while (isalnum ((int) *cp)  ||  *cp == '_'  ||  *cp == '#'  ||  *cp == ':'  ||  *cp == '$');
		vStringTerminate (name);
		makeSimpleTag (name, VimKinds, K_VARIABLE);
		vStringClear (name);
	}

cleanUp:
	vStringDelete (name);
}
示例#4
0
文件: js.c 项目: BenWiederhake/geany
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, 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.arglist = vStringValue(signature);
		}

		makeTagEntry (&e);
		vStringDelete (fullscope);
	}
}
示例#5
0
文件: basic.c 项目: ParrotSec/geany
/* Match the name of a tag (function, variable, type, ...) starting at pos. */
static char const *extract_name (char const *pos, vString * name)
{
	while (isspace (*pos))
		pos++;
	vStringClear (name);
	for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++)
		vStringPut (name, *pos);
	return pos;
}
示例#6
0
static void scanIdentifier (lexerState *lexer)
{
	vStringClear(lexer->token_str);
	do
	{
		vStringPut(lexer->token_str, (char) lexer->cur_c);
		advanceChar(lexer);
	} while(lexer->cur_c != EOF && isIdentifierContinue(lexer->cur_c));
}
示例#7
0
文件: php.c 项目: blackb1rd/ctags
/* parses a class or an interface:
 * 	class Foo {}
 * 	class Foo extends Bar {}
 * 	class Foo extends Bar implements iFoo, iBar {}
 * 	interface iFoo {}
 * 	interface iBar extends iFoo {}
 *
 * if @name is not NULL, parses an anonymous class with name @name
 * 	new class {}
 * 	new class(1, 2) {}
 * 	new class(1, 2) extends Foo implements iFoo, iBar {} */
static boolean parseClassOrIface (tokenInfo *const token, const phpKind kind,
                                  const tokenInfo *name)
{
	boolean readNext = TRUE;
	implType impl = CurrentStatement.impl;
	tokenInfo *nameFree = NULL;
	vString *inheritance = NULL;

	readToken (token);
	if (name) /* anonymous class */
	{
		/* skip possible construction arguments */
		skipOverParens (token);
	}
	else /* normal, named class */
	{
		if (token->type != TOKEN_IDENTIFIER)
			return FALSE;

		name = nameFree = newToken ();
		copyToken (nameFree, token, TRUE);

		readToken (token);
	}

	inheritance = vStringNew ();
	/* read every identifiers, keywords and commas, and assume each
	 *  identifier (not keyword) is an inheritance
	 * (like in "class Foo extends Bar implements iA, iB") */
	while (token->type == TOKEN_IDENTIFIER ||
	       token->type == TOKEN_KEYWORD ||
	       token->type == TOKEN_COMMA)
	{
		if (token->type == TOKEN_IDENTIFIER)
		{
			if (vStringLength (inheritance) > 0)
				vStringPut (inheritance, ',');
			vStringCat (inheritance, token->string);
		}

		readToken (token);
	}

	makeClassOrIfaceTag (kind, name, inheritance, impl);

	if (token->type == TOKEN_OPEN_CURLY)
		enterScope (token, name->string, kind);
	else
		readNext = FALSE;

	if (nameFree)
		deleteToken (nameFree);
	vStringDelete (inheritance);

	return readNext;
}
示例#8
0
文件: css.c 项目: pjkack/ctags
static void parseSelector (vString *const string, const int firstChar)
{
	int c = firstChar;
	do
	{
		vStringPut (string, (char) c);
		c = getcFromInputFile ();
	} while (isSelectorChar (c));
	ungetcToInputFile (c);
}
示例#9
0
文件: vhdl.c 项目: pragmaware/ctags
static void parseString (vString * const string, const int delimiter)
{
	bool end = false;
	while (!end)
	{
		int c = getcFromInputFile ();
		if (c == EOF)
			end = true;
		else if (c == '\\')
		{
			c = getcFromInputFile ();	/* This maybe a ' or ". */
			vStringPut (string, c);
		}
		else if (c == delimiter)
			end = true;
		else
			vStringPut (string, c);
	}
}
示例#10
0
文件: jscript.c 项目: ruchee/ctags
static void parseTemplateString (vString *const string)
{
	int c;
	do
	{
		c = fileGetc ();
		if (c == '`')
			break;
		vStringPut (string, c);
		if (c == '\\')
		{
			c = fileGetc();
			vStringPut(string, c);
		}
		else if (c == '$')
		{
			c = fileGetc ();
			if (c != '{')
				fileUngetc (c);
			else
			{
				int depth = 1;
				/* we need to use the real token machinery to handle strings,
				 * comments, regexes and whatnot */
				tokenInfo *token = newToken ();
				LastTokenType = TOKEN_UNDEFINED;
				vStringPut(string, c);
				do
				{
					readTokenFull (token, FALSE, string);
					if (isType (token, TOKEN_OPEN_CURLY))
						depth++;
					else if (isType (token, TOKEN_CLOSE_CURLY))
						depth--;
				}
				while (! isType (token, TOKEN_EOF) && depth > 0);
				deleteToken (token);
			}
		}
	}
	while (c != EOF);
	vStringTerminate (string);
}
示例#11
0
文件: haskell.c 项目: max630/ctags
static void add_tag(const char *token, haskellKind kind, vString *name)
{
    int i;
    for (i = 0; token[i] != '\0'; ++i)
	vStringPut(name, token[i]);

    vStringTerminate(name);
    makeSimpleTag(name, HaskellKinds, kind);
    vStringClear(name);
}
示例#12
0
/*  Reads an identifier, whose first character is given by "c", into "tag",
 *  together with the file location and corresponding line number.
 */
static void readIdentifier (int c, vString *const name)
{
	vStringClear (name);
	do
	{
		vStringPut (name, c);
		c = getcAndCollect ();
	} while (c != EOF && cppIsident (c));
	ungetcAndCollect (c);
}
示例#13
0
static void pushScope (tokenInfo *const token,
					   const tokenInfo *const parent,
					   const jsonKind parentKind)
{
	if (vStringLength (token->scope) > 0)
		vStringPut (token->scope, '.');
	vStringCat (token->scope, parent->string);
	vStringTerminate (token->scope);
	token->scopeKind = parentKind;
}
示例#14
0
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind)
{
	if (isspace (**cp))
	{
		vString *name = vStringNew ();
		vString *chunk = vStringNew ();
		rubyKind actual_kind;
		unsigned int i = 0;

		/* parse the identifier, allowing scoping like "class Foo::Bar::Baz" */
		while (1)
		{
			actual_kind = parseIdentifier (cp, chunk, expected_kind);
			if (i++ > 0)
				vStringPut (name, '.');
			vStringCat (name, chunk);
			vStringClear (chunk);

			if (actual_kind != K_UNDEFINED && (*cp)[0] == ':' && (*cp)[1] == ':')
				*cp += 2;
			else
				break;
		}
		vStringDelete (chunk);
		vStringTerminate (name);

		if (actual_kind == K_UNDEFINED || vStringLength (name) == 0)
		{
			/*
			* What kind of tags should we create for code like this?
			*
			*    %w(self.clfloor clfloor).each do |name|
			*        module_eval <<-"end;"
			*            def #{name}(x, y=1)
			*                q, r = x.divmod(y)
			*                q = q.to_i
			*                return q, r
			*            end
			*        end;
			*    end
			*
			* Or this?
			*
			*    class << HTTP
			*
			* For now, we don't create any.
			*/
		}
		else
		{
			emitRubyTag (name, actual_kind);
		}
		vStringDelete (name);
	}
}
示例#15
0
文件: ruby.c 项目: amosbird/ctags
/*
* 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);
}
示例#16
0
/**
 * Reads from 'start' to 'end' and eliminates all spaces
 * inbetween.
 */
static char *readBetweenDelimitersWhileTrimmingSpaces(char start, char end) {

  static vString *wordBuffer = 0;
  int z;
  if (!wordBuffer)
    wordBuffer = vStringNew();
  else
    vStringClear(wordBuffer);

  z = skipToNonWhite();
  if (z != start) return NULL;
  while ((z = cppGetc()) != EOF && z != end) {
    if (isspace(z)) continue;
    vStringPut(wordBuffer, z);
  }
  if (z == EOF) return NULL;
  vStringPut(wordBuffer, z);
  vStringPut(wordBuffer, 0);
  return vStringValue(wordBuffer);
}
示例#17
0
文件: vim.c 项目: Cognoscan/ctags
static void parseFunction (const unsigned char *line)
{
	vString *name = vStringNew ();
	/* boolean inFunction = FALSE; */
	int scope;

	const unsigned char *cp = line + 1;

	if ((int) *++cp == 'n'	&&	(int) *++cp == 'c'	&&
		(int) *++cp == 't'	&&	(int) *++cp == 'i'	&&
		(int) *++cp == 'o'	&&	(int) *++cp == 'n')
			++cp;
	if ((int) *cp == '!')
		++cp;
	if (isspace ((int) *cp))
	{
		while (*cp && isspace ((int) *cp))
			++cp;

		if (*cp)
		{
			cp = skipPrefix (cp, &scope);
			if (isupper ((int) *cp)  ||  
					scope == 's'  ||  /* script scope */
					scope == '<'  ||  /* script scope */
					scope == 'd'  ||  /* dictionary */
					scope == 'a')	  /* autoload */
			{
				do
				{
					vStringPut (name, (int) *cp);
					++cp;
				} while (isalnum ((int) *cp) ||  *cp == '_' ||	*cp == '.' ||  *cp == '#');
				vStringTerminate (name);
				makeSimpleTag (name, VimKinds, K_FUNCTION);
				vStringClear (name);
			}
		}
	}

	/* TODO - update struct to indicate inside function */
	while ((line = readVimLine ()) != NULL)
	{
		/* 
		 * Vim7 added the for/endfo[r] construct, so we must first
		 * check for an "endfo", before a "endf"
		 */
		if ( (!strncmp ((const char*) line, "endfo", (size_t) 5) == 0) && 
				(strncmp ((const char*) line, "endf", (size_t) 4) == 0)   )
			break;
		/* TODO - call parseVimLine */
	}
	vStringDelete (name);
}
示例#18
0
文件: php.c 项目: blackb1rd/ctags
static void parseIdentifier (vString *const string, const int firstChar)
{
	int c = firstChar;
	do
	{
		vStringPut (string, (char) c);
		c = getcFromInputFile ();
	} while (isIdentChar (c));
	ungetcToInputFile (c);
	vStringTerminate (string);
}
示例#19
0
文件: ruby.c 项目: jsvisa/ctags
/*
* Copies the characters forming an identifier from *cp into
* name, leaving *cp pointing to the character after the identifier.
*/
static rubyKind parseIdentifier (
        const unsigned char** cp, vString* name, rubyKind kind)
{
    /* Method names are slightly different to class and variable names.
     * A method name may optionally end with a question mark, exclamation
     * point or equals sign. These are all part of the name.
     * A method name may also contain a period if it's a singleton method.
     */
    const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_";

    skipWhitespace (cp);

    /* Check for an anonymous (singleton) class such as "class << HTTP". */
    if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<')
    {
        return K_UNDEFINED;
    }

    /* Check for operators such as "def []=(key, val)". */
    if (kind == K_METHOD || kind == K_SINGLETON)
    {
        if (parseRubyOperator (name, cp))
        {
            return kind;
        }
    }

    /* Copy the identifier into 'name'. */
    while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
    {
        char last_char = **cp;

        vStringPut (name, last_char);
        ++*cp;

        if (kind == K_METHOD)
        {
            /* Recognize singleton methods. */
            if (last_char == '.')
            {
                vStringTerminate (name);
                vStringClear (name);
                return parseIdentifier (cp, name, K_SINGLETON);
            }

            /* Recognize characters which mark the end of a method name. */
            if (charIsIn (last_char, "?!="))
            {
                break;
            }
        }
    }
    return kind;
}
示例#20
0
文件: erlang.c 项目: ParrotSec/geany
static const unsigned char *parseIdentifier (
		const unsigned char *cp, vString *const identifier)
{
	vStringClear (identifier);
	while (isIdentifierCharacter ((int) *cp))
	{
		vStringPut (identifier, (int) *cp);
		++cp;
	}
	return cp;
}
示例#21
0
文件: vhdl.c 项目: relaxdiego/ctags
static void parseString (vString * const string, const int delimiter)
{
	boolean end = FALSE;
	while (!end)
	{
		int c = fileGetc ();
		if (c == EOF)
			end = TRUE;
		else if (c == '\\')
		{
			c = fileGetc ();	/* This maybe a ' or ". */
			vStringPut (string, c);
		}
		else if (c == delimiter)
			end = TRUE;
		else
			vStringPut (string, c);
	}
	vStringTerminate (string);
}
示例#22
0
文件: go.c 项目: Dev0Null/ctags
static void parseIdentifier (vString *const string, const int firstChar)
{
	int c = firstChar;
	do
	{
		vStringPut (string, c);
		c = getcFromInputFile ();
	} while (isIdentChar (c));
	vStringTerminate (string);
	ungetcToInputFile (c);		/* always unget, LF might add a semicolon */
}
示例#23
0
文件: css.c 项目: relaxdiego/ctags
static void parseSelector (vString *const string, const int firstChar)
{
	int c = firstChar;
	do
	{
		vStringPut (string, (char) c);
		c = fileGetc ();
	} while (isSelectorChar (c));
	fileUngetc (c);
	vStringTerminate (string);
}
示例#24
0
文件: js.c 项目: BenWiederhake/geany
static void parseString (vString *const string, const int delimiter)
{
	boolean end = FALSE;
	while (! end)
	{
		int c = fileGetc ();
		if (c == EOF)
			end = TRUE;
		else if (c == '\\')
		{
			/* Eat the escape sequence (\", \', etc).  We properly handle
			 * <LineContinuation> by eating a whole \<CR><LF> not to see <LF>
			 * as an unescaped character, which is invalid and handled below.
			 * Also, handle the fact that <LineContinuation> produces an empty
			 * sequence.
			 * See ECMA-262 7.8.4 */
			c = fileGetc();
			if (c != '\r' && c != '\n')
				vStringPut(string, c);
			else if (c == '\r')
			{
				c = fileGetc();
				if (c != '\n')
					fileUngetc (c);
			}
		}
		else if (c == delimiter)
			end = TRUE;
		else if (c == '\r' || c == '\n')
		{
			/* those are invalid when not escaped */
			end = TRUE;
			/* we don't want to eat the newline itself to let the automatic
			 * semicolon insertion code kick in */
			fileUngetc (c);
		}
		else
			vStringPut (string, c);
	}
	vStringTerminate (string);
}
示例#25
0
文件: read.c 项目: pragmaware/ctags
/* While ANSI only permits lines of the form:
 *   # line n "filename"
 * Earlier compilers generated lines of the form
 *   # n filename
 * GNU C will output lines of the form:
 *   # n "filename"
 * So we need to be fairly flexible in what we accept.
 */
static vString *readFileName (char *s)
{
	vString *const fileName = vStringNew ();
	bool quoteDelimited = false;

	skipWhite (&s);
	if (*s == '"')
	{
		s++;  /* skip double-quote */
		quoteDelimited = true;
	}
	while (*s != '\0'  &&  *s != '\n'  &&
			(quoteDelimited ? (*s != '"') : (*s != ' '  &&  *s != '\t')))
	{
		vStringPut (fileName, *s);
		s++;
	}
	vStringPut (fileName, '\0');

	return fileName;
}
示例#26
0
文件: vhdl.c 项目: pragmaware/ctags
/*  Read a VHDL identifier beginning with "firstChar" and place it into "name".
*/
static void parseIdentifier (vString * const string, const int firstChar)
{
	int c = firstChar;
	Assert (isIdentChar1 (c));
	do
	{
		vStringPut (string, c);
		c = getcFromInputFile ();
	} while (isIdentChar (c));
	if (!isspace (c))
		ungetcToInputFile (c);	/* unget non-identifier character */
}
示例#27
0
文件: js.c 项目: BenWiederhake/geany
/*	Read a C identifier beginning with "firstChar" and places it into
 *	"name".
 */
static void parseIdentifier (vString *const string, const int firstChar)
{
	int c = firstChar;
	Assert (isIdentChar (c));
	do
	{
		vStringPut (string, c);
		c = fileGetc ();
	} while (isIdentChar (c));
	vStringTerminate (string);
	fileUngetc (c);		/* unget non-identifier character */
}
示例#28
0
文件: make.c 项目: ajitvin/v
static void readIdentifier (const int first, vString *const id)
{
	int c = first;
	vStringClear (id);
	while (isIdentifier (c))
	{
		vStringPut (id, c);
		c = nextChar ();
	}
	fileUngetc (c);
	vStringTerminate (id);
}
示例#29
0
CXXToken * cxxTokenChainExtractRange(
		CXXToken * from,
		CXXToken * to,
		unsigned int uFlags
	)
{
	if(!from)
		return NULL;

	CXXToken * pToken = from;

	CXXToken * pRet = cxxTokenCreate();
	pRet->iLineNumber = pToken->iLineNumber;
	pRet->oFilePosition = pToken->oFilePosition;
	pRet->eType = pToken->eType;

	cxxTokenAppendToString(pRet->pszWord,pToken);
	if(
			(!(uFlags & CXXTokenChainExtractRangeNoTrailingSpaces)) &&
			pToken->bFollowedBySpace
		)
		vStringPut (pRet->pszWord, ' ');
	pRet->bFollowedBySpace = pToken->bFollowedBySpace;

	while(pToken != to)
	{
		pToken = pToken->pNext;
		if(!pToken)
			return pRet;
		cxxTokenAppendToString(pRet->pszWord,pToken);
		if(
				(!(uFlags & CXXTokenChainExtractRangeNoTrailingSpaces)) &&
				pToken->bFollowedBySpace
			)
			vStringPut (pRet->pszWord, ' ');
		pRet->bFollowedBySpace = pToken->bFollowedBySpace;
	}

	return pRet;
}
示例#30
0
void cxxTokenChainJoinInString(
		CXXTokenChain * tc,
		vString * s,
		const char * szSeparator,
		unsigned int uFlags
	)
{
	if(!tc)
		return;

	if(tc->iCount == 0)
		return;

	CXXToken * t = tc->pHead;

	cxxTokenAppendToString(s,t);

	if(
			(!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) &&
			t->bFollowedBySpace
		)
		vStringPut (s, ' ');

	t = t->pNext;
	while(t)
	{
		if(szSeparator)
			vStringCatS(s,szSeparator);

		cxxTokenAppendToString(s,t);

		if(
				(!(uFlags & CXXTokenChainJoinNoTrailingSpaces)) &&
				t->bFollowedBySpace
			)
			vStringPut (s, ' ');

		t = t->pNext;
	}
}