Beispiel #1
0
const char *TokenParser::ParseToken( bool allowLineBreaks ) {
	bool hasNewLines = false;

	token[0] = '\0';

	if ( !data ) {
		return token;
	}

	char c = '\0';
	while ( 1 ) {
		// skip whitespace
		SkipWhitespace( &hasNewLines );

		if ( !data ) {
			return token;
		}
		if ( hasNewLines && !allowLineBreaks ) {
			return token;
		}

		c = *data;

		if ( c == '/' && data[1] == '/' ) {
			// skip double slash comments
			//data += 2;
			while ( *data && *data != '\n' ) {
				data++;
			}
		}

		else if ( c == '/' && data[1] == '*' ) {
			// skip block comments
			//data += 2;
			while ( *data && (*data != '*' || data[1] != '/') ) {
				data++;
			}
			if ( *data ) {
				data += 2;
			}
		}
		else {
			break;
		}
	}

	size_t len = 0u;
	if ( c == '\"' || c == '\'' ) {
		// handle quoted strings (both " and ')
		const char quotechar = c;
		data++;
		while ( 1 ) {
			c = *data++;
			if ( c == quotechar || !c || ((c == '\r' || c == '\n') && !allowLineBreaks) ) {
				token[len] = '\0';
				return token;
			}

			if ( len < sizeof(token) ) {
				token[len++] = c;
			}
		}
	}

	// parse a token
	while ( c > 32 ) {
		if ( len < sizeof(token) ) {
			token[len++] = c;
		}
		data++;

		c = *data;
		if ( c == '\n' ) {
			numLines++;
		}
	};

	token[len] = '\0';

	return token;
}
Beispiel #2
0
void Preprocess (void)
/* Preprocess a line */
{
    int         Skip;
    ident       Directive;

    /* Create the output buffer if we don't already have one */
    if (MLine == 0) {
        MLine = NewStrBuf ();
    }

    /* Skip white space at the beginning of the line */
    SkipWhitespace (0);

    /* Check for stuff to skip */
    Skip = 0;
    while (CurC == '\0' || CurC == '#' || Skip) {

        /* Check for preprocessor lines lines */
        if (CurC == '#') {
            NextChar ();
            SkipWhitespace (0);
            if (CurC == '\0') {
                /* Ignore the empty preprocessor directive */
                continue;
            }
            if (!IsSym (Directive)) {
                PPError ("Preprocessor directive expected");
                ClearLine ();
            } else {
                switch (FindPPToken (Directive)) {

                    case PP_DEFINE:
                        if (!Skip) {
                            DefineMacro ();
                        }
                        break;

                    case PP_ELIF:
                        if (IfIndex >= 0) {
                            if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {

                                /* Handle as #else/#if combination */
                                if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
                                    Skip = !Skip;
                                }
                                IfStack[IfIndex] |= IFCOND_ELSE;
                                Skip = DoIf (Skip);

                                /* #elif doesn't need a terminator */
                                IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
                            } else {
                                PPError ("Duplicate #else/#elif");
                            }
                        } else {
                            PPError ("Unexpected #elif");
                        }
                        break;

                    case PP_ELSE:
                        if (IfIndex >= 0) {
                            if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
                                if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
                                    Skip = !Skip;
                                }
                                IfStack[IfIndex] |= IFCOND_ELSE;
                            } else {
                                PPError ("Duplicate #else");
                            }
                        } else {
                            PPError ("Unexpected `#else'");
                        }
                        break;

                    case PP_ENDIF:
                        if (IfIndex >= 0) {
                            /* Remove any clauses on top of stack that do not
                             * need a terminating #endif.
                             */
                            while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
                                --IfIndex;
                            }

                            /* Stack may not be empty here or something is wrong */
                            CHECK (IfIndex >= 0);

                            /* Remove the clause that needs a terminator */
                            Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0;
                        } else {
                            PPError ("Unexpected `#endif'");
                        }
                        break;

                    case PP_ERROR:
                        if (!Skip) {
                            DoError ();
                        }
                        break;

                    case PP_IF:
                        Skip = DoIf (Skip);
                        break;

                    case PP_IFDEF:
                        Skip = DoIfDef (Skip, 1);
                        break;

                    case PP_IFNDEF:
                        Skip = DoIfDef (Skip, 0);
                        break;

                    case PP_INCLUDE:
                        if (!Skip) {
                            DoInclude ();
                        }
                        break;

                    case PP_LINE:
                        /* Should do something in C99 at least, but we ignore it */
                        if (!Skip) {
                            ClearLine ();
                        }
                        break;

                    case PP_PRAGMA:
                        if (!Skip) {
                            DoPragma ();
                            goto Done;
                        }
                        break;

                    case PP_UNDEF:
                        if (!Skip) {
                            DoUndef ();
                        }
                        break;

                    case PP_WARNING:
                        /* #warning is a non standard extension */
                        if (IS_Get (&Standard) > STD_C99) {
                            if (!Skip) {
                                DoWarning ();
                            }
                        } else {
                            if (!Skip) {
                                PPError ("Preprocessor directive expected");
                            }
                            ClearLine ();
                        }
                        break;

                    default:
                        if (!Skip) {
                            PPError ("Preprocessor directive expected");
                        }
                        ClearLine ();
                }
            }

        }
        if (NextLine () == 0) {
            if (IfIndex >= 0) {
                PPError ("`#endif' expected");
            }
            return;
        }
        SkipWhitespace (0);
    }

    PreprocessLine ();

Done:
    if (Verbosity > 1 && SB_NotEmpty (Line)) {
        printf ("%s(%u): %.*s\n", GetCurrentFile (), GetCurrentLine (),
                (int) SB_GetLen (Line), SB_GetConstBuf (Line));
    }
}
Beispiel #3
0
LONG GetExpression(VOID)
{
    LONG op1;
    LONG op2;
    WCHAR byOperator;
    UINT wFlags;

    /* Get the first operand */
    op1 = GetOperand();

    /* take care of symbol use */
    if (curChar == SYMUSESTART) {
        GetSymbol(TRUE, curChar);
        token.sym.nID = token.val;
    }

    /* Loop until end of expression */
    for (; ; ) {
        /* Get the operator */
        wFlags = GetOperator(&byOperator);

        /* If this is a right paren, dec the count */
        if (byOperator == L')') {
            /* Bring the paren count back down */
            --nParenCount;

            /* Skip the paren and any trailing whitespace */
            OurGetChar();
            SkipWhitespace();
        }

        /* If this isn't an operator, we're done with the expression */
        if (!wFlags)
        {
            token.sym.nID = (unsigned)op1;
            return op1;
        }
        token.sym.name[0] = L'\0';

        /* Get the second operand */
        op2 = GetOperand();

        /* Compute the value of the expression */
        switch (byOperator)
        {
            case L'+':
                op1 += op2;
                break;

            case L'-':
                op1 -= op2;
                break;

            case L'&':
                op1 &= op2;
                break;

            case L'|':
                op1 |= op2;
                break;
        }
    }
}
Beispiel #4
0
void *Asc2Bin(const	char *source,	const	int	count, const char	*spec, void	*dest)
{
  if ( !source || !spec ) 
		return 0;
	int	cnt	=	0;
	int	size = 0;

	Atype	types[MAXARG];

	const	char *ctype	=	spec;

	while	(*ctype)
	{
		switch (ToLower(*ctype))
		{
			case 'f':
				size +=	sizeof(float);
				types[cnt] = AT_FLOAT;
				cnt++;
				break;
			case 'd':
				size +=	sizeof(int);
				types[cnt] = AT_INT;
				cnt++;
				break;
			case 'c':
				size +=	sizeof(char);
				types[cnt] = AT_CHAR;
				cnt++;
				break;
			case 'b':
				size +=	sizeof(char);
				types[cnt] = AT_BYTE;
				cnt++;
				break;
			case 'h':
				size +=	sizeof(short);
				types[cnt] = AT_SHORT;
				cnt++;
				break;
			case 'p':
				size +=	sizeof(const char*);
				types[cnt] = AT_STR;
				cnt++;
				break;
			case 'x':
				if (1)
				{
					Atype	type = AT_HEX4;
					int	sz = 4;
					switch (ctype[1])
					{
					case '1':
						type = AT_HEX1;
						sz = 1;
						ctype++;
						break;
					case '2':
						type = AT_HEX2;
						sz = 2;
						ctype++;
						break;
					case '4':
						type = AT_HEX4;
						sz = 4;
						ctype++;
						break;
					}
					types[cnt] = type;
					size +=	sz;
					cnt++;
				}
				break;
		}
		if (cnt	== MAXARG)
		{
			return 0;
		}
		// over	flowed the maximum specification!
		ctype++;
	}

	bool myalloc = false;

	if (dest ==	0)
	{
		myalloc	=	true;
		dest = (char*)new	char[count *size];
	}

	// ok...ready	to parse lovely	data....
	memset(dest, 0,	count	*size);	// zero	out	memory

	char *dst	=	(char*)dest; //	where	we are storing the results
	for	(int i = 0;	i	<	count && source; i++)
	{
		for	(int j = 0;	j	<	cnt && source; j++)
		{
			source = SkipWhitespace(source); //	skip white spaces.

			if (*source	== 0)
			// we	hit	the	end	of the input data	before we	successfully parsed	all	input!
			{
				if (myalloc)
				{
					delete (char*)dest;
				}
				return 0;
			}

			switch (types[j])
			{
				case AT_FLOAT:
					if (1)
					{
						float	*v = (float*)dst;
						*v = GetFloatValue(source, &source);
						dst	+= sizeof(float);
					}
					break;
				case AT_INT:
					if (1)
					{
						int	*v = (int*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(int);
					}
					break;
				case AT_CHAR:
					if (1)
					{
						*dst++ =	*source++;
					}
					break;
				case AT_BYTE:
					if (1)
					{
						char *v	=	(char*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(char);
					}
					break;
				case AT_SHORT:
					if (1)
					{
						short	*v = (short*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(short);
					}
					break;
				case AT_STR:
					if (1)
					{
						const	char **ptr = (const	char **)dst;
						*ptr = source;
						dst	+= sizeof(const	char*);
						while	(*source &&	!IsWhitespace(*source))
						{
							source++;
						}
					}
					break;
				case AT_HEX1:
					if (1)
					{
						unsigned int hex = GetHEX1(source, &source);
						unsigned char	*v = (unsigned char*)dst;
						*v = hex;
						dst	+= sizeof(unsigned char);
					}
					break;
				case AT_HEX2:
					if (1)
					{
						unsigned int hex = GetHEX2(source, &source);
						unsigned short *v	=	(unsigned	short*)dst;
						*v = hex;
						dst	+= sizeof(unsigned short);
					}
					break;
				case AT_HEX4:
					if (1)
					{
						unsigned int hex = GetHEX4(source, &source);
						unsigned int *v	=	(unsigned	int*)dst;
						*v = hex;
						dst	+= sizeof(unsigned int);
					}
					break;
				default:
					break;
			}
		}
	}

	return dest;
}
Beispiel #5
0
bool GrammarParseItem(Grammar *grammar, GrammarOption *option, char **pos, bool *ok)
{
    *ok = true;

    // Are we at the end of the line?
    SkipWhitespace(pos);
    if (**pos == 0)
    {
        // There are no more items.
        return false;
    }

    // Create an item node.
    GrammarItem *item = calloc(1, sizeof(*item));
    if (item == NULL)
    {
        AllocSprintf(&grammar->errMsg, "out of memory");
        return false;
    }

    // Add it to the end of the list.
    if (option->firstItem == NULL)
    {
        option->firstItem = item;
        option->lastItem = item;
    }
    else
    {
        option->lastItem->nextItem = item;
        option->lastItem = item;
    }

    item->nextItem = NULL;
    item->repeated = false;
    item->definitionName = NULL;
    item->token = NULL;
    item->charSet = NULL;

    // Is it repeated?
    bool repeated = false;
    char ch = **pos;
    if (ch == '[')
    {
        repeated = true;
        (*pos)++;
    }

    // What kind of token is next?
    switch (ch)
    {
    case 0:
        AllocSprintf(&grammar->errMsg, "missing item after '[' in line %d\n", grammar->lineNo);
        *ok = false;
        break;

    case '\'':
        *ok = GrammarParseString(grammar, item, pos);
        break;

    case '{':
        *ok = GrammarParseCharSet(grammar, item, pos);
        break;

    default:
        if (isalpha(ch))
        {
            // Parse a definition name.
            item->definitionName = GrammarParseIdentifier(pos);
        }
        else
        {
            // It's something unknown.
            AllocSprintf(&grammar->errMsg, "unknown character in line %d\n", grammar->lineNo);
            *ok = false;
        }
        break;
    }

    // If it was repeated, make sure we have a closing square bracket.
    if (repeated)
    {
        if (**pos != ']')
        {
            AllocSprintf(&grammar->errMsg, "expected closing ']' after repeated term in line %d\n", grammar->lineNo);
            *ok = false;
        }

        item->repeated = true;
    }

    // If we're failing out deallocate the item.
    if (!*ok)
    {
        free(item);
        return false;
    }

    return true;
}
void HLSLTokenizer::Next(const bool EOLSkipping)
{
    m_bufferPrevious = m_buffer;

    while( SkipWhitespace(EOLSkipping) || SkipComment(&m_buffer, EOLSkipping) || ScanLineDirective() || SkipPragmaDirective() )
    {
    }

    if (m_error)
    {
        m_token = HLSLToken_EndOfStream;
        return;
    }

    if (!EOLSkipping && m_buffer[0] == '\n')
    {
        m_token = HLSLToken_EndOfLine;
        return;
    }

    m_tokenLineNumber = m_lineNumber;

    if (m_buffer >= m_bufferEnd || *m_buffer == '\0')
    {
        m_token = HLSLToken_EndOfStream;
        return;
    }

    const char* start = m_buffer;

    // +=, -=, *=, /=, ==, <=, >=
    if (m_buffer[0] == '+' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_PlusEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '-' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_MinusEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '*' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_TimesEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '/' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_DivideEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '=' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_EqualEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '!' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_NotEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '<' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_LessEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '>' && m_buffer[1] == '=')
    {
        m_token = HLSLToken_GreaterEqual;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '&' && m_buffer[1] == '&')
    {
        m_token = HLSLToken_AndAnd;
        m_buffer += 2;
        return;
    }
    else if (m_buffer[0] == '|' && m_buffer[1] == '|')
    {
        m_token = HLSLToken_BarBar;
        m_buffer += 2;
        return;
    }

    // ++, --
    if ((m_buffer[0] == '-' || m_buffer[0] == '+') && (m_buffer[1] == m_buffer[0]))
    {
        m_token = (m_buffer[0] == '+') ? HLSLToken_PlusPlus : HLSLToken_MinusMinus;
        m_buffer += 2;
        return;
    }

    // Check for the start of a number.
    if (ScanNumber())
    {
        return;
    }
    
    if (GetIsSymbol(m_buffer[0]))
    {
        m_token = static_cast<unsigned char>(m_buffer[0]);
        ++m_buffer;
        return;
    }

    // Must be an identifier or a reserved word.
    while (m_buffer < m_bufferEnd && m_buffer[0] != 0 && !GetIsSymbol(m_buffer[0]) && !isspace(m_buffer[0]))
    {
        ++m_buffer;
    }

    size_t length = m_buffer - start;
    memcpy(m_identifier, start, length);
    m_identifier[length] = 0;
    
    const int numReservedWords = sizeof(_reservedWords) / sizeof(const char*);
    for (int i = 0; i < numReservedWords; ++i)
    {
        if (strcmp(_reservedWords[i], m_identifier) == 0)
        {
            m_token = 256 + i;
            return;
        }
    }

    m_token = HLSLToken_Identifier;

}
const TCHAR* UStructProperty::ImportText_Static(UScriptStruct* InStruct, const FString& Name, const TCHAR* InBuffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText)
{
	auto Struct = InStruct;

	if (Struct->StructFlags & STRUCT_ImportTextItemNative)
	{
		UScriptStruct::ICppStructOps* CppStructOps = Struct->GetCppStructOps();
		check(CppStructOps); // else should not have STRUCT_ImportTextItemNative
		if (CppStructOps->ImportTextItem(InBuffer, Data, PortFlags, Parent, ErrorText))
		{
			return InBuffer;
		}
	}
	
	TArray<FDefinedProperty> DefinedProperties;
	// this keeps track of the number of errors we've logged, so that we can add new lines when logging more than one error
	int32 ErrorCount = 0;
	const TCHAR* Buffer = InBuffer;
	if (*Buffer++ == TCHAR('('))
	{
		// Parse all properties.
		while (*Buffer != TCHAR(')'))
		{
			// parse and import the value
			Buffer = ImportSingleProperty(Buffer, Data, Struct, Parent, PortFlags | PPF_Delimited, ErrorText, DefinedProperties);

			// skip any remaining text before the next property value
			SkipWhitespace(Buffer);
			int32 SubCount = 0;
			while ( *Buffer && *Buffer != TCHAR('\r') && *Buffer != TCHAR('\n') &&
					(SubCount > 0 || *Buffer != TCHAR(')')) && (SubCount > 0 || *Buffer != TCHAR(',')) )
			{
				SkipWhitespace(Buffer);
				if (*Buffer == TCHAR('\"'))
				{
					do
					{
						Buffer++;
					} while (*Buffer && *Buffer != TCHAR('\"') && *Buffer != TCHAR('\n') && *Buffer != TCHAR('\r'));

					if (*Buffer != TCHAR('\"'))
					{
						ErrorText->Logf(TEXT("%sImportText (%s): Bad quoted string at: %s"), ErrorCount++ > 0 ? LINE_TERMINATOR : TEXT(""), *Name, Buffer);
						return NULL;
					}
				}
				else if( *Buffer == TCHAR('(') )
				{
					SubCount++;
				}
				else if( *Buffer == TCHAR(')') )
				{
					SubCount--;
					if( SubCount < 0 )
					{
						ErrorText->Logf(TEXT("%sImportText (%s): Too many closing parenthesis in: %s"), ErrorCount++ > 0 ? LINE_TERMINATOR : TEXT(""), *Name, InBuffer);
						return NULL;
					}
				}
				Buffer++;
			}
			if( SubCount > 0 )
			{
				ErrorText->Logf(TEXT("%sImportText(%s): Not enough closing parenthesis in: %s"), ErrorCount++ > 0 ? LINE_TERMINATOR : TEXT(""), *Name, InBuffer);
				return NULL;
			}

			// Skip comma.
			if( *Buffer==TCHAR(',') )
			{
				// Skip comma.
				Buffer++;
			}
			else if( *Buffer!=TCHAR(')') )
			{
				ErrorText->Logf(TEXT("%sImportText (%s): Missing closing parenthesis: %s"), ErrorCount++ > 0 ? LINE_TERMINATOR : TEXT(""), *Name, InBuffer);
				return NULL;
			}

			SkipWhitespace(Buffer);
		}

		// Skip trailing ')'.
		Buffer++;
	}
	else
	{
		ErrorText->Logf(TEXT("%sImportText (%s): Missing opening parenthesis: %s"), ErrorCount++ > 0 ? LINE_TERMINATOR : TEXT(""), *Name, InBuffer);
		return NULL;
	}
	return Buffer;
}
Beispiel #8
0
bool mcMapParser::ReadNextToken (csString& str)
{
  char c, next_c;

  str.Clear();
  m_empty_token = false;

  /* Skip commented and empty lines */
  for(;;)
  {
    if( !SkipWhitespace() ) 
    {
      return false;
    }

    if( !GetChar(c) )
    {
      return false;
    }

    if(c == '\n')
    {
      /* An empty line */
      ++m_current_line;
      continue;
    }

    if( PeekChar(next_c) )
    {
      if( c == '/' && next_c == '/')
      {
        if( !SkipToNextLine() )
        {
          return false;
        }
      }
      else
      {
        break;
      }
    }
    else
    {
      break;
    }
  }

  /* Quoted strings are returned directly */
  if (c == '\"')
  {
    for(;;)
    {
      if ( !GetChar(c) )
      {
        /* If we fail now, the token is not complete! */
        return false; 
      }

      if (c == '\"')
      {
        /* The end of the string has been reached */
	m_empty_token = str.IsEmpty();
        return true;
      }

      str << c;
    }
  }

  /* Check for special single character tokens */
  if ( c == '{'  || c == '}' ||
       c == '('  || c == ')' ||
       c == '\'' || c ==':'  )
  {
    str << c;
    return true;
  }

  /* Parse a regular word */
  for(;;)
  {
    str << c;

    if (!PeekChar(next_c))
    {
      break;
    }

    if ( next_c == '{'  || next_c == '}'  ||
         next_c == '('  || next_c == ')'  ||
         next_c == '\'' || next_c ==':'   ||
         next_c == ' '  || next_c == '\t' || 
         next_c == '\r' || next_c == '\n' )
    {
      break;
    }

    if(!GetChar(c))
    {
      break;
    }
  }

  return true;
}
Beispiel #9
0
// FindEnclosed
bool COpcTextReader::FindEnclosed(COpcText& cToken)
{
    OPC_ASSERT(m_szBuf != NULL);
    OPC_ASSERT(m_uLength != 0);
      
    WCHAR zStart = 0;
    WCHAR zEnd   = 0;
    cToken.GetBounds(zStart, zEnd);

    // skip leading whitespace
    UINT uPosition = SkipWhitespace(cToken);

    // check if there is still data left to read.
    if (uPosition >= m_uEndOfData)
    {
        return false;
    } 

    // read until finding the start delimiter,
    for (UINT ii = uPosition; ii < m_uEndOfData; ii++)
    {
        // check if search halted.
        if (CheckForHalt(cToken, ii))
        {
            return false;
        }

        // check for start character.
        if (IsEqual(cToken, m_szBuf[ii], zStart)) 
        {
            uPosition = ii;
            break;
        }
    }
    
    // check if there is still data left to read.
    if (ii >= m_uEndOfData)
    {
        return false;
    } 

    // read until finding the end delimiter,
    for (ii = uPosition+1; ii < m_uEndOfData; ii++)
    {
        // check if search halted.
        if (CheckForHalt(cToken, ii))
        {
            return false;
        }

        // check for end character.
        if (IsEqual(cToken, m_szBuf[ii], zStart)) 
        {
            // ignore if character is escaped.
            if (cToken.GetAllowEscape() && (uPosition < ii-1))
            {
                if (m_szBuf[ii-1] == L'\\')
                {
                    continue;
                }
            }

            // copy token - empty tokens are valid.
            CopyData(cToken, uPosition+1, ii);
            return true;
        }
    }

    return false;
}
Beispiel #10
0
bool Match(char* ptr, unsigned int depth, int startposition, char* kind, bool wildstart,unsigned int& gap,unsigned int& wildcardSelector,
	int &returnstart,int& returnend,bool &uppercasem,int& firstMatched,int& positionStart,int& positionEnd, bool reverse)
{//   always STARTS past initial opening thing ( [ {  and ends with closing matching thing
	int startdepth = globalDepth;
    char word[MAX_WORD_SIZE];
	char* orig = ptr;
	int statusBits = (*kind == '<') ? FREEMODE_BIT : 0; //   turns off: not, quote, startedgap, freemode, gappassback,wildselectorpassback
    if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERTABLOG, "%s ",kind); //   start on new indented line
	ChangeDepth(1,(char*)"Match");
    bool matched;
	unsigned int startNest = functionNest;
	unsigned int result;
	int pendingMatch = -1;
    WORDP D;
	int hold;
	unsigned int oldtrace = trace;
	bool oldecho = echo;
	bool success = false;
    firstMatched = -1; //   ()  should return spot it started (firstMatched) so caller has ability to bind any wild card before it
    if (wildstart)  positionStart = INFINITE_MATCH; //   INFINITE_MATCH means we are in initial startup, allows us to match ANYWHERE forward to start
    positionEnd = startposition; //   we scan starting 1 after this
 	int basicStart = startposition;	//   we must not match real stuff any earlier than here
    char* argumentText = NULL; //   pushed original text from a function arg -- function arg never decodes to name another function arg, we would have expanded it instead
    bool uppercasematch = false;
	while (ALWAYS) //   we have a list of things, either () or { } or [ ].  We check each item until one fails in () or one succeeds in  [ ] or { }
    {
        int oldStart = positionStart; //  allows us to restore if we fail, and confirm legality of position advance.
        int oldEnd = positionEnd;
		int id;
		char* nextTokenStart = SkipWhitespace(ptr);
		ptr = ReadCompiledWord(nextTokenStart,word);
		if (*word == '<' && word[1] == '<')  ++nextTokenStart; // skip the 1st < of <<  form
		if (*word == '>' && word[1] == '>')  ++nextTokenStart; // skip the 1st > of >>  form
		nextTokenStart = SkipWhitespace(nextTokenStart+1);	// ignore blanks after if token is a simple single thing like !

		char c = *word;
		if (deeptrace) Log(STDUSERLOG,(char*)" token:%s ",word);
        switch(c) 
        {
			// prefixs on tokens
            case '!': //   NOT condition - not a stand-alone token, attached to another token
				ptr = nextTokenStart;
				statusBits |= NOT_BIT;
				if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"!");
				if (*ptr == '!') 
				{
					ptr = SkipWhitespace(nextTokenStart+1);
					statusBits |= NOTNOT_BIT;
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"!");
				}
				continue;
			case '\'': //   single quoted item    
				if (!stricmp(word,(char*)"'s"))
				{
					matched = MatchTest(reverse,FindWord(word),(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,NULL,NULL,
						statusBits & QUOTE_BIT,uppercasematch,positionStart,positionEnd);
					if (!matched || !(wildcardSelector & WILDMEMORIZESPECIFIC)) uppercasematch = false;
					if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart;
					break;
				}
				else
				{
					statusBits |= QUOTE_BIT;
					ptr = nextTokenStart;
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"'");
					continue;
				}
			case '_': //     memorization coming - there can be up-to-two memorizations in progress: _* and _xxx  OR  simply names a memorized value like _8
				
				// a wildcard id?
				if (IsDigit(word[1]))
				{
					matched = GetwildcardText(GetWildcardID(word),false)[0] != 0; // simple _2  means is it defined
					break;
				}
				ptr = nextTokenStart;
			
				// if we are going to memorize something AND we previously matched inside a phrase, we need to move to after...
				if ((positionStart - positionEnd) == 1 && !reverse) positionEnd = positionStart; // If currently matched a phrase, move to end. 
				else if ((positionEnd - positionStart) == 1 && reverse) positionStart = positionEnd; // If currently matched a phrase, move to end. 
				uppercasematch = false;

				// specifics are fixed values in length, gaps are unknown lengths

				if (ptr[0] != '*') wildcardSelector |= WILDMEMORIZESPECIFIC; // no wildcard
				else if (IsDigit(ptr[1])) wildcardSelector |= WILDMEMORIZESPECIFIC; // specific gap like *2
				else if (ptr[1] == '~') wildcardSelector |= WILDMEMORIZEGAP; // variable gap like *~2
				else if ( ptr[1] == '-') wildcardSelector |= WILDMEMORIZESPECIFIC; // backwards specific gap like *-4
				else if (ptr[0] == '*' && IsAlphaUTF8(ptr[1]))  wildcardSelector |= WILDMEMORIZESPECIFIC; // *dda* pattern
				else wildcardSelector |=  WILDMEMORIZEGAP; // variable gap
				if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"_");
				continue;
			case '@': // factset ref
				if (word[1] == '_') // set positional reference  @_20+ or @_0-   
				{
					if (firstMatched < 0) firstMatched = NORETRY; // cannot retry this match locally
	
					// memorize gap to end based on direction...xxxx
					if (gap && !reverse) // close to end of sentence 
					{
						positionStart = wordCount; // pretend to match at end of sentence
						int start = gap & 0x000000ff;
						int limit = (gap >> 8);
						gap = 0;   //   turn off
  						if ((positionStart + 1 - start) > limit) //   too long til end
						{
							matched = false;
 							wildcardSelector &= -1 ^ WILDMEMORIZEGAP;
							break;
						}
						if (wildcardSelector & WILDMEMORIZEGAP) 
						{
							SetWildCard(start,wordCount,true);  //   legal swallow of gap //   request memorize
 							wildcardSelector &= -1 ^ WILDMEMORIZEGAP;
						}
					}

					char* end = word+3;  // skip @_2
					if (IsDigit(*end)) ++end; // point to proper + or - ending
					unsigned int wild = wildcardPosition[GetWildcardID(word+1)];
					if (*end == '+') 
					{
						positionStart = WILDCARD_START(wild);
						positionEnd = WILDCARD_END(wild);
						reverse = false;
					}
					else if (*end == '-') 
					{
						reverse = true;
						positionStart = WILDCARD_END(wild);
						positionEnd = WILDCARD_START(wild); 
					}
					if (!positionEnd) break;
					oldEnd = positionEnd; // forced match ok
					oldStart = positionStart;
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) 
					{
						if (positionStart <= 0 || positionStart > wordCount || positionEnd <= 0 || positionEnd > wordCount) Log(STDUSERLOG, "(index:%d)",positionEnd);
						else if (positionStart == positionEnd) Log(STDUSERLOG,(char*)"(word:%s index:%d)",wordStarts[positionEnd],positionEnd);
						else Log(STDUSERLOG,(char*)"(word:%s-%s index:%d-%d)",wordStarts[positionStart],wordStarts[positionEnd],positionStart,positionEnd);
					}
					matched = true;
				}
				else
				{
					int set = GetSetID(word);
					if (set == ILLEGAL_FACTSET) matched = false;
					else matched = FACTSET_COUNT(set) != 0;
				}
				break;
   			case '<': //   sentence start marker OR << >> set
				if (firstMatched < 0) firstMatched = NORETRY; // cannot retry this match
				if (word[1] == '<') 
					goto DOUBLELEFT; //   << 
                else 
				{
					ptr = nextTokenStart;
					if (gap && !reverse) // cannot memorize going forward to  start of sentence
					{
						gap = 0;  
						matched = false;
 						wildcardSelector &= -1 ^ WILDMEMORIZEGAP;
					}
					else { // match can FORCE it to go to start from any direction
						positionStart = positionEnd = 0; //   idiom < * and < _* handled under *
						matched = true;
					}
				}
                break;
            case '>': //   sentence end marker
				if (word[1] == '>') 
					goto DOUBLERIGHT; //   >> closer, and reset to start of sentence wild again...
				
				ptr = nextTokenStart;
				if (gap && reverse) // cannot memorize going backward to  end of sentence
				{
					gap = 0;  
					matched = false;
 					wildcardSelector &= -1 ^ WILDMEMORIZEGAP;
				}
				else if (gap || positionEnd == wordCount)// you can go to end from anywhere if you have a gap OR you are there
				{
					matched =  true;
					positionStart = positionEnd = wordCount + 1; //   pretend to match a word off end of sentence
				}
				else matched = false;
                break;
             case '*': //   GAP - accept anything (perhaps with length restrictions)
				if (word[1] == '-') //   backward gap, -1 is word before now -- BUG does not respect unmark system
				{
					int at = positionEnd - (word[2] - '0') - 1; // limited to 9 back
					if (at >= 0) //   no earlier than pre sentence start
					{
						oldEnd = at; //   set last match BEFORE our word
						positionStart = positionEnd = at + 1; //   cover the word now
						matched = true; 
					}
					else matched = false;
				}
				else if (IsDigit(word[1]))  // fixed length gap
                {
					int at;
					int count = word[1] - '0';	// how many to swallow
					if (reverse)
					{
						int begin = positionStart -1;
						at = positionStart; // start here
						while (count-- && --at >= 1) // can we swallow this (not an ignored word)
						{
							if (unmarked[at]) 
							{
								++count;	// ignore this word
								if (at == begin) --begin;	// ignore this as starter
							}
						}
						if (at >= 1 ) // pretend match
						{ 
							positionEnd = begin ; // pretend match here -  wildcard covers the gap
							positionStart = at; 
							matched = true; 
						}
						else  matched = false;
					}
					else
					{
						at = positionEnd; // start here
						int begin = positionEnd + 1;
						while (count-- && ++at <= wordCount) // can we swallow this (not an ignored word)
						{
							if (unmarked[at]) 
							{
								++count;	// ignore this word
								if (at == begin) ++begin;	// ignore this as starter
							}
						}
						if (at <= wordCount ) // pretend match
						{ 
							positionStart = begin; // pretend match here -  wildcard covers the gap
 							positionEnd = at; 
							matched = true; 
						}
						else  matched = false;
					}
                }
				else if (IsAlphaUTF8(word[1]) || word[1] == '*') 
					matched = FindPartialInSentenceTest(word+1,(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,positionStart,reverse,
					positionStart,positionEnd); // wildword match like st*m* or *team* matches steamroller
                else // variable gap
                {
                    if (word[1] == '~') gap = (word[2]-'0') << 8; // *~3 - limit 9 back
                    else // I * meat
					{
						gap = 200 << 8;  // 200 is a safe infinity
						if (positionStart == 0) positionStart = INFINITE_MATCH; // < * resets to allow match anywhere
					}
                    gap |= (reverse) ? (positionStart  - 1) : (positionEnd  + 1);
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"%s ",word);
					continue;
                }
                break;
            case '$': // is user variable defined
				{
					char* val = GetUserVariable(word);
					matched = *val ? true : false;
				}
                break;
            case '^': //   function call, function argument  or indirect function variable assign ref like ^$$tmp = null
                 if  (IsDigit(word[1]) || word[1] == '$' || word[1] == '_') //   macro argument substitution or indirect function variable
                {
                    argumentText = ptr; //   transient substitution of text

					if (IsDigit(word[1]))  ptr = callArgumentList[word[1]-'0'+fnVarBase];  // nine argument limit
					else if (word[1] == '$') ptr = GetUserVariable(word+1); // get value of variable and continue in place
					else ptr = wildcardCanonicalText[GetWildcardID(word+1)]; // ordinary wildcard substituted in place (bug)?
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"%s=>",word);
					continue;
                }
                
				D = FindWord(word,0); // find the function
				if (!D || !(D->internalBits & FUNCTION_NAME)) matched = false; // shouldnt fail
				else if (D->x.codeIndex) // system function - execute it
                {
					char* old = currentOutputBase;
					char* oldrule = currentRuleOutputBase;
					currentRuleOutputBase = currentOutputBase = AllocateBuffer(); // start an independent buffer
					FunctionResult result;
					matching = true;
					ptr = DoFunction(word,ptr,currentOutputBase,result);
					matching = false;
					matched = !(result & ENDCODES); 

					// allowed to do comparisons on answers from system functions but cannot have space before them, but not from user macros
					if (*ptr == '!' && ptr[1] == ' ' ){;} // simple not operator
					else if (ptr[1] == '<' || ptr[1] == '>'){;} // << and >> are not comparison operators in a pattern
					else if (IsComparison(*ptr) && *(ptr-1) != ' ' && (*ptr != '!' || ptr[1] == '='))  // ! w/o = is not a comparison
					{
						char op[10];
						char* opptr = ptr;
						*op = *opptr;
						op[1] = 0;
						char* rhs = ++opptr; 
						if (*opptr == '=') // was == or >= or <= or &= 
						{
							op[1] = '=';
							op[2] = 0;
							++rhs;
						}
						char copy[MAX_WORD_SIZE];
						ptr = ReadCompiledWord(rhs,copy);
						rhs = copy;

						if (*rhs == '^') // local function argument or indirect ^$ var  is LHS. copy across real argument
						{
							char* at = "";
							if (rhs[1] == '$') at = GetUserVariable(rhs+1); 
							else if (IsDigit(rhs[1])) at = callArgumentList[rhs[1]-'0'+fnVarBase];
							at = SkipWhitespace(at);
							strcpy(rhs,at);
						}
				
						if (*op == '?' && opptr[0] != '~')
						{
							bool junk;
							matched = MatchTest(reverse,FindWord(currentOutputBase),
								(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,NULL,NULL,false,junk,
								positionStart,positionEnd); 
							if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
						}
						else
						{
							int id;
							char word1val[MAX_WORD_SIZE];
							char word2val[MAX_WORD_SIZE];
 							result = HandleRelation(currentOutputBase,op,rhs,false,id,word1val,word2val); 
							matched = (result & ENDCODES) ? 0 : 1;
						}
					}
					FreeBuffer();
					currentOutputBase = old;
					currentRuleOutputBase = oldrule;
                }
				else // user function - execute it in pattern context as continuation of current code
				{ 
					if (functionNest >= MAX_PAREN_NEST) // fail, too deep nesting
					{
						matched = false;
						break; 
					}

					//   save old base data
					baseStack[functionNest] = callArgumentBase; 
					argStack[functionNest] = callArgumentIndex; 
					fnVarBaseStack[functionNest] = fnVarBase;

					if ((trace & TRACE_PATTERN || D->internalBits & MACRO_TRACE)  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"((char*)"); 
					ptr += 2; // skip ( and space
					// read arguments
					while (*ptr && *ptr != ')' ) 
					{
						char* arg = callArgumentList[callArgumentIndex++];
						ptr = ReadArgument(ptr,arg);  // gets the unevealed arg
						if ((trace & TRACE_PATTERN || D->internalBits & MACRO_TRACE)  && CheckTopicTrace()) Log(STDUSERLOG,(char*)" %s, ",arg); 
					}
					if ((trace & TRACE_PATTERN || D->internalBits & MACRO_TRACE)  && CheckTopicTrace()) Log(STDUSERLOG,(char*)")\r\n"); 
					fnVarBase = callArgumentBase = argStack[functionNest];
					ptrStack[functionNest++] = ptr+2; // skip closing paren and space
					ptr = (char*) D->w.fndefinition + 1; // continue processing within the macro, skip argument count
					oldecho = echo;
					oldtrace = trace;
					if (D->internalBits & MACRO_TRACE  && CheckTopicTrace()) 
					{
						trace = (unsigned int)-1;
						echo = true;
					}
					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERLOG,(char*)"%s=> ",word);
					continue;
				}
				break;
          case 0: // end of data (argument or function - never a real rule)
	           if (argumentText) // return to normal from argument substitution
                {
                    ptr = argumentText;
                    argumentText = NULL;
                    continue;
                }
                else if (functionNest > startNest) // function call end
                {
 					if (trace & TRACE_PATTERN  && CheckTopicTrace()) Log(STDUSERTABLOG,(char*)""); 
					--functionNest;
                    callArgumentIndex = argStack[functionNest]; //   end of argument list (for next argument set)
                    callArgumentBase = baseStack[functionNest]; //   base of callArgumentList
                    fnVarBase = fnVarBaseStack[functionNest];
					ptr = ptrStack[functionNest]; // continue using prior code
					trace = oldtrace;
                    echo = oldecho;
					continue;
                }
                else 
				{
					ChangeDepth(-1,(char*)"Match");
					globalDepth = startdepth;
 					return false; // shouldn't happen
				}
                break;
DOUBLELEFT:  case '(': case '[':  case '{': // nested condition (required or optional) (= consecutive  [ = choice   { = optional   << all of
				// we make << also a depth token
				ptr = nextTokenStart;
				hold = wildcardIndex;
				{
					if (wildcardSelector & WILDMEMORIZESPECIFIC) 
					{
						pendingMatch = wildcardIndex;	// on match later, use this matchvar 
						SetWildCard(1,1,true); // dummy match
					}

					int oldgap = gap;
					int returnStart = positionStart;
					int returnEnd = positionEnd;
					int rStart = positionStart;
					int rEnd = positionEnd;
					unsigned int oldselect = wildcardSelector;
					wildcardSelector = 0;
					bool uppercasemat = false;
					// nest inherits gaps leading to it. memorization requests withheld til he returns
					int whenmatched = 0;
					char* type = "[";
					if (*word == '(') type = "(";
					else if (*word == '{') type = "{";
					else if (*word == '<') 
					{
						type = "<<";
						positionEnd = startposition;  //   allowed to pick up after here - oldStart/oldEnd synch automatically works
						positionStart = INFINITE_MATCH;
						rEnd = 0;
						rStart = INFINITE_MATCH; 
					}
					matched = Match(ptr,depth+1,positionEnd,type, positionStart == INFINITE_MATCH,gap,wildcardSelector,returnStart,
						returnEnd,uppercasemat,whenmatched,positionStart,positionEnd,reverse); //   subsection ok - it is allowed to set position vars, if ! get used, they dont matter because we fail
					wildcardSelector = oldselect;
					if (matched) 
					{
						if (!(statusBits & NOT_BIT)  && firstMatched < 0) firstMatched = whenmatched;
						positionStart = returnStart;
						if (positionStart == INFINITE_MATCH && returnStart > 0 &&  returnStart != INFINITE_MATCH) positionStart = returnEnd;
						positionEnd = returnEnd;
						if (*word == '<') // allows thereafter to be anywhere
						{
							positionStart = INFINITE_MATCH;
							oldEnd = oldStart = positionEnd = 0;
						}
						if (wildcardSelector) gap = oldgap;	 // to size a gap
						uppercasematch = uppercasemat;
						// The whole thing matched but if @_ was used, which way it ran and what to consider the resulting zone is completely confused.
						// So force a tolerable meaning so it acts like it is contiguous to caller.  If we are memorizing it may be silly but its what we can do.
						if (*word == '(' && positionStart == NORETRY) 
						{
							positionEnd = positionStart = (reverse) ? (oldStart - 1) : (oldEnd + 1) ;  // claim we only moved 1 unit
						}
						else if (positionEnd) oldEnd = (reverse) ? (positionEnd + 1) : (positionEnd - 1); //   nested checked continuity, so we allow match whatever it found - but not if never set it (match didnt have words)
						if (*word == '{') 
						{
							gap = oldgap; // restore any pending gap we didnt plug  (eg *~2 {xx yy zz} a )
						}
					}
					else if (*word == '{') 
					{
						gap = oldgap; // restore any pending gap we didnt plug  (eg *~2 {xx yy zz} a )
					}
					else // no match for ( or [ or << means we have to restore old positions regardless of what happened inside
					{ // but we should check why the positions were not properly restored from the match call...BUG
						positionStart = rStart;
						positionEnd = rEnd;
					}
				}
				ptr = BalanceParen(ptr); // skip over the material including closer 
				if (!matched) // failed, revert wildcard index - if ! was used, we will need this
                {
  				    if (*word == '{') 
                    {
						if (wildcardSelector & WILDMEMORIZESPECIFIC) //   we need to memorize failure because optional cant fail
						{
							wildcardSelector ^= WILDMEMORIZESPECIFIC;
							SetWildCardGiven(0, wordCount,true,pendingMatch); 
						}
						pendingMatch = -1;
                        if (gap) continue;   //   if we are waiting to close a wildcard, ignore our failed existence entirely
                        statusBits |= NOT_BIT; //   we didnt match and pretend we didnt want to
                    }
   					else // failure of [ and ( and <<
					{
						wildcardSelector = 0;
						wildcardIndex = hold;
					}
    				pendingMatch = -1;
				}
                break;
 DOUBLERIGHT: case ')': case ']': case '}' :  //   end sequence/choice/optional

				ptr = nextTokenStart;
				matched = (*kind == '(' || *kind == '<'); //   [] and {} must be failures if we are here while ( ) and << >> are success
				if (gap) //   pending gap  -  [ foo fum * ] and { foo fot * } are pointless but [*3 *2] is not 
                {
					if (depth != 0) // for simplicity don't end with a gap 
					{
						gap = wildcardSelector = 0;
						matched = false; //   force match failure
					}
					else positionStart = wordCount + 1; //   at top level a close implies > )
				}
                break; 
            case '"':  //   double quoted string
				matched = FindPhrase(word,(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd, reverse,
					positionStart,positionEnd);
				if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
				break;
            case '%': //   system variable
				if (!word[1]) // simple % 
				{
					bool junk;
					matched = MatchTest(reverse,FindWord(word),(positionEnd < basicStart && firstMatched < 0) ? basicStart: positionEnd,NULL,NULL,
						statusBits & QUOTE_BIT,junk,positionStart,positionEnd); //   possessive 's
					if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
				}
                else matched = SysVarExists(word);
                break;
            case '?': //  question sentence? 
				ptr = nextTokenStart;
				if (!word[1]) matched = (tokenFlags & QUESTIONMARK) ? true : false;
				else matched = false;
	            break;
            case '=': //   a comparison test - never quotes the left side. Right side could be quoted
				//   format is:  = 1-bytejumpcodeToComparator leftside comparator rightside
				if (!word[1]) //   the simple = being present
				{
					bool junk;
					matched = MatchTest(reverse,FindWord(word),(positionEnd < basicStart && firstMatched < 0)  ? basicStart : positionEnd,NULL,NULL,
						statusBits & QUOTE_BIT,junk,positionStart,positionEnd); //   possessive 's
					if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
				}
				//   if left side is anything but a variable $ or _ or @, it must be found in sentence and that is what we compare against
				else 
				{
					char lhsside[MAX_WORD_SIZE];
					char* lhs = lhsside;
					char op[10];
					char rhsside[MAX_WORD_SIZE];
					char* rhs = rhsside;
					DecodeComparison(word, lhs, op, rhs);
					if (trace) sprintf(word,(char*)"%s%s%s",lhs,op,rhs);
					if (*lhs == '^') DecodeFNRef(lhs); // local function arg indirect ^$ var or _ as LHS
					if (*rhs == '^') DecodeFNRef(rhs);// local function argument or indirect ^$ var  is LHS. copy across real argument
				
					bool quoted = false;
					if (*lhs == '\'') // left side is quoted
					{
						++lhs; 
						quoted = true;
					}
			
					if (*op == '?' && *rhs != '~') // NOT a ? into a set test - means does this thing exist in sentence
					{
						char* val = "";
						if (*lhs == '$') val = GetUserVariable(lhs);
						else if (*lhs == '_') val = (quoted) ? wildcardOriginalText[GetWildcardID(lhs)] : wildcardCanonicalText[GetWildcardID(lhs)];
						else if (*lhs == '^' && IsDigit(lhs[1])) val = callArgumentList[lhs[1]-'0'+fnVarBase];  // nine argument limit
						else if (*lhs == '%') val = SystemVariable(lhs,NULL);
						else val = lhs; // direct word

						if (*val == '"') // phrase requires dynamic matching
						{
							matched = FindPhrase(val,(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd, reverse,
								positionStart,positionEnd);
							if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
							if (trace) sprintf(word,(char*)"%s(%s)%s",lhs,val,op);
							break;
						}

						bool junk;
						matched = MatchTest(reverse,FindWord(val),(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,NULL,NULL,
							quoted,junk,positionStart,positionEnd); 
						if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; //   first SOLID match
						if (trace) sprintf(word,(char*)"%s(%s)%s",lhs,val,op);
						break;
					}
	
					result = *lhs;
					if (result == '%' || result == '$' || result == '_' || result == '@' || (*op == '?' && rhs)) // otherwise for words and concepts, look up in sentence and check relation there
					{
						if (result == '_' && quoted) --lhs; // include the quote
						char word1val[MAX_WORD_SIZE];
						char word2val[MAX_WORD_SIZE];
						FunctionResult answer = HandleRelation(lhs,op,rhs,false,id,word1val,word2val); 
						matched = (answer & ENDCODES) ? 0 : 1;
						if (trace) 
						{
							if (!stricmp(lhs,word1val)) *word1val = 0; // dont need redundant constants in trace
							if (!stricmp(rhs,word2val)) *word2val = 0; // dont need redundant constants in trace
							if (*word1val && *word2val) sprintf(word,(char*)"%s(%s)%s%s(%s)",lhs,word1val,op,rhs,word2val);
							else if (*word1val) sprintf(word,(char*)"%s(%s)%s%s",lhs,word1val,op,rhs);
							else if (*word2val) sprintf(word,(char*)"%s%s%s(%s)",lhs,op,rhs,word2val);
							else sprintf(word,(char*)"%s%s%s",lhs,op,rhs);
						}
					}
					else // find and test
					{
						bool junk;
						matched = MatchTest(reverse,FindWord(lhs),(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,op,rhs,
							quoted,junk,positionStart,positionEnd); //   MUST match later 
						if (!matched) break;
					}
 				}
				break;
            case '\\': //   escape to allow [ ] () < > ' {  } ! as words and 's possessive And anything else for that matter
				{
					bool junk;
					matched =  MatchTest(reverse,FindWord(word+1),(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,NULL,NULL,
						statusBits & QUOTE_BIT,junk,positionStart,positionEnd);
					if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart; 
					if (matched) {}
					else if (word[1] == '!' ) matched =  (wordCount && (tokenFlags & EXCLAMATIONMARK)); //   exclamatory sentence
  					else if (word[1] == '?') matched =  (tokenFlags & QUESTIONMARK) ? true : false; //   question sentence
					break;
				}
			case '~': // current topic ~ and named topic
				if (word[1] == 0) // current topic
				{
					matched = IsCurrentTopic(currentTopicID); // clearly we are executing rules from it but is the current topic interesting
					break;
				}
				// drop thru for all other ~
			default: //   ordinary words, concept/topic, numbers, : and ~ and | and & accelerator
				matched = MatchTest(reverse,FindWord(word),(positionEnd < basicStart && firstMatched < 0) ? basicStart : positionEnd,NULL,NULL,
					statusBits & QUOTE_BIT,uppercasematch,positionStart,positionEnd);
				if (!matched || !(wildcardSelector & WILDMEMORIZESPECIFIC)) uppercasematch = false;
				if (!(statusBits & NOT_BIT) && matched && firstMatched < 0) firstMatched = positionStart;
         } 
Beispiel #11
0
// ReadArrayOfStruct
//------------------------------------------------------------------------------
bool TextReader::ReadArrayOfStruct()
{
    // element type
    AStackString<> elementType;
    if ( !GetToken( elementType ) )
    {
        Error( "Missing array element type" );
        return false;
    }

    // close array >
    SkipWhitespace();
    if ( *m_Pos != '>' )
    {
        Error( "Missing array close token >" );
        return false;
    }
    m_Pos++;

    // property name
    AStackString<> name;
    if ( !GetToken( name ) )
    {
        Error( "Missing array property name" );
        return false;
    }

    // Get Array ReflectedProperty
    const StackFrame & sf = m_DeserializationStack.Top();
    const ReflectedProperty * rp = sf.m_Reflection->GetReflectedProperty( name );
    if ( !rp )
    {
        Error( "missing array" ); // TODO: This should be handled gracefully (skip)
        return false;
    }
    if ( rp->IsArray() == false )
    {
        Error( "property is not an array" ); // TODO: This should be handled gracefully (skip)
        return false;
    }
    if ( rp->GetType() != PT_STRUCT )
    {
        Error( "property is not an arrayOfStruct" ); // TODO: This should be handled gracefully (skip)
        return false;
    }

    const ReflectedPropertyStruct * rps = static_cast< const ReflectedPropertyStruct * >( rp );
    if ( elementType != rps->GetStructReflectionInfo()->GetTypeName() )
    {
        Error( "mismatched struct type in arrayOfStruct" ); // TODO: This should be handled gracefully (skip)
        return false;
    }

    // clear the array (it will be re-populated)
    rps->ResizeArrayOfStruct( sf.m_Base, 0 );

    StackFrame newSF;
    newSF.m_Base = sf.m_Base;
    newSF.m_Reflection = sf.m_Reflection;
    newSF.m_ArrayProperty = rps;
    #ifdef DEBUG
        newSF.m_RefObject = nullptr;
        newSF.m_Struct = nullptr;
    #endif
    m_DeserializationStack.Append( newSF );

    return true;
}
Beispiel #12
0
const ezTokenizer* ezTokenizedFileCache::Tokenize(const ezString& sFileName, const ezDynamicArray<ezUInt8>& FileContent, const ezTimestamp& FileTimeStamp, ezLogInterface* pLog)
{
  EZ_LOCK(m_Mutex);

  auto& data = m_Cache[sFileName];

  data.m_Timestamp = FileTimeStamp;
  ezTokenizer* pTokenizer = &data.m_Tokens;
  pTokenizer->Tokenize(FileContent, pLog);

  ezDeque<ezToken>& Tokens = pTokenizer->GetTokens();

  ezHashedString sFile;
  sFile.Assign(sFileName.GetData());

  ezInt32 iLineOffset = 0;

  for (ezUInt32 i = 0; i + 1 < Tokens.GetCount(); ++i)
  {
    const ezUInt32 uiCurLine = Tokens[i].m_uiLine;

    Tokens[i].m_File = sFile;
    Tokens[i].m_uiLine += iLineOffset;

    if (Tokens[i].m_iType == ezTokenType::NonIdentifier &&
        ezString(Tokens[i].m_DataView) == "#")
    {
      ezUInt32 uiNext = i + 1;

      SkipWhitespace(Tokens, uiNext);

      if (uiNext < Tokens.GetCount() && 
          Tokens[uiNext].m_iType == ezTokenType::Identifier &&
          ezString(Tokens[uiNext].m_DataView) == "line")
      {
        ++uiNext;
        SkipWhitespace(Tokens, uiNext);

        if (uiNext < Tokens.GetCount() && 
            Tokens[uiNext].m_iType == ezTokenType::Identifier)
        {
          ezInt32 iNextLine = 0;

          const ezString sNumber = Tokens[uiNext].m_DataView;
          if (ezConversionUtils::StringToInt(sNumber.GetData(), iNextLine).Succeeded())
          {
            iLineOffset = (iNextLine - uiCurLine) - 1;

            ++uiNext;
            SkipWhitespace(Tokens, uiNext);

            if (uiNext < Tokens.GetCount())
            {
              if (Tokens[uiNext].m_iType == ezTokenType::String1)
              {
                ezStringBuilder sFileName = Tokens[uiNext].m_DataView;
                sFileName.Shrink(1, 1); // remove surrounding "

                sFile.Assign(sFileName.GetData());
              }
            }
          }
        }
      }
    }
  }

  return pTokenizer;
}
Beispiel #13
0
ezResult ezPreprocessor::HandleInclude(const TokenStream& Tokens, ezUInt32 uiCurToken, ezUInt32 uiDirectiveToken, TokenStream& TokenOutput)
{
  EZ_ASSERT_DEV(m_FileLocatorCallback.IsValid(), "File locator callback has not been set");

  SkipWhitespace(Tokens, uiCurToken);

  ezStringBuilder sPath;

  IncludeType IncType = IncludeType::GlobalInclude;

  ezUInt32 uiAccepted;
  if (Accept(Tokens, uiCurToken, ezTokenType::String1, &uiAccepted))
  {
    IncType = IncludeType::RelativeInclude;
    sPath = Tokens[uiAccepted]->m_DataView;
    sPath.Shrink(1, 1); // remove " at start and end
  }
  else
  {
    // in global include paths (ie. <bla/blub.h>) we need to handle line comments special
    // because a path with two slashes will be a comment token, although it could be a valid path
    // so we concatenate just everything and then make sure it ends with a >

    if (Expect(Tokens, uiCurToken, "<", &uiAccepted).Failed())
      return EZ_FAILURE;

    TokenStream PathTokens;

    while (uiCurToken < Tokens.GetCount())
    {
      if (Tokens[uiCurToken]->m_iType == ezTokenType::Newline)
      {
        ++uiCurToken;
        continue;
      }

      PathTokens.PushBack(Tokens[uiCurToken]);
      ++uiCurToken;
    }

    CombineTokensToString(PathTokens, 0, sPath);

    // remove all whitespace at the end (this could be part of a comment, so not tokenized as whitespace)
    while (sPath.EndsWith(" ") || sPath.EndsWith("\t"))
      sPath.Shrink(0, 1);

    // there must always be a > at the end, although it could be a separate token or part of a comment
    // so we check the string, instead of the tokens
    if (sPath.EndsWith(">"))
      sPath.Shrink(0, 1);
    else
    {
      PP_LOG(Error, "Invalid include path '%s'", Tokens[uiAccepted], sPath.GetData());
      return EZ_FAILURE;
    }
  }

  if (ExpectEndOfLine(Tokens, uiCurToken).Failed())
  {
    PP_LOG0(Error, "Expected end-of-line", Tokens[uiCurToken]);
    return EZ_FAILURE;
  }

  EZ_ASSERT_DEV(!m_sCurrentFileStack.IsEmpty(), "Implementation error.");

  ezString sOtherFile;

  if (m_FileLocatorCallback(m_sCurrentFileStack.PeekBack().m_sFileName.GetData(), sPath.GetData(), IncType, sOtherFile).Failed())
  {
    PP_LOG(Error, "#include file '%s' could not be located", Tokens[uiAccepted], sPath.GetData());
    return EZ_FAILURE;
  }

  // if this has been included before, and contains a #pragma once, do not include it again
  if (m_PragmaOnce.Find(sOtherFile.GetData()).IsValid())
    return EZ_SUCCESS;

  if (ProcessFile(sOtherFile.GetData(), TokenOutput).Failed())
    return EZ_FAILURE;

  if (uiCurToken < Tokens.GetCount() && (Tokens[uiCurToken]->m_iType == ezTokenType::Newline || Tokens[uiCurToken]->m_iType == ezTokenType::EndOfFile))
    TokenOutput.PushBack(Tokens[uiCurToken]);

  return EZ_SUCCESS;
}
Beispiel #14
0
FarXMLNode *FarXMLScanner::ParseChildNode()
{
    SkipWhitespace();

  int tagStartLine = fCurLine;
  int tagStartCol = GetCurColumn();
  if (!NextExpectedChar ('<'))
    return NULL;

  FarString tagName = NextName();
    if (tagName.IsEmpty())
    return NULL;

    FarXMLNode *theNode = new FarXMLNode();
  theNode->SetTag (tagName);
  theNode->SetStartPosition (tagStartLine, tagStartCol);

  while (1)
  {
    SkipWhitespace();
    char c = PeekNextChar();
    if (c == '/')
    {
      NextChar();
      if (!NextExpectedChar ('>'))
      {
        delete theNode;
        return NULL;
      }
      break;
    }
    else if (c == '>')
    {
      NextChar();
      SkipWhitespace();
      while (1)
      {
        if (PeekNextChar() == '<' && PeekNextChar (1) == '/')
          break;
        FarXMLNode *nextChild = ParseChildNode();
        if (!nextChild)
        {
          delete theNode;
          return NULL;
        }
        theNode->AddChild (nextChild);
        SkipWhitespace();
      }
      NextChar(); // <
      NextChar(); // /
      FarString closeTagName = NextName();
      if (closeTagName != tagName)
      {
        ReportError (tagName);
        delete theNode;
        return NULL;
      }
      SkipWhitespace();
      if (!NextExpectedChar ('>'))
      {
        delete theNode;
        return NULL;
      }
      break;
    }
    else
    {
      if (!ParseAttribute (theNode))
      {
        delete theNode;
        return NULL;
      }
    }
  }
  theNode->SetEndPosition (fCurLine, GetCurColumn());
  SkipWhitespace();

  return theNode;
}
/**
 * Parses a text buffer into an object reference.
 *
 * @param	Property			the property that the value is being importing to
 * @param	OwnerObject			the object that is importing the value; used for determining search scope.
 * @param	RequiredMetaClass	the meta-class for the object to find; if the object that is resolved is not of this class type, the result is NULL.
 * @param	PortFlags			bitmask of EPropertyPortFlags that can modify the behavior of the search
 * @param	Buffer				the text to parse; should point to a textual representation of an object reference.  Can be just the object name (either fully 
 *								fully qualified or not), or can be formatted as a const object reference (i.e. SomeClass'SomePackage.TheObject')
 *								When the function returns, Buffer will be pointing to the first character after the object value text in the input stream.
 * @param	ResolvedValue		receives the object that is resolved from the input text.
 *
 * @return	true if the text is successfully resolved into a valid object reference of the correct type, false otherwise.
 */
bool UObjectPropertyBase::ParseObjectPropertyValue( const UProperty* Property, UObject* OwnerObject, UClass* RequiredMetaClass, uint32 PortFlags, const TCHAR*& Buffer, UObject*& out_ResolvedValue )
{
	check(Property);
	if (!RequiredMetaClass)
	{
		UE_LOG(LogProperty, Error, TEXT("ParseObjectPropertyValue Error: RequiredMetaClass is null, for property: %s "), *Property->GetFullName());
		out_ResolvedValue = nullptr;
		return false;
	}

 	const TCHAR* InBuffer = Buffer;

	FString Temp;
	Buffer = UPropertyHelpers::ReadToken(Buffer, Temp, true);
	if ( Buffer == NULL )
	{
		return false;
	}

	if ( Temp == TEXT("None") )
	{
		out_ResolvedValue = NULL;
	}
	else
	{
		UClass*	ObjectClass = RequiredMetaClass;

		SkipWhitespace(Buffer);

		bool bWarnOnNULL = (PortFlags&PPF_CheckReferences)!=0;

		if( *Buffer == TCHAR('\'') )
		{
			FString ObjectText;
			Buffer = UPropertyHelpers::ReadToken( ++Buffer, ObjectText, true );
			if( Buffer == NULL )
			{
				return false;
			}

			if( *Buffer++ != TCHAR('\'') )
			{
				return false;
			}

			// ignore the object class, it isn't fully qualified, and searching ANY_PACKAGE might get the wrong one!
			// Try the find the object.
			out_ResolvedValue = UObjectPropertyBase::FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, *ObjectText, PortFlags);
		}
		else
		{
			// Try the find the object.
			out_ResolvedValue = UObjectPropertyBase::FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, *Temp, PortFlags);
		}

		if ( out_ResolvedValue != NULL && !out_ResolvedValue->GetClass()->IsChildOf(RequiredMetaClass) )
		{
			if (bWarnOnNULL )
			{
				UE_LOG(LogProperty, Error, TEXT("%s: bad cast in '%s'"), *Property->GetFullName(), InBuffer );
			}

			out_ResolvedValue = NULL;
			return false;
		}

		// If we couldn't find it or load it, we'll have to do without it.
		if ( out_ResolvedValue == NULL )
		{
			if( bWarnOnNULL )
			{
				UE_LOG(LogProperty, Warning, TEXT("%s: unresolved reference to '%s'"), *Property->GetFullName(), InBuffer );
			}
			return false;
		}
	}

	return true;
}
Beispiel #16
0
const TCHAR* UArrayProperty::ImportText_Internal( const TCHAR* Buffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText ) const
{
	checkSlow(Inner);

	FScriptArrayHelper ArrayHelper(this, Data);

	// If we export an empty array we export an empty string, so ensure that if we're passed an empty string
	// we interpret it as an empty array.
	if ( *Buffer == TCHAR('\0') )
	{
		ArrayHelper.EmptyValues();
		return NULL;
	}

	if ( *Buffer++ != TCHAR('(') )
	{
		return NULL;
	}

	ArrayHelper.EmptyValues();

	SkipWhitespace(Buffer);

	int32 Index = 0;

	const bool bEmptyArray = *Buffer == TCHAR(')');
	if (!bEmptyArray)
	{
		ArrayHelper.ExpandForIndex(0);
	}
	while ((Buffer != NULL) && (*Buffer != TCHAR(')')))
	{
		SkipWhitespace(Buffer);

		if (*Buffer != TCHAR(','))
		{
			// Parse the item
			Buffer = Inner->ImportText(Buffer, ArrayHelper.GetRawPtr(Index), PortFlags | PPF_Delimited, Parent, ErrorText);

			if(!Buffer)
			{
				return NULL;
			}

			SkipWhitespace(Buffer);
		}


		if (*Buffer == TCHAR(','))
		{
			Buffer++;
			Index++;
			ArrayHelper.ExpandForIndex(Index);
		}
		else
		{
			break;
		}
	}

	// Make sure we ended on a )
	CA_SUPPRESS(6011)
	if (*Buffer++ != TCHAR(')'))
	{
		return NULL;
	}

	return Buffer;
}
Beispiel #17
0
/*
   ==============
   Com_ParseExt

   Parse a token out of a string
   Will never return NULL, just empty strings.
   An empty string will only be returned at end of file.

   If "allowLineBreaks" is qtrue then an empty
   string will be returned if the next token is
   a newline.
   ==============
 */
static char *Com_ParseExt( const char *( *data_p ), qboolean allowLineBreaks ) {
	int c = 0, len;
	qboolean hasNewLines = qfalse;
	const char *data;
	const char **punc;

	if ( !data_p ) {
		Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" );
	}

	data = *data_p;
	len = 0;
	pi->token[0] = 0;

	// make sure incoming data is valid
	if ( !data ) {
		*data_p = NULL;
		return pi->token;
	}

	// skip any leading whitespace
	while ( 1 ) {
		// skip whitespace
		data = SkipWhitespace( data, &hasNewLines );
		if ( !data ) {
			*data_p = NULL;
			return pi->token;
		}
		if ( hasNewLines && !allowLineBreaks ) {
			*data_p = data;
			return pi->token;
		}

		c = *data;

		// skip double slash comments
		if ( c == '/' && data[1] == '/' ) {
			while ( *data && *data != '\n' ) {
				data++;
			}
			continue;
		}

		// skip /* */ comments
		if ( c == '/' && data[1] == '*' ) {
			while ( *data && ( *data != '*' || data[1] != '/' ) ) {
				if ( *data == '\n' ) {
					pi->lines++;
				}
				data++;
			}
			if ( *data ) {
				data += 2;
			}
			continue;
		}

		// a real token to parse
		break;
	}

	// handle quoted strings
	if ( c == '\"' ) {
		data++;
		while ( 1 ) {
			c = *data++;
			if ( ( c == '\\' ) && ( *data == '\"' ) ) {
				// allow quoted strings to use \" to indicate the " character
				data++;
			}
			else if ( c == '\"' || !c ) {
				pi->token[len] = 0;
				*data_p = ( char * ) data;
				return pi->token;
			}
			else if ( *data == '\n' ) {
				pi->lines++;
			}
			if ( len < MAX_TOKEN_CHARS - 1 ) {
				pi->token[len] = c;
				len++;
			}
		}
	}

	// check for a number
	// is this parsing of negative numbers going to cause expression problems
	if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ||
		 ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) {
		do  {

			if ( len < MAX_TOKEN_CHARS - 1 ) {
				pi->token[len] = c;
				len++;
			}
			data++;

			c = *data;
		} while ( ( c >= '0' && c <= '9' ) || c == '.' );

		// parse the exponent
		if ( c == 'e' || c == 'E' ) {
			if ( len < MAX_TOKEN_CHARS - 1 ) {
				pi->token[len] = c;
				len++;
			}
			data++;
			c = *data;

			if ( c == '-' || c == '+' ) {
				if ( len < MAX_TOKEN_CHARS - 1 ) {
					pi->token[len] = c;
					len++;
				}
				data++;
				c = *data;
			}

			do  {
				if ( len < MAX_TOKEN_CHARS - 1 ) {
					pi->token[len] = c;
					len++;
				}
				data++;

				c = *data;
			} while ( c >= '0' && c <= '9' );
		}

		if ( len == MAX_TOKEN_CHARS ) {
			len = 0;
		}
		pi->token[len] = 0;

		*data_p = ( char * ) data;
		return pi->token;
	}

	// check for a regular word
	// we still allow forward and back slashes in name tokens for pathnames
	// and also colons for drive letters
	if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) {
		do  {
			if ( len < MAX_TOKEN_CHARS - 1 ) {
				pi->token[len] = c;
				len++;
			}
			data++;

			c = *data;
		} while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_'
				  || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' );

		if ( len == MAX_TOKEN_CHARS ) {
			len = 0;
		}
		pi->token[len] = 0;

		*data_p = ( char * ) data;
		return pi->token;
	}

	// check for multi-character punctuation token
	for ( punc = punctuation ; *punc ; punc++ ) {
		int l;
		int j;

		l = strlen( *punc );
		for ( j = 0 ; j < l ; j++ ) {
			if ( data[j] != ( *punc )[j] ) {
				break;
			}
		}
		if ( j == l ) {
			// a valid multi-character punctuation
			memcpy( pi->token, *punc, l );
			pi->token[l] = 0;
			data += l;
			*data_p = (char *)data;
			return pi->token;
		}
	}

	// single character punctuation
	pi->token[0] = *data;
	pi->token[1] = 0;
	data++;
	*data_p = (char *)data;

	return pi->token;
}
Beispiel #18
0
static bool ParseXml(ParserState *state)
{
    Vec<XmlNestingInfo> stack;
    int parentIdx = -1;
    char *s = state->curr;
    for (;;)
    {
        XmlTagInfo tagInfo;
        SkipWhitespace(s);
        if (!*s) {
            if (parentIdx != -1)
                return false;
            if (stack.Count() > 0)
                return false;
            return true;
        }

        if (*s != '<')
            return false;
        s++;

        bool skipped;
        if (!SkipCommentOrProcesingInstr(s, skipped))
            return false;
        if (skipped)
            continue;

        if (!ParseTag(s, tagInfo))
            return false;

        if (TAG_CLOSE == tagInfo.type) {
            if (0 == stack.Count())
                return false;
            size_t pos = stack.Count() - 1;
            XmlNestingInfo ni = stack.At(pos);
            stack.RemoveAt(pos);
            if (!str::Eq(ni.name, tagInfo.name))
                return false;
            parentIdx = -1;
            if (stack.Count() > 0) {
                ni = stack.At(stack.Count() - 1);
                parentIdx = ni.nodeIdx;
            }
            continue;
        }

        int nodeIdx;
        MarkupNode *node = state->AllocNode(nodeIdx, parentIdx);
        node->name = tagInfo.name;
        node->attributes = tagInfo.attributes;
        node->user = NULL;

        state->cb->NewNode(node);

        if (TAG_OPEN == tagInfo.type) {
            XmlNestingInfo ni;
            ni.name = tagInfo.name;
            ni.nodeIdx = nodeIdx;
            stack.Push(ni);
            parentIdx = nodeIdx;
        }

    }
}
VOID CALLBACK TimeCheck( HWND hwnd, UINT uMsg,UINT_PTR idEvent,DWORD dwTime) // every 100 ms
{
	char c;
	static bool init = false;
	static int inputCount = 0;
	if (!init)
	{
		init = true;
	//	char word[MAX_WORD_SIZE];
	//	GetCurrentDir(word, MAX_WORD_SIZE);
		InitChatbot(computerName);
		RECT rect;
		GetClientRect(hwnd, &rect);
		InvalidateRect(hwnd, &rect, TRUE);
		strcpy(response,"Chatbot initialization complete");
	}

	static int counter = 0;
	++counter; // increament each timer interrupt, tracking how long since last key input from user
	static char lastchar = 0;
	static bool keyhit = false;
	while ((c = ReadChar())) // returns 0 if nothing found
	{
		keyhit = true; // user input seen since last output
		RECT rect;
		GetClientRect(hwnd, &rect);
		InvalidateRect(hwnd, &rect, TRUE);
		if ( c == 8) // backspace
		{
			if ( msgPtr != inputMessage) *--msgPtr = 0;
		}
		else if ( c == '\n' || c == '\r') // prepare for NEW input and get response
		{
			if (msgPtr == inputMessage) continue;	// ignore empty lines
			*msgPtr = 0;
			counter = 100;	// treat as end of input
			break;	// dont read until we have responded
		}
		else if (msgPtr == inputMessage && (c == ' ' || c == '\t' )) continue;	// ignore leading whitespace.
		else // accept new character
		{
			*msgPtr++ = c;
			lastchar = c;
			*msgPtr = 0;
		}
		counter = 0; // start time wait over again
	}

	// do we have something we want to respond to?
	bool trigger = false;
	if (counter >= 30 && *inputMessage && (lastchar == '.' || lastchar == '?' || lastchar == '!')) trigger = true; // 3 sec passed and have input ended on closer 
	else if (counter >= 70 && *inputMessage) trigger = true; // 7 seconds + have lingering input
	// or timer oob goes off
	char oob[MAX_WORD_SIZE];
	*oob = 0;
	ProcessInputDelays(oob,keyhit); 

	if (trigger || *oob)
	{
		if (*oob) strcpy(ourMainInputBuffer,oob); // priority is to alarm callback. others will be only if no user input anyway
		else  
		{
			strcpy(ourMainInputBuffer,inputMessage);
			// clear all signs of user input
			lastchar = 0;	
			*inputMessage = 0;
			msgPtr = inputMessage;
			keyhit = false;
		}

		PerformChat(loginID,computerID,ourMainInputBuffer,NULL,ourMainOutputBuffer);
		strcpy(response,ourMainOutputBuffer);
		callBackDelay = 0; // now turned off after an output
		ProcessOOB(ourMainOutputBuffer); // process relevant out of band messaging and remove

		char word[MAX_WORD_SIZE];
		char* p = SkipWhitespace(ourMainOutputBuffer);
		ReadCompiledWord(p,word);
		if (!*word) strcpy(p,"huh?"); // in case we fail to generate output

		// transmit message to user
		++inputCount;
		while (*p) 
		{
			if (SendChar(*p,p[1],inputCount)) p++; // got sent
		}
		SendChar('\n',0,inputCount);
		if (loopBackDelay) loopBackTime = ElapsedMilliseconds() + loopBackDelay; // resets every output

		// write out last sequence id
		FILE* out = fopen("sequence", "wb");
		fprintf(out,"%d",sequence);
		fclose(out);

		counter = 0;
		RECT rect;
		GetClientRect(hwnd, &rect);
		InvalidateRect(hwnd, &rect, TRUE);
	}
}
Beispiel #20
0
// native sscanf(const data[], const format[], (Float,_}:...);
static cell AMX_NATIVE_CALL
	n_sscanf(AMX * amx, cell * params)
{
	if (g_iTrueMax == 0)
	{
		logprintf("sscanf error: System not initialised.");
		return SSCANF_FAIL_RETURN;
	}
	// Friendly note, the most complex set of specifier additions is:
	// 
	//  A<i>(10, 11)[5]
	// 
	// In that exact order - type, default, size.  It's very opposite to how
	// it's done in code, where you would do the eqivalent to:
	// 
	//  <i>[5] = {10, 11}
	// 
	// But this method is vastly simpler to parse in this context!  Technically
	// you can, due to legacy support for 'p', do:
	// 
	//  Ai(10, 11)[5]
	// 
	// But you will get an sscanf warning, and I may remove that ability from
	// the start - that will mean a new function, but an easy to write one.
	// In fact the most complex will probably be something like:
	// 
	//  E<ifs[32]s[8]d>(10, 12.3, Hello there, Hi, 42)
	// 
	// Get the number of parameters passed.  We add one as the indexes are out
	// by one (OBOE - Out By One Error) due to params[0] being the parameter
	// count, not an actual parameter.
	const int
		paramCount = ((int)params[0] / 4) + 1;
	// Could add a check for only 3 parameters here - I can't think of a time
	// when you would not want any return values at all, but that doesn't mean
	// they don't exist - you could just want to check but not save the format.
	// Update - that is now a possibility with the '{...}' specifiers.
	if (paramCount < (2 + 1))
	{
		logprintf("sscanf error: Missing required parameters.");
		return SSCANF_FAIL_RETURN;
	}
	//else if (paramCount == (2 + 1))
	//{
		// Only have an input and a specifier - better hope the whole specifier
		// is quite (i.e. enclosed in '{...}').
	//}
	// Set up function wide values.
	// Get and check the main data.
	// Pointer to the current input data.
	char *
		string;
	STR_PARAM(amx, params[1], string);
	// Pointer to the current format specifier.
	char *
		format;
	STR_PARAM(amx, params[2], format);
	// Check for CallRemoteFunction style null strings and correct.
	if (string[0] == '\1' && string[1] == '\0')
	{
		string[0] = '\0';
	}
	// Current parameter to save data to.
	int
		paramPos = 3;
	cell *
		cptr;
	InitialiseDelimiter();
	// Skip leading space.
	SkipWhitespace(&string);
	bool
		doSave;
	// Code for the rare cases where the WHOLE format is quiet.
	if (*format == '{')
	{
		++format;
		doSave = false;
	}
	else
	{
		doSave = true;
	}
	// Now do the main loop as long as there are variables to store the data in
	// and input string remaining to get the data from.
	while (*string && (paramPos < paramCount || !doSave))
	{
		if (!*format)
		{
			// End of the format string - if we're here we've got all the
			// parameters but there is extra string or variables, which may
			// indicate their code needs fixing, for example:
			// sscanf(data, "ii", var0, var1, var3, var4);
			// There is only two format specifiers, but four returns.  This may
			// also be reached if there is too much input data, but that is
			// considered OK as that is likely a user's fault.
			if (paramPos < paramCount)
			{
				logprintf("sscanf warning: Format specifier does not match parameter count.");
			}
			if (!doSave)
			{
				// Started a quiet section but never explicitly ended it.
				logprintf("sscanf warning: Unclosed quiet section.");
			}
			return SSCANF_TRUE_RETURN;
		}
		else if (IsWhitespace(*format))
		{
			++format;
		}
		else
		{
			switch (*format++)
			{
				case 'L':
					DX(bool, L)
					// FALLTHROUGH
				case 'l':
					DOV(bool, L)
					break;
				case 'B':
					DX(int, B)
					// FALLTHROUGH
				case 'b':
					DO(int, B)
				case 'N':
					DX(int, N)
					// FALLTHROUGH
				case 'n':
					DO(int, N)
				case 'C':
					DX(char, C)
					// FALLTHROUGH
				case 'c':
					DO(char, C)
				case 'I':
				case 'D':
					DX(int, I)
					// FALLTHROUGH
				case 'i':
				case 'd':
					DO(int, I)
				case 'H':
				case 'X':
					DX(int, H)
					// FALLTHROUGH
				case 'h':
				case 'x':
					DO(int, H)
				case 'O':
					DX(int, O)
					// FALLTHROUGH
				case 'o':
					DO(int, O)
				case 'F':
					DXF(double, F)
					// FALLTHROUGH
				case 'f':
					DOF(double, F)
				case 'G':
					DXF(double, G)
					// FALLTHROUGH
				case 'g':
					DOF(double, G)
				case '{':
					if (doSave)
					{
						doSave = false;
					}
					else
					{
						// Already in a quiet section.
						logprintf("sscanf warning: Can't have nestled quiet sections.");
					}
					continue;
				case '}':
					if (doSave)
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else
					{
						doSave = true;
					}
					continue;
				case 'P':
					logprintf("sscanf warning: You can't have an optional delimiter.");
					// FALLTHROUGH
				case 'p':
					// 'P' doesn't exist.
					// Theoretically, for compatibility, this should be:
					// p<delimiter>, but that will break backwards
					// compatibility with anyone doing "p<" to use '<' as a
					// delimiter (doesn't matter how rare that may be).  Also,
					// writing deprecation code and both the new and old code
					// is more trouble than it's worth, and it's slow.
					// UPDATE: I wrote the "GetSingleType" code for 'a' and
					// figured out a way to support legacy and new code, while
					// still maintaining support for the legacy "p<" separator,
					// so here it is:
					ResetDelimiter();
					AddDelimiter(GetSingleType(&format));
					continue;
				case 'Z':
					logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
					// FALLTHROUGH
				case 'z':
					logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
					// FALLTHROUGH
				case 'S':
					if (IsDelimiter(*string))
					{
						char *
							dest;
						int
							length;
						if (DoSD(&format, &dest, &length))
						{
							// Send the string to PAWN.
							if (doSave)
							{
								amx_GetAddr(amx, params[paramPos++], &cptr);
								amx_SetString(cptr, dest, 0, 0, length);
							}
						}
						break;
					}
					// Implicit "else".
					SkipDefaultEx(&format);
					// FALLTHROUGH
				case 's':
					{
						// Get the length.
						int
							length = GetLength(&format, false);
						char *
							dest;
						DoS(&string, &dest, length, IsEnd(*format));
						// Send the string to PAWN.
						if (doSave)
						{
							amx_GetAddr(amx, params[paramPos++], &cptr);
							amx_SetString(cptr, dest, 0, 0, length);
						}
					}
					break;
				case 'U':
					DX(int, U)
					// FALLTHROUGH
				case 'u':
					DOV(int, U)
					break;
				case 'Q':
					DX(int, Q)
					// FALLTHROUGH
				case 'q':
					DOV(int, Q)
					break;
				case 'R':
					DX(int, R)
					// FALLTHROUGH
				case 'r':
					DOV(int, R)
					break;
				case 'A':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoA(&format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'a':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoA(&format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'E':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoE(&format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'e':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoE(&format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'K':
					// We need the default values here.
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, &string, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoK(amx, &format, &string, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'k':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, &string, cptr, false))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						if (DoK(amx, &format, &string, NULL, false))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case '\'':
					// Find the end of the literal.
					{
						char
							* str = format,
							* write = format;
						bool
							escape = false;
						while (!IsEnd(*str) && (escape || *str != '\''))
						{
							if (*str == '\\')
							{
								if (escape)
								{
									// "\\" - Go back a step to write this
									// character over the last character (which
									// just happens to be the same character).
									--write;
								}
								escape = !escape;
							}
							else
							{
								if (*str == '\'')
								{
									// Overwrite the escape character with the
									// quote character.  Must have been
									// preceeded by a slash or it wouldn't have
									// got to here in the loop.
									--write;
								}
								escape = false;
							}
							// Copy the string over itself to get rid of excess
							// escape characters.
							// Not sure if it's faster in the average case to
							// always do the copy or check if it's needed.
							// This write is always safe as it makes the string
							// shorter, so we'll never run out of space.  It
							// will also not overwrite the original string.
							*write++ = *str++;
						}
						if (*str == '\'')
						{
							// Correct end.  Make a shorter string to search
							// for.
							*write = '\0';
							// Find the current section of format in string.
							char *
								find = strstr(string, format);
							if (!find)
							{
								// Didn't find the string
								return SSCANF_FAIL_RETURN;
							}
							// Found the string.  Update the current string
							// position to the length of the search term
							// further along from the start of the term.  Use
							// "write" here as we want the escaped string
							// length.
							string = find + (write - format);
							// Move to after the end of the search string.  Use
							// "str" here as we want the unescaped string
							// length.
							format = str + 1;
						}
						else
						{
							logprintf("sscanf warning: Unclosed string literal.");
							char *
								find = strstr(string, format);
							if (!find)
							{
								return SSCANF_FAIL_RETURN;
							}
							string = find + (write - format);
							format = str;
						}
					}
					break;
				case '%':
					logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
					continue;
				default:
					logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
					continue;
			}
			// Loop cleanup - only skip one spacer so that we can detect
			// multiple explicit delimiters in a row, for example:
			// 
			// hi     there
			// 
			// is NOT multiple explicit delimiters in a row (they're
			// whitespace).  This however is:
			// 
			// hi , , , there
			// 
			SkipOneSpacer(&string);
		}
	}
	// Temporary to the end of the code.
	ResetDelimiter();
	AddDelimiter(')');
	// We don't need code here to handle the case where paramPos was reached,
	// but the end of the string wasn't - if that's the case there's no
	// problem as we just ignore excess string data.
	while (paramPos < paramCount || !doSave)
	{
		// Loop through if there's still parameters remaining.
		if (!*format)
		{
			logprintf("sscanf warning: Format specifier does not match parameter count.");
			if (!doSave)
			{
				// Started a quiet section but never explicitly ended it.
				logprintf("sscanf warning: Unclosed quiet section.");
			}
			return SSCANF_TRUE_RETURN;
		}
		else if (IsWhitespace(*format))
		{
			++format;
		}
		else
		{
			// Do the main switch again.
			switch (*format++)
			{
				case 'L':
					DE(bool, L)
				case 'B':
					DE(int, B)
				case 'N':
					DE(int, N)
				case 'C':
					DE(char, C)
				case 'I':
				case 'D':
					DE(int, I)
				case 'H':
				case 'X':
					DE(int, H)
				case 'O':
					DE(int, O)
				case 'F':
					DEF(double, F)
				case 'G':
					DEF(double, G)
				case 'U':
					DE(int, U)
				case 'Q':
					DE(int, Q)
				case 'R':
					DE(int, R)
				case 'A':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoA(&format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoA(&format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'E':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoE(&format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoE(&format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case 'K':
					if (doSave)
					{
						amx_GetAddr(amx, params[paramPos++], &cptr);
						if (DoK(amx, &format, NULL, cptr, true))
						{
							break;
						}
					}
					else
					{
						// Pass a NULL pointer so data isn't saved anywhere.
						// Also pass NULL data so it knows to only collect the
						// default values.
						if (DoK(amx, &format, NULL, NULL, true))
						{
							break;
						}
					}
					return SSCANF_FAIL_RETURN;
				case '{':
					if (doSave)
					{
						doSave = false;
					}
					else
					{
						// Already in a quiet section.
						logprintf("sscanf warning: Can't have nestled quiet sections.");
					}
					break;
				case '}':
					if (doSave)
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else
					{
						doSave = true;
					}
					break;
				case 'Z':
					logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
					// FALLTHROUGH
				case 'z':
					logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
					// FALLTHROUGH
				case 'S':
					{
						char *
							dest;
						int
							length;
						if (DoSD(&format, &dest, &length))
						{
							// Send the string to PAWN.
							if (doSave)
							{
								amx_GetAddr(amx, params[paramPos++], &cptr);
								amx_SetString(cptr, dest, 0, 0, length);
							}
						}
					}
					break;
				case 'P':
					logprintf("sscanf warning: You can't have an optional delimiter.");
					// FALLTHROUGH
				case 'p':
					// Discard delimiter.  This only matters when they have
					// real inputs, not the default ones used here.
					GetSingleType(&format);
					continue;
				case '\'':
					// Implicitly optional if the specifiers after it are
					// optional.
					{
						bool
							escape = false;
						while (!IsEnd(*format) && (escape || *format != '\''))
						{
							if (*format == '\\')
							{
								escape = !escape;
							}
							else
							{
								escape = false;
							}
							++format;
						}
						if (*format == '\'')
						{
							++format;
						}
						else
						{
							logprintf("sscanf warning: Unclosed string literal.");
						}
					}
					break;
					// Large block of specifiers all together.
				case 'a':
				case 'b':
				case 'c':
				case 'd':
				case 'e':
				case 'f':
				case 'g':
				case 'h':
				case 'i':
				case 'k':
				case 'l':
				case 'n':
				case 'o':
				case 'q':
				case 'r':
				case 's':
				case 'u':
				case 'x':
					// These are non optional items, but the input string
					// didn't include them, so we fail - this is in fact the
					// most basic definition of a fail (the original)!  We
					// don't need any text warnings here - admittedly we don't
					// know if the format specifier is well formed (there may
					// not be enough return variables for example), but it
					// doesn't matter - the coder should have tested for those
					// things, and the more important thing is that the user
					// didn't enter the correct data.
					return SSCANF_FAIL_RETURN;
				case '%':
					logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
					break;
				default:
					logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
					break;
			}
			// Don't need any cleanup here.
		}
	}
	if (*format)
	{
		do
		{
			if (!IsWhitespace(*format))
			{
				// Only print this warning if the remaining characters are not
				// spaces - spaces are allowed, and sometimes required, on the
				// ends of formats (e.g. to stop the final 's' specifier
				// collecting all remaining characters and only get one word).
				// We could check that the remaining specifier is a valid one,
				// but this is only a guide - they shouldn't even have other
				// characters IN the specifier so it doesn't matter - it will
				// point to a bug, which is the important thing.
				if (doSave)
				{
					if (*format == '}')
					{
						logprintf("sscanf warning: Not in a quiet section.");
					}
					else if (*format != '{')
					{
						// Fix the bad display bug.
						logprintf("sscanf warning: Format specifier does not match parameter count.");
					}
					// Only display it once.
					break;
				}
				else
				{
					if (*format == '}')
					{
						doSave = true;
					}
					else
					{
						logprintf("sscanf warning: Format specifier does not match parameter count.");
						break;
					}
				}
			}
			++format;
		}
		while (*format);
	}
	if (!doSave)
	{
		// Started a quiet section but never explicitly ended it.
		logprintf("sscanf warning: Unclosed quiet section.");
	}
	// No more parameters and no more format specifiers which could be read
	// from - this is a valid return!
	return SSCANF_TRUE_RETURN;
}
Beispiel #21
0
static inline float	GetFloatValue(const	char *str, const char	**next)
{
	float	ret	=	0;

	if ( str )
	{
		if (next)
		{
			*next	=	0;
		}

		str	=	SkipWhitespace(str);

		char dest[MAXNUM];
		char *dst	=	dest;
		const	char *hex	=	0;

		for	(int i = 0;	i	<	(MAXNUM	-	1);	i++)
		{
			char c =	*str;
			if (c	== 0 ||	IsWhitespace(c))
			{
				if (next)
				{
					*next	=	str;
				}
				break;
			}
			else if	(c ==	'$')
			{
				hex	=	str	+	1;
			}
			*dst++ = ToLower(c);
			str++;
		}

		*dst = 0;

		if (hex)
		{
			unsigned int iv	=	GetHEX(hex,	0);
			float	*v = (float*)	&iv;
			ret	=	 *v;
		}
		else if	(dest[0] ==	'f')
		{
			if (strcasecmp(dest,	"fltmax")	== 0 ||	strcasecmp(dest,	"fmax")	== 0 ||	strcasecmp(dest,	"FLT_MAX") ==	0	|| strcasecmp(dest, "INF")	== 0)
			{
				ret	=	FLT_MAX;
			}
			else if	(strcasecmp(dest, "fltmin") ==	0	|| strcasecmp(dest, "fmin") ==	0	|| strcasecmp(dest, "FLT_MIN")	== 0 ||	strcasecmp(dest,	"-INF")	== 0)
			{
				ret	=	-FLT_MAX;
			}
		}
		else if	(dest[0] ==	't')
		// t or	'true' is	treated	as the value '1'.
		{
			ret	=	1;
		}
		else
		{
			ret	=	(float)atof(dest);
		}
	}
	return ret;
}
Beispiel #22
0
void LanguagePack::ParseString(IStringReader *reader)
{
    auto sb = StringBuilder();
    codepoint_t codepoint;

    // Parse string identifier
    while (reader->TryPeek(&codepoint))
    {
        if (IsNewLine(codepoint))
        {
            // Unexpected new line, ignore line entirely
            return;
        }
        else if (!IsWhitespace(codepoint) && codepoint != ':')
        {
            reader->Skip();
            sb.Append(codepoint);
        }
        else
        {
            break;
        }
    }

    SkipWhitespace(reader);

    // Parse a colon
    if (!reader->TryPeek(&codepoint) || codepoint != ':')
    {
        // Expected a colon, ignore line entirely
        return;
    }
    reader->Skip();

    // Validate identifier
    const utf8 *identifier = sb.GetBuffer();

    int stringId;
    if (_currentGroup == nullptr)
    {
        if (sscanf(identifier, "STR_%4d", &stringId) != 1)
        {
            // Ignore line entirely
            return;
        }
    }
    else
    {
        if (strcmp(identifier, "STR_NAME") == 0) { stringId = 0; }
        else if (strcmp(identifier, "STR_DESC") == 0) { stringId = 1; }
        else if (strcmp(identifier, "STR_CPTY") == 0) { stringId = 2; }

        else if (strcmp(identifier, "STR_SCNR") == 0) { stringId = 0; }
        else if (strcmp(identifier, "STR_PARK") == 0) { stringId = 1; }
        else if (strcmp(identifier, "STR_DTLS") == 0) { stringId = 2; }
        else {
            // Ignore line entirely
            return;
        }
    }

    // Rest of the line is the actual string
    sb.Clear();
    while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint))
    {
        if (codepoint == '{')
        {
            uint32 token;
            bool isByte;
            if (ParseToken(reader, &token, &isByte))
            {
                if (isByte)
                {
                    sb.Append((const utf8*)&token, 1);
                }
                else
                {
                    sb.Append((int)token);
                }
            }
            else
            {
                // Syntax error or unknown token, ignore line entirely
                return;
            }
        }
        else
        {
            reader->Skip();
            sb.Append(codepoint);
        }
    }

    // Append a null terminator for the benefit of the last string
    _stringDataSB.Append('\0');

    // Get the relative offset to the string (add the base offset when we extract the string properly)
    utf8 * relativeOffset = (utf8*)_stringDataSB.GetLength();

    if (_currentGroup == nullptr)
    {
        // Make sure the list is big enough to contain this string id
        while (_strings.size() <= (size_t)stringId)
        {
            _strings.push_back(nullptr);
        }

        _strings[stringId] = relativeOffset;
    }
    else
    {
        if (_currentObjectOverride != nullptr)
        {
            _currentObjectOverride->strings[stringId] = relativeOffset;
        }
        else
        {
            _currentScenarioOverride->strings[stringId] = relativeOffset;
        }
    }

    _stringDataSB.Append(&sb);
}
Beispiel #23
0
void *Asc2Bin(const	char *source,	int	&count,	const	char *spec)
{
	char *dest = 0;

	count	=	0;


	int	cnt	=	0;
	int	size = 0;

	Atype	types[MAXARG];

	const	char *ctype	=	spec;

	while	(*ctype)
	{
		switch (ToLower(*ctype))
		{
			case 'f':
				size +=	sizeof(float);
				types[cnt] = AT_FLOAT;
				cnt++;
				break;
			case 'd':
				size +=	sizeof(int);
				types[cnt] = AT_INT;
				cnt++;
				break;
			case 'c':
				size +=	sizeof(char);
				types[cnt] = AT_CHAR;
				cnt++;
				break;
			case 'b':
				size +=	sizeof(char);
				types[cnt] = AT_BYTE;
				cnt++;
				break;
			case 'h':
				size +=	sizeof(short);
				types[cnt] = AT_SHORT;
				cnt++;
				break;
			case 'p':
				size +=	sizeof(const char*);
				types[cnt] = AT_STR;
				cnt++;
				break;
			case 'x':
				if (1)
				{
					Atype	type = AT_HEX4;
					int	sz = 4;
					switch (ctype[1])
					{
					case '1':
						type = AT_HEX1;
						sz = 1;
						ctype++;
						break;
					case '2':
						type = AT_HEX2;
						sz = 2;
						ctype++;
						break;
					case '4':
						type = AT_HEX4;
						sz = 4;
						ctype++;
						break;
					}
					types[cnt] = type;
					size +=	sz;
					cnt++;
				}
				break;
		}
		if (cnt	== MAXARG)
		{
			return 0;
		}
		// over	flowed the maximum specification!
		ctype++;
	}

	int	reserve_count	=	16;

	dest = new char[reserve_count	*size];
	memset(dest, 0,	reserve_count	*size);	// zero	out	memory

	char *dst	=	(char*)dest; //	where	we are storing the results

	while	(1)
	{

		for	(int j = 0;	j	<	cnt; j++)
		{
			source = SkipWhitespace(source); //	skip white spaces.

			if (*source	== 0)
			// we	hit	the	end	of the input data	before we	successfully parsed	all	input!
			{
				return dest;
			}

			switch (types[j])
			{
				case AT_FLOAT:
					if (1)
					{
						float	*v = (float*)dst;
						*v = GetFloatValue(source, &source);
						dst	+= sizeof(float);
					}
					break;
				case AT_INT:
					if (1)
					{
						int	*v = (int*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(int);
					}
					break;
				case AT_CHAR:
					if (1)
					{
						*dst++ =	*source++;
					}
					break;
				case AT_BYTE:
					if (1)
					{
						char *v	=	(char*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(char);
					}
					break;
				case AT_SHORT:
					if (1)
					{
						short	*v = (short*)dst;
						*v = GetIntValue(source, &source);
						dst	+= sizeof(short);
					}
					break;
				case AT_STR:
					if (1)
					{
						const	char **ptr = (const	char **)dst;
						*ptr = source;
						dst	+= sizeof(const	char*);
						while	(*source &&	!IsWhitespace(*source))
						{
							source++;
						}
					}
					break;
				case AT_HEX1:
					if (1)
					{
						unsigned int hex = GetHEX1(source, &source);
						unsigned char	*v = (unsigned char*)dst;
						*v = hex;
						dst	+= sizeof(unsigned char);
					}
					break;
				case AT_HEX2:
					if (1)
					{
						unsigned int hex = GetHEX2(source, &source);
						unsigned short *v	=	(unsigned	short*)dst;
						*v = hex;
						dst	+= sizeof(unsigned short);
					}
					break;
				case AT_HEX4:
					if (1)
					{
						unsigned int hex = GetHEX4(source, &source);
						unsigned int *v	=	(unsigned	int*)dst;
						*v = hex;
						dst	+= sizeof(unsigned int);
					}
					break;
				default: /*nothing*/ break;
			}
		}
		count++;

		if (count	>= reserve_count)
		{
			char *old_dest = (char*)dest;
			reserve_count	*= 2;
			dest = new char[reserve_count	*size];
			memset(dest, 0,	reserve_count	*size);	// zero	out	memory
			memcpy(dest, old_dest, reserve_count / 2 * size);	// copy	the	old	data.

			int	dist = (int)(dst - old_dest);
			dst	=	&dest[dist]; //	the	new	destination.

			delete old_dest; //	free up	the	old	data.

		}

	}

	return dest;
}
Beispiel #24
0
/** \brief parse configuration file.
*
* \param[in,out] as Pointer to session handle
* \param[in] filename Path to the configuration file
* \return 0 if parsing was successful, -1 if an error occured.
*/
int parse_config_file(struct auto_handle *as, const char *filename) {
  FILE *fp = NULL;
  char *line = NULL;
  char opt[MAX_OPT_LEN + 1];
  char param[MAX_PARAM_LEN + 1];
  char c; /* for the "" and '' check */
  int line_num = 0;
  int line_pos = 0;
  int opt_pos;
  int param_pos;
  int parse_error = 0;
  struct stat fs;
  option_type type;

  if ((fp = fopen(filename, "rb")) == NULL) {
    perror("fopen");
    return -1;
  }

  if(stat(filename, &fs) == -1) {
    fclose(fp);
    return -1;
  }

  if ((line = am_malloc(fs.st_size + 1)) == NULL) {
    dbg_printf(P_ERROR, "Can't allocate memory for 'line': %s (%ldb)", strerror(errno), fs.st_size + 1);
    fclose(fp);
    return -1;
  }

  if(fread(line, fs.st_size, 1, fp) != 1) {
    perror("fread");
    fclose(fp);
    am_free(line);
    return -1;
  }

  /* NULL-terminate the result */
  line[fs.st_size] = '\0';

  if(fp) {
    fclose(fp);
  }

  while(line_pos != fs.st_size) {
    line_pos = SkipWhitespace(line, line_pos, &line_num);

    if(line_pos < 0) {
      parse_error = 1;
      break;
    }

    if(line_pos >= fs.st_size) {
      break;
    }

    /* comment */
    if (line[line_pos] == '#') {
      ////dbg_printf(P_INFO2, "skipping comment (line %d)", line_num);
      while (line[line_pos] != '\n') {
        ++line_pos;
      }

      ++line_num;
      ++line_pos;  /* skip the newline as well */
      continue;
    }

    /* read option */
    for (opt_pos = 0; isprint(line[line_pos]) && line[line_pos] != ' ' &&
         line[line_pos] != '#' && line[line_pos] != '='; /* NOTHING */) {
      opt[opt_pos++] = line[line_pos++];
      if (opt_pos >= MAX_OPT_LEN) {
        dbg_printf(P_ERROR, "too long option at line %d", line_num);
        parse_error = 1;
      }
    }

    if (opt_pos == 0 || parse_error == 1) {
      dbg_printf(P_ERROR, "parse error at line %d (pos: %d)", line_num, line_pos);
      parse_error = 1;
      break;
    } else {
      opt[opt_pos] = '\0';
    }

    line_pos = SkipWhitespace(line, line_pos, &line_num);

    if(line_pos < 0) {
      parse_error = 1;
      break;
    }

    if(line_pos >= fs.st_size) {
      break;
    }

    /* check for '=' */
    if (line[line_pos++] != '=') {
         dbg_printf(P_ERROR, "Option '%s' needs a parameter (line %d)", opt, line_num);
      parse_error = 1;
      break;
    }

    line_pos = SkipWhitespace(line, line_pos, &line_num);

    if(line_pos < 0) {
      parse_error = 1;
      break;
    }

    if(line_pos >= fs.st_size) {
      break;
    }

    /* read the parameter */

    /* case 1: single string, no linebreaks allowed */
    if (line[line_pos] == '"' || line[line_pos] == '\'') {
      c = line[line_pos]; /* single or double quote */
      ++line_pos;  /* skip quote */
      parse_error = 1;
      for (param_pos = 0; (param_pos < MAX_PARAM_LEN) && (line_pos < fs.st_size) && (line[line_pos] != '\n'); /* NOTHING */) {
        if( line[line_pos] == c) {
          parse_error = 0;
          break;
        }
        param[param_pos++] = line[line_pos++];
      }

      if(parse_error == 0) {
        line_pos++;  /* skip the closing single or double quote */
        type = CONF_TYPE_STRING;
      } else {
        dbg_printf(P_ERROR, "Option '%s' has a too long parameter (line %d). Closing quote missing?", opt, line_num);
        break;
      }
    } else if (line[line_pos] == '{') { /* case 2: multiple items, linebreaks allowed */
      dbg_printf(P_DBG, "reading multiline param", line_num);
      ++line_pos;
      parse_error = 1;

      for (param_pos = 0; (line_pos < fs.st_size) && (param_pos < MAX_PARAM_LEN); /* NOTHING */) {
        if(line[line_pos] == '}') {
          parse_error = 0;
          break;
        }
        param[param_pos++] = line[line_pos++];
        if(line[line_pos] == '\n') {
          line_num++;
        }
      }

      if(parse_error == 0) {
        line_pos++;  /* skip the closing '}' */
        type = CONF_TYPE_STRINGLIST;
      } else {
        dbg_printf(P_ERROR, "Option %s has a too long parameter (line %d). Closing bracket missing?", opt, line_num);
        parse_error = 1;
        break;
      }
    } else { /* Case 3: integers */
      parse_error = 0;
      for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos]) && line[line_pos] != '#'; /* NOTHING */) {
          param[param_pos++] = line[line_pos++];
          if (param_pos >= MAX_PARAM_LEN) {
            dbg_printf(P_ERROR, "Option %s has a too long parameter (line %d)", opt, line_num);
            parse_error = 1;
            break;
          }
      }

      if(parse_error == 0) {
        type = CONF_TYPE_INT;
      } else {
        break;
      }
    }

    param[param_pos] = '\0';
    dbg_printf(P_DBG, "[parse_config_file] option: %s", opt);
    dbg_printf(P_DBG, "[parse_config_file] param: %s (%d byte)", param, strlen(param));
    dbg_printf(P_DBG, "[parse_config_file] -----------------");

    if(set_option(as, opt, param, type) == FAILURE) {
      parse_error = 1;
      break;
    }

    line_pos = SkipWhitespace(line, line_pos, &line_num);

    if(line_pos < 0) {
      parse_error = 1;
      break;
    }

    if(line_pos >= fs.st_size) {
      break;
    }
  }

  am_free(line);

  return (parse_error == 1) ? -1 : 0;
}
Beispiel #25
0
        result_t ParseJsonNumber(v8::Local<v8::Value> &retVal)
        {
            bool negative = false;
            int32_t beg_pos = position_;

            if (c0_ == '-') {
                Advance();
                negative = true;
            }

            if (c0_ == '0') {
                Advance();
                if (IsDecimalDigit(c0_))
                    return ReportUnexpectedCharacter();
            } else
            {
                int32_t i = 0;
                int32_t digits = 0;
                if (c0_ < '1' || c0_ > '9')
                    return ReportUnexpectedCharacter();

                do {
                    i = i * 10 + c0_ - '0';
                    digits++;
                    Advance();
                } while (IsDecimalDigit(c0_));

                if (c0_ != '.' && c0_ != 'e' && c0_ != 'E' && digits < 10) {
                    SkipWhitespace();
                    retVal = v8::Int32::New(isolate->m_isolate, negative ? -i : i);
                    return 0;
                }
            }

            if (c0_ == '.') {
                Advance();
                if (!IsDecimalDigit(c0_))
                    return ReportUnexpectedCharacter();

                do {
                    Advance();
                } while (IsDecimalDigit(c0_));
            }

            if (AsciiAlphaToLower(c0_) == 'e') {
                Advance();
                if (c0_ == '-' || c0_ == '+') Advance();
                if (!IsDecimalDigit(c0_))
                    return ReportUnexpectedCharacter();

                do {
                    Advance();
                } while (IsDecimalDigit(c0_));
            }

            int32_t length = position_ - beg_pos;
            double number;
            std::string chars(source_ + beg_pos, length);

            number = atof(chars.c_str());
            SkipWhitespace();
            retVal = v8::Number::New(isolate->m_isolate, number);
            return 0;
        }
void * Asc2Bin(const char *source,const MiI32 count,const char *spec,void *dest)
{

	MiI32   cnt = 0;
	MiI32   size  = 0;

	Atype types[MAXARG];

	const char *ctype = spec;

	while ( *ctype )
	{
		switch ( ToLower(*ctype) )
		{
			case 'f': size+= sizeof(MiF32); types[cnt] = AT_FLOAT; cnt++;  break;
			case 'd': size+= sizeof(MiI32);   types[cnt] = AT_INT;   cnt++;  break;
			case 'c': size+=sizeof(char);   types[cnt] = AT_CHAR;  cnt++;  break;
			case 'b': size+=sizeof(char);   types[cnt] = AT_BYTE;  cnt++;  break;
			case 'h': size+=sizeof(short);  types[cnt] = AT_SHORT; cnt++;  break;
			case 'p': size+=sizeof(const char *);  types[cnt] = AT_STR; cnt++;  break;
			case 'x':
				{
					Atype type = AT_HEX4;
					MiI32 sz = 4;
					switch ( ctype[1] )
					{
						case '1':  type = AT_HEX1; sz   = 1; ctype++;  break;
						case '2':  type = AT_HEX2; sz   = 2; ctype++;  break;
						case '4':  type = AT_HEX4; sz   = 4; ctype++;  break;
					}
					types[cnt] = type;
					size+=sz;
					cnt++;
				}
				break;
		}
		if ( cnt == MAXARG ) return 0; // over flowed the maximum specification!
		ctype++;
	}

	bool myalloc = false;

	if ( dest == 0 )
	{
		myalloc = true;
		dest = (char *) MI_ALLOC(sizeof(char)*count*size);
	}

	// ok...ready to parse lovely data....
	memset(dest,0,size_t(count*size)); // zero out memory

	char *dst = (char *) dest; // where we are storing the results
	for (MiI32 i=0; i<count; i++)
	{
		for (MiI32 j=0; j<cnt; j++)
		{
			source = SkipWhitespace(source); // skip white spaces.

			if (source == NULL ||  *source == 0 ) // we hit the end of the input data before we successfully parsed all input!
			{
				if ( myalloc )
				{
					MI_FREE(dest);
				}
				return 0;
			}

			switch ( types[j] )
			{
				case AT_FLOAT:
					{
						MiF32 *v = (MiF32 *) dst;
						*v = GetFloatValue(source,&source);
						dst+=sizeof(MiF32);
					}
					break;
				case AT_INT:
					{
						MiI32 *v = (MiI32 *) dst;
						*v = GetIntValue( source, &source );
						dst+=sizeof(MiI32);
					}
					break;
				case AT_CHAR:
					{
						*dst++ = *source++;
					}
					break;
				case AT_BYTE:
					{
						char *v = (char *) dst;
						*v = (char)GetIntValue(source,&source);
						dst+=sizeof(char);
					}
					break;
				case AT_SHORT:
					{
						short *v = (short *) dst;
						*v = (short)(unsigned short)GetIntValue( source,&source );
						dst+=sizeof(short);
					}
					break;
				case AT_STR:
					{
						const char **ptr = (const char **) dst;
						*ptr = source;
						dst+=sizeof(const char *);
						while ( *source && !IsWhitespace(*source) ) source++;
					}
					break;
				case AT_HEX1:
					{
						MiU32 hex = GetHEX1(source,&source);
						MiU8 *v = (MiU8 *) dst;
						*v = (MiU8)hex;
						dst+=sizeof(MiU8);
					}
					break;
				case AT_HEX2:
					{
						MiU32 hex = GetHEX2(source,&source);
						unsigned short *v = (unsigned short *) dst;
						*v = (unsigned short)hex;
						dst+=sizeof(unsigned short);
					}
					break;
				case AT_HEX4:
					{
						MiU32 hex = GetHEX4(source,&source);
						MiU32 *v = (MiU32 *) dst;
						*v = hex;
						dst+=sizeof(MiU32);
					}
					break;
				case AT_LAST: // Make compiler happy
					break;
			}
		}
	}

	return dest;
}
Beispiel #27
0
static void ReadMacroArgs (MacroExp* E)
/* Identify the arguments to a macro call */
{
    unsigned    Parens;         /* Number of open parenthesis */
    StrBuf      Arg = STATIC_STRBUF_INITIALIZER;

    /* Read the actual macro arguments */
    Parens = 0;
    while (1) {
        if (CurC == '(') {

            /* Nested parenthesis */
            SB_AppendChar (&Arg, CurC);
            NextChar ();
            ++Parens;

        } else if (IsQuote (CurC)) {

            /* Quoted string - just copy */
            CopyQuotedString (&Arg);

        } else if (CurC == ',' || CurC == ')') {

            if (Parens) {
                /* Comma or right paren inside nested parenthesis */
                if (CurC == ')') {
                    --Parens;
                }
                SB_AppendChar (&Arg, CurC);
                NextChar ();
            } else if (CurC == ',' && ME_ArgIsVariadic (E)) {
                /* It's a comma, but we're inside a variadic macro argument, so
                 * just copy it and proceed.
                 */
                SB_AppendChar (&Arg, CurC);
                NextChar ();
            } else {
                /* End of actual argument. Remove whitespace from the end. */
                while (IsSpace (SB_LookAtLast (&Arg))) {
                    SB_Drop (&Arg, 1);
                }

                /* If this is not the single empty argument for a macro with
                 * an empty argument list, remember it.
                 */
                if (CurC != ')' || SB_NotEmpty (&Arg) || E->M->ArgCount > 0) {
                    ME_AppendActual (E, &Arg);
                }

                /* Check for end of macro param list */
                if (CurC == ')') {
                    NextChar ();
                    break;
                }

                /* Start the next param */
                NextChar ();
                SB_Clear (&Arg);
            }
        } else if (SkipWhitespace (1)) {
            /* Squeeze runs of blanks within an arg */
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
        } else if (CurC == '/' && NextC == '*') {
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
            OldStyleComment ();
        } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
            if (SB_NotEmpty (&Arg)) {
                SB_AppendChar (&Arg, ' ');
            }
            NewStyleComment ();
        } else if (CurC == '\0') {
            /* End of input inside macro argument list */
            PPError ("Unterminated argument list invoking macro `%s'", E->M->Name);

            ClearLine ();
            break;
        } else {
            /* Just copy the character */
            SB_AppendChar (&Arg, CurC);
            NextChar ();
        }
    }

    /* Deallocate string buf resources */
    SB_Done (&Arg);
}
Beispiel #28
0
int CIMFHeader::Parse(char* buf, int len, int offs)
{
	char* p;
	char* key;
	char* value;
	int nkv = miHeaderSize;
	KeyValue* keyvalue;
	int keylen;

// macro for calculating remaining length
#define remlen ((int) (len - (p - buf)))

	mpcData = buf;
	
	p = buf + offs;
	p = SkipCrlf(p, remlen);
	if (!p)
		return -1;
	
	while (p < buf + len) {
		key = p;
		p = SeekChar(p, remlen, ':');
		
		if (p)
		{
			keylen = (int) (p - key);
			
			*p++ = '\0';
			p = SkipWhitespace(p, remlen);
			
			value = p;
			p = SeekCrlf(p, remlen);
			if (p)
			{
				keyvalue = GetmpoHeaders(nkv);
				
				keyvalue[nkv].keyStart = (int) (key - buf);
				keyvalue[nkv].keyLength = keylen;
				keyvalue[nkv].valueStart = (int) (value - buf);
				keyvalue[nkv].valueLength = (int) (p - value);
				nkv++;

				*p = '\0';
				p += 2;
			}
			else
			{
				p = key;
				break;
			}
		}
		else
		{
			p = key;
			break;
		}
	}
	
	miHeaderSize = nkv;
	
	return (int) (p - buf);

#undef remlen	
}