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 }