core/TextParsers.cpp
changeset 1656 b0b86d57530c
parent 1503 a799e1126242
child 1730 62dd251bb1cd
     1.1 --- a/core/TextParsers.cpp	Tue Oct 30 20:43:59 2007 +0000
     1.2 +++ b/core/TextParsers.cpp	Wed Oct 31 05:04:07 2007 +0000
     1.3 @@ -107,14 +107,13 @@
     1.4  	return true;
     1.5  }
     1.6  
     1.7 -SMCParseError TextParsers::ParseString_SMC(const char *stream, 
     1.8 +SMCError TextParsers::ParseString_SMC(const char *stream, 
     1.9  					 ITextListener_SMC *smc,
    1.10 -					 unsigned int *line,
    1.11 -					 unsigned int *col)
    1.12 +					 SMCStates *states)
    1.13  {
    1.14  	CharStream srdr = { stream };
    1.15  
    1.16 -	return ParseStream_SMC(&srdr, CharStreamReader, smc, line, col);
    1.17 +	return ParseStream_SMC(&srdr, CharStreamReader, smc, states);
    1.18  }
    1.19  
    1.20  /**
    1.21 @@ -135,16 +134,21 @@
    1.22  	return (ferror((FILE *)stream) == 0);
    1.23  }
    1.24  
    1.25 -SMCParseError TextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, unsigned int *line, unsigned int *col)
    1.26 +SMCError TextParsers::ParseFile_SMC(const char *file, ITextListener_SMC *smc, SMCStates *states)
    1.27  {
    1.28  	FILE *fp = fopen(file, "rt");
    1.29  
    1.30  	if (!fp)
    1.31  	{
    1.32 -		return SMCParse_StreamOpen;
    1.33 +		if (states != NULL)
    1.34 +		{
    1.35 +			states->line = 0;
    1.36 +			states->col = 0;
    1.37 +		}
    1.38 +		return SMCError_StreamOpen;
    1.39  	}
    1.40  
    1.41 -	SMCParseError result = ParseStream_SMC(fp, FileStreamReader, smc, line, col);
    1.42 +	SMCError result = ParseStream_SMC(fp, FileStreamReader, smc, states);
    1.43  
    1.44  	fclose(fp);
    1.45  
    1.46 @@ -273,34 +277,44 @@
    1.47  	return NULL;
    1.48  }
    1.49  
    1.50 -SMCParseError TextParsers::ParseStream_SMC(void *stream, 
    1.51 +SMCError TextParsers::ParseStream_SMC(void *stream, 
    1.52  								   STREAMREADER srdr, 
    1.53  								   ITextListener_SMC *smc, 
    1.54 -								   unsigned int *line, 
    1.55 -								   unsigned int *col)
    1.56 +								   SMCStates *pStates)
    1.57  {
    1.58  	char *reparse_point = NULL;
    1.59  	char in_buf[4096];
    1.60  	char *parse_point = in_buf;
    1.61  	char *line_begin = in_buf;
    1.62  	unsigned int read;
    1.63 -	unsigned int curline = 1;
    1.64 -	unsigned int curtok = 0;
    1.65  	unsigned int curlevel = 0;
    1.66  	bool in_quote = false;
    1.67  	bool ignoring = false;
    1.68  	bool eol_comment = false;
    1.69  	bool ml_comment = false;
    1.70  	unsigned int i;
    1.71 -	SMCParseError err = SMCParse_Okay;
    1.72 -	SMCParseResult res;
    1.73 +	SMCError err = SMCError_Okay;
    1.74 +	SMCResult res;
    1.75 +	SMCStates states;
    1.76  	char c;
    1.77  
    1.78  	StringInfo strings[3];
    1.79  	StringInfo emptystring;
    1.80  
    1.81 +	states.line = 1;
    1.82 +	states.col = 0;
    1.83 +
    1.84  	smc->ReadSMC_ParseStart();
    1.85  
    1.86 +	/**
    1.87 +	 * The stream reader reads in as much as it can fill the buffer with.
    1.88 +	 * It then processes the buffer.  If the buffer cannot be fully processed, for example, 
    1.89 +	 * a line is left hanging with no newline, then the contents of the buffer is shifted 
    1.90 +	 * down, and the buffer is filled from the stream reader again.
    1.91 +	 *
    1.92 +	 * What makes this particularly annoying is that we cache pointers everywhere, so when 
    1.93 +	 * the shifting process takes place, all those pointers must be shifted as well.
    1.94 +	 */
    1.95  	while (srdr(stream, parse_point, sizeof(in_buf) - (parse_point - in_buf) - 1, &read))
    1.96  	{
    1.97  		if (!read)
    1.98 @@ -308,10 +322,10 @@
    1.99  			break;
   1.100  		}
   1.101  
   1.102 -		/* :TODO: do this outside of the main loop somehow
   1.103 -		 * This checks for BOM markings
   1.104 +		/* Check for BOM markings, which is only relevant on the first line.
   1.105 +		 * Not worth it, but it could be moved out of the loop.
   1.106  		 */
   1.107 -		if (curline == 1 && 
   1.108 +		if (states.line == 1 && 
   1.109  			in_buf[0] == (char)0xEF && 
   1.110  			in_buf[1] == (char)0xBB && 
   1.111  			in_buf[2] == (char)0xBF)
   1.112 @@ -341,7 +355,7 @@
   1.113  					strings[0].end = &parse_point[i];
   1.114  					if (rotate(strings) != NULL)
   1.115  					{
   1.116 -						err = SMCParse_InvalidTokens;
   1.117 +						err = SMCError_InvalidTokens;
   1.118  						goto failed;
   1.119  					}
   1.120  				}
   1.121 @@ -354,39 +368,44 @@
   1.122  					ignoring = false;
   1.123  				}
   1.124  
   1.125 -				/* Pass the raw line onto the listener */
   1.126 -				if ((res=smc->ReadSMC_RawLine(line_begin, curline)) != SMCParse_Continue)
   1.127 +				/* Pass the raw line onto the listener.  We terminate the line so the receiver 
   1.128 +				 * doesn't get tons of useless info.  We restore the newline after.
   1.129 +				 */
   1.130 +				parse_point[i] = '\0';
   1.131 +				if ((res=smc->ReadSMC_RawLine(&states, line_begin)) != SMCResult_Continue)
   1.132  				{
   1.133 -					err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
   1.134 +					err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
   1.135  					goto failed;
   1.136  				}
   1.137 +				parse_point[i] = '\n';
   1.138  
   1.139  				/* Now we check the sanity of our staged strings! */
   1.140  				if (strings[2].ptr)
   1.141  				{
   1.142  					if (!curlevel)
   1.143  					{
   1.144 -						err = SMCParse_InvalidProperty1;
   1.145 +						err = SMCError_InvalidProperty1;
   1.146  						goto failed;
   1.147  					}
   1.148  					/* Assume the next string is a property and pass the info on. */
   1.149  					if ((res=smc->ReadSMC_KeyValue(
   1.150 +						&states,
   1.151  						FixupString(strings[2]),
   1.152 -						FixupString(strings[1]),
   1.153 -						strings[2].quoted,
   1.154 -						strings[1].quoted)) != SMCParse_Continue)
   1.155 +						FixupString(strings[1]))) != SMCResult_Continue)
   1.156  					{
   1.157 -						err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
   1.158 +						err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
   1.159  						goto failed;
   1.160  					}
   1.161  					scrap(strings);
   1.162  				}
   1.163  
   1.164  				/* Change the states for the next line */
   1.165 -				curtok = 0;
   1.166 -				curline++;
   1.167 +				states.col = 0;
   1.168 +				states.line++;
   1.169  				line_begin = &parse_point[i+1];		//Note: safe because this gets relocated later
   1.170 -			} else if (ignoring) {
   1.171 +			} 
   1.172 +			else if (ignoring) 
   1.173 +			{
   1.174  				if (in_quote)
   1.175  				{
   1.176  					/* If i was 0, this case is impossible due to reparsing */
   1.177 @@ -403,10 +422,12 @@
   1.178  						if (rotate(strings) != NULL)
   1.179  						{
   1.180  							/* If we rotated too many strings, there was too much crap on one line */
   1.181 -							err = SMCParse_InvalidTokens;
   1.182 +							err = SMCError_InvalidTokens;
   1.183  							goto failed;
   1.184  						}
   1.185 -					} else if (c == '\\') {
   1.186 +					} 
   1.187 +					else if (c == '\\') 
   1.188 +					{
   1.189  						strings[0].special = true;
   1.190  						if (i == (read - 1))
   1.191  						{
   1.192 @@ -414,7 +435,9 @@
   1.193  							break;
   1.194  						}
   1.195  					}
   1.196 -				} else if (ml_comment) {
   1.197 +				} 
   1.198 +				else if (ml_comment) 
   1.199 +				{
   1.200  					if (c == '*')
   1.201  					{
   1.202  						/* Check if we need to get more input first */
   1.203 @@ -431,11 +454,13 @@
   1.204  							assert(strings[0].ptr == NULL);
   1.205  							/* Advance the input stream so we don't choke on this token */
   1.206  							i++;
   1.207 -							curtok++;
   1.208 +							states.col++;
   1.209  						}
   1.210  					}
   1.211  				}
   1.212 -			} else {
   1.213 +			} 
   1.214 +			else 
   1.215 +			{
   1.216  				/* Check if we're whitespace or not */
   1.217  				if (!g_ws_chartable[(unsigned)c])
   1.218  				{
   1.219 @@ -468,7 +493,9 @@
   1.220  								ignoring = true;
   1.221  								eol_comment = true;
   1.222  								restage = true;
   1.223 -							} else if (parse_point[i+1] == '*') {
   1.224 +							} 
   1.225 +							else if (parse_point[i+1] == '*') 
   1.226 +							{
   1.227  								/* inline comment - start ignoring */
   1.228  								ignoring = true;
   1.229  								ml_comment = true;
   1.230 @@ -479,93 +506,108 @@
   1.231  								 */
   1.232  								restage = true;
   1.233  							}
   1.234 -						} else {
   1.235 +						} 
   1.236 +						else 
   1.237 +						{
   1.238  							ignoring = true;
   1.239  							eol_comment = true;
   1.240  							restage = true;
   1.241  						}
   1.242 -					} else if (c == '{') {
   1.243 +					} 
   1.244 +					else if (c == '{') 
   1.245 +					{
   1.246  						/* If we are staging a string, we must rotate here */
   1.247  						if (strings[0].ptr)
   1.248  						{
   1.249  							/* We have unacceptable tokens on this line */
   1.250  							if (rotate(strings) != NULL)
   1.251  							{
   1.252 -								err = SMCParse_InvalidSection1;
   1.253 +								err = SMCError_InvalidSection1;
   1.254  								goto failed;
   1.255  							}
   1.256  						}
   1.257  						/* Sections must always be alone */
   1.258  						if (strings[2].ptr != NULL)
   1.259  						{
   1.260 -							err = SMCParse_InvalidSection1;
   1.261 +							err = SMCError_InvalidSection1;
   1.262  							goto failed;
   1.263 -						} else if (strings[1].ptr == NULL) {
   1.264 -							err = SMCParse_InvalidSection2;
   1.265 +						} 
   1.266 +						else if (strings[1].ptr == NULL)
   1.267 +						{
   1.268 +							err = SMCError_InvalidSection2;
   1.269  							goto failed;
   1.270  						}
   1.271 -						if ((res=smc->ReadSMC_NewSection(FixupString(strings[1]), strings[1].quoted))
   1.272 -							!= SMCParse_Continue)
   1.273 +						if ((res=smc->ReadSMC_NewSection(&states, FixupString(strings[1])))
   1.274 +							!= SMCResult_Continue)
   1.275  						{
   1.276 -							err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
   1.277 +							err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
   1.278  							goto failed;
   1.279  						}
   1.280  						strings[1] = emptystring;
   1.281  						curlevel++;
   1.282 -					} else if (c == '}') {
   1.283 +					} 
   1.284 +					else if (c == '}') 
   1.285 +					{
   1.286  						/* Unlike our matching friend, this can be on the same line as something prior */
   1.287  						if (rotate(strings) != NULL)
   1.288  						{
   1.289 -							err = SMCParse_InvalidSection3;
   1.290 +							err = SMCError_InvalidSection3;
   1.291  							goto failed;
   1.292  						}
   1.293  						if (strings[2].ptr)
   1.294  						{
   1.295  							if (!curlevel)
   1.296  							{
   1.297 -								err = SMCParse_InvalidProperty1;
   1.298 +								err = SMCError_InvalidProperty1;
   1.299  								goto failed;
   1.300  							}
   1.301  							if ((res=smc->ReadSMC_KeyValue(
   1.302 +											&states,
   1.303  											FixupString(strings[2]),
   1.304 -											FixupString(strings[1]),
   1.305 -											strings[2].quoted,
   1.306 -											strings[1].quoted))
   1.307 -								!= SMCParse_Continue)
   1.308 +											FixupString(strings[1])))
   1.309 +								!= SMCResult_Continue)
   1.310  							{
   1.311 -								err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
   1.312 +								err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
   1.313  								goto failed;
   1.314  							}
   1.315 -						} else if (strings[1].ptr) {
   1.316 -							err = SMCParse_InvalidSection3;
   1.317 +						} 
   1.318 +						else if (strings[1].ptr) 
   1.319 +						{
   1.320 +							err = SMCError_InvalidSection3;
   1.321  							goto failed;
   1.322 -						} else if (!curlevel) {
   1.323 -							err = SMCParse_InvalidSection4;
   1.324 +						} 
   1.325 +						else if (!curlevel) 
   1.326 +						{
   1.327 +							err = SMCError_InvalidSection4;
   1.328  							goto failed;
   1.329  						}
   1.330  						/* Now it's safe to leave the section */
   1.331  						scrap(strings);
   1.332 -						if ((res=smc->ReadSMC_LeavingSection()) != SMCParse_Continue)
   1.333 +						if ((res=smc->ReadSMC_LeavingSection(&states)) != SMCResult_Continue)
   1.334  						{
   1.335 -							err = (res == SMCParse_HaltFail) ? SMCParse_Custom : SMCParse_Okay;
   1.336 +							err = (res == SMCResult_HaltFail) ? SMCError_Custom : SMCError_Okay;
   1.337  							goto failed;
   1.338  						}
   1.339  						curlevel--;
   1.340 -					} else if (c == '"') {
   1.341 +					} 
   1.342 +					else if (c == '"') 
   1.343 +					{
   1.344  						/* If we get a quote mark, we always restage, but we need to do it beforehand */
   1.345  						if (strings[0].ptr)
   1.346  						{
   1.347  							strings[0].end = &parse_point[i];
   1.348  							if (rotate(strings) != NULL)
   1.349  							{
   1.350 -								err = SMCParse_InvalidTokens;
   1.351 +								err = SMCError_InvalidTokens;
   1.352  								goto failed;
   1.353  							}
   1.354  						}
   1.355  						strings[0].ptr = &parse_point[i];
   1.356  						in_quote = true;
   1.357  						ignoring = true;
   1.358 -					} else if (!strings[0].ptr) {
   1.359 +					} 
   1.360 +					else if (!strings[0].ptr) 
   1.361 +					{
   1.362  						/* If we have no string, we must start one */
   1.363  						strings[0].ptr = &parse_point[i];
   1.364  					}
   1.365 @@ -574,11 +616,13 @@
   1.366  						strings[0].end = &parse_point[i];
   1.367  						if (rotate(strings) != NULL)
   1.368  						{
   1.369 -							err = SMCParse_InvalidTokens;
   1.370 +							err = SMCError_InvalidTokens;
   1.371  							goto failed;
   1.372  						}
   1.373  					}
   1.374 -				} else {
   1.375 +				} 
   1.376 +				else 
   1.377 +				{
   1.378  					/* If we're eating a string and get whitespace, we need to restage.
   1.379  					 * (Note that if we are quoted, this is being ignored)
   1.380  					 */
   1.381 @@ -594,8 +638,10 @@
   1.382  							/* There's no string, so we must move this one down and eat up another */
   1.383  							strings[0].end = &parse_point[i];
   1.384  							rotate(strings);
   1.385 -						} else if (!strings[1].quoted) {
   1.386 -							err = SMCParse_InvalidTokens;
   1.387 +						} 
   1.388 +						else if (!strings[1].quoted) 
   1.389 +						{
   1.390 +							err = SMCError_InvalidTokens;
   1.391  							goto failed;
   1.392  						}
   1.393  					}
   1.394 @@ -603,7 +649,7 @@
   1.395  			}
   1.396  
   1.397  			/* Advance which token we're on */
   1.398 -			curtok++;
   1.399 +			states.col++;
   1.400  		}
   1.401  
   1.402  		if (line_begin != in_buf)
   1.403 @@ -637,8 +683,10 @@
   1.404  				parse_point = &parse_point[read];
   1.405  				parse_point -= bytes;
   1.406  			}
   1.407 -		} else if (read == sizeof(in_buf) - 1) {
   1.408 -			err = SMCParse_TokenOverflow;
   1.409 +		} 
   1.410 +		else if (read == sizeof(in_buf) - 1) 
   1.411 +		{
   1.412 +			err = SMCError_TokenOverflow;
   1.413  			goto failed;
   1.414  		}
   1.415  	}
   1.416 @@ -646,29 +694,31 @@
   1.417  	/* If we're done parsing and there are tokens left over... */
   1.418  	if (curlevel)
   1.419  	{
   1.420 -		err = SMCParse_InvalidSection5;
   1.421 +		err = SMCError_InvalidSection5;
   1.422  		goto failed;
   1.423 -	} else if (strings[0].ptr || strings[1].ptr) {
   1.424 -		err = SMCParse_InvalidTokens;
   1.425 +	} 
   1.426 +	else if (strings[0].ptr || strings[1].ptr) 
   1.427 +	{
   1.428 +		err = SMCError_InvalidTokens;
   1.429  		goto failed;
   1.430  	}
   1.431  	
   1.432  	smc->ReadSMC_ParseEnd(false, false);
   1.433 +	
   1.434 +	if (pStates != NULL)
   1.435 +	{
   1.436 +		*pStates = states;
   1.437 +	}
   1.438  
   1.439 -	return SMCParse_Okay;
   1.440 +	return SMCError_Okay;
   1.441  
   1.442  failed:
   1.443 -	if (line)
   1.444 +	if (pStates != NULL)
   1.445  	{
   1.446 -		*line = curline;
   1.447 +		*pStates = states;
   1.448  	}
   1.449  
   1.450 -	smc->ReadSMC_ParseEnd(true, (err == SMCParse_Custom));
   1.451 -
   1.452 -	if (col)
   1.453 -	{
   1.454 -		*col = curtok;
   1.455 -	}
   1.456 +	smc->ReadSMC_ParseEnd(true, (err == SMCError_Custom));
   1.457  
   1.458  	return err;
   1.459  }
   1.460 @@ -976,7 +1026,7 @@
   1.461  	return false;
   1.462  }
   1.463  
   1.464 -const char *TextParsers::GetSMCErrorString(SMCParseError err)
   1.465 +const char *TextParsers::GetSMCErrorString(SMCError err)
   1.466  {
   1.467  	static const char *s_errors[] = 
   1.468  	{
   1.469 @@ -994,7 +1044,7 @@
   1.470  		"A property was declared outside of a section",
   1.471  	};
   1.472  
   1.473 -	if (err < SMCParse_Okay || err > SMCParse_InvalidProperty1)
   1.474 +	if (err < SMCError_Okay || err > SMCError_InvalidProperty1)
   1.475  	{
   1.476  		return NULL;
   1.477  	}