Example #1
0
bool LDAPExpr::CompareString( const std::string& s1, int op, const std::string& s2 )
{
  switch(op)
  {
  case LE:
    return s1.compare(s2) <= 0;
  case GE:
    return s1.compare(s2) >= 0;
  case EQ:
    return PatSubstr(s1,s2);
  case APPROX:
    return FixupString(s2) == FixupString(s1);
  default:
    return false;
  }
}
Example #2
0
SMCError TextParsers::ParseStream_SMC(void *stream,
	STREAMREADER srdr,
	ITextListener_SMC *smc,
	SMCStates *pStates)
{
	char *reparse_point = NULL;
	char in_buf[4096];
	char *parse_point = in_buf;
	char *line_begin = in_buf;
	unsigned int read;
	unsigned int curlevel = 0;
	bool in_quote = false;
	bool ignoring = false;
	bool eol_comment = false;
	bool ml_comment = false;
	unsigned int i;
	SMCError err = SMCError_Okay;
	SMCResult res;
	SMCStates states;
	char c;

	StringInfo strings[3];
	StringInfo emptystring;

	states.line = 1;
	states.col = 0;

	smc->ReadSMC_ParseStart();

	/**
	* The stream reader reads in as much as it can fill the buffer with.
	* It then processes the buffer.  If the buffer cannot be fully processed, for example,
	* a line is left hanging with no newline, then the contents of the buffer is shifted
	* down, and the buffer is filled from the stream reader again.
	*
	* What makes this particularly annoying is that we cache pointers everywhere, so when
	* the shifting process takes place, all those pointers must be shifted as well.
	*/
	while (srdr(stream, parse_point, sizeof(in_buf)-(parse_point - in_buf) - 1, &read))
	{
		if (!read)
		{
			break;
		}

		/* Check for BOM markings, which is only relevant on the first line.
		* Not worth it, but it could be moved out of the loop.
		*/
		if (states.line == 1 &&
			in_buf[0] == (char)0xEF &&
			in_buf[1] == (char)0xBB &&
			in_buf[2] == (char)0xBF)
		{
			/* Move EVERYTHING down :\ */
			memmove(in_buf, &in_buf[3], read - 3);
			read -= 3;
		}

		if (reparse_point)
		{
			read += (parse_point - reparse_point);
			parse_point = reparse_point;
			reparse_point = NULL;
		}

		for (i = 0; i<read; i++)
		{
			c = parse_point[i];
			if (c == '\n')
			{
				/* If we got a newline, there's a lot of things that could have happened in the interim.
				* First, let's make sure the staged strings are rotated.
				*/
				if (strings[0].ptr)
				{
					strings[0].end = &parse_point[i];
					if (rotate(strings) != NULL)
					{
						err = SMCError_InvalidTokens;
						goto failed;
					}
				}

				/* Next, let's clear some line-based values that may no longer have meaning */
				eol_comment = false;
				in_quote = false;
				if (ignoring && !ml_comment)
				{
					ignoring = false;
				}

				/* Pass the raw line onto the listener.  We terminate the line so the receiver
				* doesn't get tons of useless info.  We restore the newline after.
				*/
				parse_point[i] = '\0';
				if ((res = smc->ReadSMC_RawLine(&states, line_begin)) != SMCResult_Continue)
				{
					err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
					goto failed;
				}
				parse_point[i] = '\n';

				/* Now we check the sanity of our staged strings! */
				if (strings[2].ptr)
				{
					if (!curlevel)
					{
						err = SMCError_InvalidProperty1;
						goto failed;
					}
					/* Assume the next string is a property and pass the info on. */
					if ((res = smc->ReadSMC_KeyValue(
						&states,
						FixupString(strings[2]),
						FixupString(strings[1]))) != SMCResult_Continue)
					{
						err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
						goto failed;
					}
					scrap(strings);
				}

				/* Change the states for the next line */
				states.col = 0;
				states.line++;
				line_begin = &parse_point[i + 1];		//Note: safe because this gets relocated later
			}
			else if (ignoring)
			{
				if (in_quote)
				{
					/* If i was 0, we could have reparsed, so make sure there's no buffer underrun */
					if ((&parse_point[i] != in_buf) && c == '"' && parse_point[i - 1] != '\\')
					{
						/* If we reached a quote in an ignore phase,
						* we're staging a string and we must rotate it out.
						*/
						in_quote = false;
						ignoring = false;
						/* Set our info */
						strings[0].end = &parse_point[i];
						strings[0].quoted = true;
						if (rotate(strings) != NULL)
						{
							/* If we rotated too many strings, there was too much crap on one line */
							err = SMCError_InvalidTokens;
							goto failed;
						}
					}
					else if (c == '\\')
					{
						strings[0].special = true;
						if (i == (read - 1))
						{
							reparse_point = &parse_point[i];
							break;
						}
					}
				}
				else if (ml_comment)
				{
					if (c == '*')
					{
						/* Check if we need to get more input first */
						if (i == read - 1)
						{
							reparse_point = &parse_point[i];
							break;
						}
						if (parse_point[i + 1] == '/')
						{
							ml_comment = false;
							ignoring = false;
							/* We should not be staging anything right now. */
							assert(strings[0].ptr == NULL);
							/* Advance the input stream so we don't choke on this token */
							i++;
							states.col++;
						}
					}
				}
			}
			else
			{
				/* Check if we're whitespace or not */
				if (!g_ws_chartable[(unsigned char)c])
				{
					bool restage = false;
					/* Check various special tokens:
					* ;
					* //
					* / *
					* {
					* }
					*/
					if (c == ';' || c == '/')
					{
						/* If it's a line-based comment (that is, ; or //)
						* we will need to scrap everything until the end of the line.
						*/
						if (c == '/')
						{
							if (i == read - 1)
							{
								/* If we reached the end of the look-ahead, we need to re-check our input.
								* Breaking out will force this to be the new reparse point!
								*/
								reparse_point = &parse_point[i];
								break;
							}
							if (parse_point[i + 1] == '/')
							{
								/* standard comment */
								ignoring = true;
								eol_comment = true;
								restage = true;
							}
							else if (parse_point[i + 1] == '*')
							{
								/* inline comment - start ignoring */
								ignoring = true;
								ml_comment = true;
								/* yes, we restage, meaning that:
								* STR/ *stuff* /ING  (space because ml comments don't nest in C++)
								* will not generate 'STRING', but rather 'STR' and 'ING'.
								* This should be a rare occurrence and is done here for convenience.
								*/
								restage = true;
							}
						}
						else
						{
							ignoring = true;
							eol_comment = true;
							restage = true;
						}
					}
					else if (c == '{')
					{
						/* If we are staging a string, we must rotate here */
						if (strings[0].ptr)
						{
							/* We have unacceptable tokens on this line */
							if (rotate(strings) != NULL)
							{
								err = SMCError_InvalidSection1;
								goto failed;
							}
						}
						/* Sections must always be alone */
						if (strings[2].ptr != NULL)
						{
							err = SMCError_InvalidSection1;
							goto failed;
						}
						else if (strings[1].ptr == NULL)
						{
							err = SMCError_InvalidSection2;
							goto failed;
						}
						if ((res = smc->ReadSMC_NewSection(&states, FixupString(strings[1])))
							!= SMCResult_Continue)
						{
							err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
							goto failed;
						}
						strings[1] = emptystring;
						curlevel++;
					}
					else if (c == '}')
					{
						/* Unlike our matching friend, this can be on the same line as something prior */
						if (rotate(strings) != NULL)
						{
							err = SMCError_InvalidSection3;
							goto failed;
						}
						if (strings[2].ptr)
						{
							if (!curlevel)
							{
								err = SMCError_InvalidProperty1;
								goto failed;
							}
							if ((res = smc->ReadSMC_KeyValue(
								&states,
								FixupString(strings[2]),
								FixupString(strings[1])))
								!= SMCResult_Continue)
							{
								err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
								goto failed;
							}
						}
						else if (strings[1].ptr)
						{
							err = SMCError_InvalidSection3;
							goto failed;
						}
						else if (!curlevel)
						{
							err = SMCError_InvalidSection4;
							goto failed;
						}
						/* Now it's safe to leave the section */
						scrap(strings);
						if ((res = smc->ReadSMC_LeavingSection(&states)) != SMCResult_Continue)
						{
							err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
							goto failed;
						}
						curlevel--;
					}
					else if (c == '"')
					{
						/* If we get a quote mark, we always restage, but we need to do it beforehand */
						if (strings[0].ptr)
						{
							strings[0].end = &parse_point[i];
							if (rotate(strings) != NULL)
							{
								err = SMCError_InvalidTokens;
								goto failed;
							}
						}
						strings[0].ptr = &parse_point[i];
						in_quote = true;
						ignoring = true;
					}
					else if (!strings[0].ptr)
					{
						/* If we have no string, we must start one */
						strings[0].ptr = &parse_point[i];
					}
					if (restage && strings[0].ptr)
					{
						strings[0].end = &parse_point[i];
						if (rotate(strings) != NULL)
						{
							err = SMCError_InvalidTokens;
							goto failed;
						}
					}
				}
				else
				{
					/* If we're eating a string and get whitespace, we need to restage.
					* (Note that if we are quoted, this is being ignored)
					*/
					if (strings[0].ptr)
					{
						/*
						* The specification says the second string in a pair does not need to be quoted.
						* Thus, we check if there's already a string on the stack.
						* If there's a newline, we always rotate so the newline has an empty starter.
						*/
						if (!strings[1].ptr)
						{
							/* There's no string, so we must move this one down and eat up another */
							strings[0].end = &parse_point[i];
							rotate(strings);
						}
						else if (!strings[1].quoted)
						{
							err = SMCError_InvalidTokens;
							goto failed;
						}
					}
				}
			}

			/* Advance which token we're on */
			states.col++;
		}

		if (line_begin != in_buf)
		{
			/* The line buffer has advanced, so it's safe to copy N bytes back to the beginning.
			* What's N?  N is the lowest point we're currently relying on.
			*/
			char *stage = lowstring(strings);
			if (!stage || stage > line_begin)
			{
				stage = line_begin;
			}
			unsigned int bytes = read - (stage - parse_point);

			/* It is now safe to delete everything before the staged point */
			memmove(in_buf, stage, bytes);

			/* Calculate the number of bytes in the new buffer */
			bytes = stage - in_buf;
			/* Relocate all the cached pointers to our new base */
			line_begin -= bytes;
			reloc(strings[0], bytes);
			reloc(strings[1], bytes);
			reloc(strings[2], bytes);
			if (reparse_point)
			{
				reparse_point -= bytes;
			}
			if (parse_point)
			{
				parse_point = &parse_point[read];
				parse_point -= bytes;
			}
		}
		else if (read == sizeof(in_buf)-1)
		{
			err = SMCError_TokenOverflow;
			goto failed;
		}
	}

	/* If we're done parsing and there are tokens left over... */
	if (curlevel)
	{
		err = SMCError_InvalidSection5;
		goto failed;
	}
	else if (strings[0].ptr || strings[1].ptr)
	{
		err = SMCError_InvalidTokens;
		goto failed;
	}

	smc->ReadSMC_ParseEnd(false, false);

	if (pStates != NULL)
	{
		*pStates = states;
	}

	return SMCError_Okay;

failed:
	if (pStates != NULL)
	{
		*pStates = states;
	}

	smc->ReadSMC_ParseEnd(true, (err == SMCError_Custom));

	return err;
}