Пример #1
0
static blocktype
parse_block_type(void)
{
	char new_file_token_str[256];
	blocktype block_type;

	// Parse the file token string as a name.

	if (!parse_name(file_token_str, new_file_token_str, false))
		expected_token("a valid block type");

	// Now verify it's a valid block type.

	if (!stricmp(new_file_token_str, "structural"))
		block_type = STRUCTURAL_BLOCK;
	else if (!stricmp(new_file_token_str, "multifaceted sprite"))
		block_type = MULTIFACETED_SPRITE;
	else if (!stricmp(new_file_token_str, "angled sprite"))
		block_type = ANGLED_SPRITE;
	else if (!stricmp(new_file_token_str, "revolving sprite"))
		block_type = REVOLVING_SPRITE;
	else if (!stricmp(new_file_token_str, "facing sprite"))
		block_type = FACING_SPRITE;
	else if (!stricmp(new_file_token_str, "player sprite"))
		block_type = PLAYER_SPRITE;
	else
		expected_token("block type 'structural', 'multifaceted sprite', "
			"'angled sprite', 'revolving sprite', 'facing sprite' or "
			"'player sprite'");
	return(block_type);
}
Пример #2
0
static char
parse_char()
{
	if (strlen(file_token_str) != 1)
		expected_token("a single-character string");
	return(*file_token_str);
}
Пример #3
0
static bool
parse_bool()
{
	bool value;

	start_parsing_value();
	if (token_in_value_is("yes"))
		value = true;
	else if (token_in_value_is("no"))
		value = false;
	else
		expected_token("boolean 'yes' or 'no'");
	stop_parsing_value();
	return(value);
}
Пример #4
0
static texstyle
parse_texture_style(void)
{
	texstyle style;

	start_parsing_value();
	if (token_in_value_is("tiled"))
		style = TILED_TEXTURE;
	else if (token_in_value_is("scaled"))
		style = SCALED_TEXTURE;
	else if (token_in_value_is("stretched"))
		style = STRETCHED_TEXTURE;
	else
		expected_token("texture style 'tiled', 'scaled' or 'stretched'");
	stop_parsing_value();
	return(style);
}
Пример #5
0
// Read a stream a line at a time, and parse it to fill out the print mask,
// header, group_by, where expression, and projection attributes.
//
int SetAttrListPrintMaskFromStream (
	SimpleInputStream & stream, // in: fetch lines from this stream until nextline() returns NULL
	const CustomFormatFnTable & FnTable, // in: table of custom output functions for SELECT
	AttrListPrintMask & mask, // out: columns and headers set in SELECT
	printmask_headerfooter_t & headfoot, // out: header and footer flags set in SELECT or SUMMARY
	printmask_aggregation_t & aggregate, // out: aggregation mode in SELECT
	std::vector<GroupByKeyInfo> & group_by, // out: ordered set of attributes/expressions in GROUP BY
	std::string & where_expression, // out: classad expression from WHERE
	StringList & attrs, // out ClassAd attributes referenced in mask or group_by outputs
	std::string & error_message) // out, if return is non-zero, this will be an error message
{
	ClassAd ad; // so we can GetExprReferences
	enum section_t { NOWHERE=0, SELECT, SUMMARY, WHERE, GROUP};
	enum cust_t { PRINTAS_STRING, PRINTAS_INT, PRINTAS_FLOAT };

	bool label_fields = false;
	const char * labelsep = " = ";
	const char * prowpre = NULL;
	const char * pcolpre = " ";
	const char * pcolsux = NULL;
	const char * prowsux = "\n";
	mask.SetAutoSep(prowpre, pcolpre, pcolsux, prowsux);

	error_message.clear();
	aggregate = PR_NO_AGGREGATION;

	printmask_headerfooter_t usingHeadFoot = (printmask_headerfooter_t)(HF_CUSTOM | HF_NOSUMMARY);
	section_t sect = SELECT;
	tokener toke("");
	while (toke.set(stream.nextline())) {
		if ( ! toke.next())
			continue;

		if (toke.matches("#")) continue;

		if (toke.matches("SELECT"))	{
			while (toke.next()) {
				if (toke.matches("FROM")) {
					if (toke.next()) {
						if (toke.matches("AUTOCLUSTER")) {
							aggregate = PR_FROM_AUTOCLUSTER;
						} else {
							std::string aa; toke.copy_token(aa);
							formatstr_cat(error_message, "Warning: Unknown header argument %s for SELECT FROM\n", aa.c_str());
						}
					}
				} else if (toke.matches("UNIQUE")) {
					aggregate = PR_COUNT_UNIQUE;
				} else if (toke.matches("BARE")) {
					usingHeadFoot = HF_BARE;
				} else if (toke.matches("NOTITLE")) {
					usingHeadFoot = (printmask_headerfooter_t)(usingHeadFoot | HF_NOTITLE);
				} else if (toke.matches("NOHEADER")) {
					usingHeadFoot = (printmask_headerfooter_t)(usingHeadFoot | HF_NOHEADER);
				} else if (toke.matches("NOSUMMARY")) {
					usingHeadFoot = (printmask_headerfooter_t)(usingHeadFoot | HF_NOSUMMARY);
				} else if (toke.matches("LABEL")) {
					label_fields = true;
				} else if (label_fields && toke.matches("SEPARATOR")) {
					if (toke.next()) { std::string tmp; toke.copy_token(tmp); collapse_escapes(tmp); labelsep = mask.store(tmp.c_str()); }
				} else if (toke.matches("RECORDPREFIX")) {
					if (toke.next()) { std::string tmp; toke.copy_token(tmp); collapse_escapes(tmp); prowpre = mask.store(tmp.c_str()); }
				} else if (toke.matches("RECORDSUFFIX")) {
					if (toke.next()) { std::string tmp; toke.copy_token(tmp); collapse_escapes(tmp); prowsux = mask.store(tmp.c_str()); }
				} else if (toke.matches("FIELDPREFIX")) {
					if (toke.next()) { std::string tmp; toke.copy_token(tmp); collapse_escapes(tmp); pcolpre = mask.store(tmp.c_str()); }
				} else if (toke.matches("FIELDSUFFIX")) {
					if (toke.next()) { std::string tmp; toke.copy_token(tmp); collapse_escapes(tmp); pcolsux = mask.store(tmp.c_str()); }
				} else {
					std::string aa; toke.copy_token(aa);
					formatstr_cat(error_message, "Warning: Unknown header argument %s for SELECT\n", aa.c_str());
				}
			}
			mask.SetAutoSep(prowpre, pcolpre, pcolsux, prowsux);
			sect = SELECT;
			continue;
		} else if (toke.matches("WHERE")) {
			sect = WHERE;
			if ( ! toke.next()) continue;
		} else if (toke.matches("GROUP")) {
			sect = GROUP;
			if ( ! toke.next() || (toke.matches("BY") && ! toke.next())) continue;
		} else if (toke.matches("SUMMARY")) {
			usingHeadFoot = (printmask_headerfooter_t)(usingHeadFoot & ~HF_NOSUMMARY);
			while (toke.next()) {
				if (toke.matches("STANDARD")) {
					// attrs.insert(ATTR_JOB_STATUS);
				} else if (toke.matches("NONE")) {
					usingHeadFoot = (printmask_headerfooter_t)(usingHeadFoot | HF_NOSUMMARY);
				} else {
					std::string aa; toke.copy_token(aa);
					formatstr_cat(error_message, "Unknown argument %s for SELECT\n", aa.c_str());
				}
			}
			sect = SUMMARY;
			continue;
		}

		switch (sect) {
		case SELECT: {
			toke.mark();
			std::string attr;
			std::string name;
			int opts = FormatOptionAutoWidth | FormatOptionNoTruncate;
			const char * fmt = "%v";
			int wid = 0;
			CustomFormatFn cust;

			bool got_attr = false;
			while (toke.next()) {
				const Keyword * pkw = SelectKeywords.find_match(toke);
				if ( ! pkw)
					continue;

				// next token is a keyword, if we havent set the attribute yet
				// it's everything up to the current token.
				int kw = pkw->value;
				if ( ! got_attr) {
					toke.copy_marked(attr);
					got_attr = true;
				}

				switch (kw) {
				case kw_AS: {
					if (toke.next()) {
						toke.copy_token(name);
						if (toke.is_quoted_string()) { collapse_escapes(name); }
					} else {
						expected_token(error_message, "column name after AS", "SELECT", stream, toke);
					}
					toke.mark_after();
				} break;
				case kw_PRINTF: {
					if (toke.next()) {
						std::string val; toke.copy_token(val);
						fmt = mask.store(val.c_str());
					} else {
						expected_token(error_message, "format after PRINTF", "SELECT", stream, toke);
					}
				} break;
				case kw_PRINTAS: {
					if (toke.next()) {
						const CustomFormatFnTableItem * pcffi = FnTable.find_match(toke);
						if (pcffi) {
							cust = pcffi->cust;
							//cust_type = pcffi->cust;
							const char * pszz = pcffi->extra_attribs;
							if (pszz) {
								size_t cch = strlen(pszz);
								while (cch > 0) { attrs.insert(pszz); pszz += cch+1; cch = strlen(pszz); }
							}
						} else {
							std::string aa; toke.copy_token(aa);
							formatstr_cat(error_message, "Unknown argument %s for PRINTAS\n", aa.c_str());
						}
					} else {
						expected_token(error_message, "function name after PRINTAS", "SELECT", stream, toke);
					}
				} break;
				case kw_NOSUFFIX: {
					opts |= FormatOptionNoSuffix;
				} break;
				case kw_NOPREFIX: {
					opts |= FormatOptionNoPrefix;
				} break;
				case kw_LEFT: {
					opts |= FormatOptionLeftAlign;
				} break;
				case kw_RIGHT: {
					opts &= ~FormatOptionLeftAlign;
				} break;
				case kw_TRUNCATE: {
					opts &= ~FormatOptionNoTruncate;
				} break;
				case kw_WIDTH: {
					if (toke.next()) {
						std::string val; toke.copy_token(val);
						if (toke.matches("AUTO")) {
							opts |= FormatOptionAutoWidth;
						} else {
							wid = atoi(val.c_str());
							//if (wid) opts &= ~FormatOptionAutoWidth;
							//PRAGMA_REMIND("TJ: decide how LEFT & RIGHT interact with pos and neg widths."
						}
					} else {
						expected_token(error_message, "number or AUTO after WIDTH", "SELECT", stream, toke);
					}
				} break;
				default:
					unexpected_token(error_message, "SELECT", stream, toke);
				break;
				} // switch
			} // while

			if ( ! got_attr) { attr = toke.content(); }
			trim(attr);
			if (attr.empty() || attr[0] == '#') continue;

			const char * lbl = name.empty() ? attr.c_str() : name.c_str();
			if (label_fields) {
				// build a format string that contains the label
				std::string label(lbl);
				if (labelsep) { label += labelsep; }
				if (fmt) { label += fmt; } 
				else {
					label += "%";
					if (wid) {
						if (opts & FormatOptionNoTruncate)
							formatstr_cat(label, "%d", wid);
						else
							formatstr_cat(label, "%d.%d", wid, wid < 0 ? -wid : wid);
					}
					label += cust ? "s" : "v";
				}
				lbl = mask.store(label.c_str());
				fmt = lbl;
				wid = 0;
			} else {
				if ( ! wid) { wid = 0 - (int)strlen(lbl); }
				mask.set_heading(lbl);
				lbl = NULL;
			}
			if (cust) {
				mask.registerFormat (lbl, wid, opts, cust, attr.c_str());
			} else {
				mask.registerFormat(fmt, wid, opts, attr.c_str());
			}
			ad.GetExprReferences(attr.c_str(), NULL, &attrs);
		}
		break;

		case WHERE: {
			toke.copy_to_end(where_expression);
			trim(where_expression);
		}
		break;

		case SUMMARY: {
		}
		break;

		case GROUP: {
			toke.mark();
			GroupByKeyInfo key;

			// in case we end up finding no keywords, copy the remainder of the line now as the expression
			toke.copy_to_end(key.expr);
			bool got_expr = false;

			while (toke.next()) {
				const Keyword * pgw = GroupKeywords.find_match(toke);
				if ( ! pgw)
					continue;

				// got a keyword
				int gw = pgw->value;
				if ( ! got_expr) {
					toke.copy_marked(key.expr);
					got_expr = true;
				}

				switch (gw) {
				case gw_AS: {
					if (toke.next()) { toke.copy_token(key.name); }
					toke.mark_after();
				} break;
				case gw_DECENDING: {
					key.decending = true;
					toke.mark_after();
				} break;
				case gw_ASCENDING: {
					key.decending = false;
					toke.mark_after();
				} break;
				default:
					unexpected_token(error_message, "GROUP BY", stream, toke);
				break;
				} // switch
			} // while toke.next

			trim(key.expr);
			if (key.expr.empty() || key.expr[0] == '#')
				continue;

			if ( ! ad.GetExprReferences(key.expr.c_str(), NULL, &attrs)) {
				formatstr_cat(error_message, "GROUP BY expression is not valid: %s\n", key.expr.c_str());
			} else {
				group_by.push_back(key);
			}
		}
		break;

		default:
		break;
		}
	}

	headfoot = usingHeadFoot;

	return 0;
}
Пример #6
0
void
parse_param_list(token tag_name, param *param_list, token end_token)
{
	param *param_ptr;
	int param_index;
	char old_name[256];

	// Initialise the parameter list.

	init_param_list();

	// Parse the parameter list.

	while ((param_ptr = parse_next_param(param_list)) != NULL) {
		switch (param_ptr->value_type) {
		case VALUE_BLOCK_NAME:
			parse_string(old_name, 256);
			if (!parse_name(old_name, (char *)param_ptr->variable_ptr, false))
				file_error("Expected a valid block name rather than '%s'",
					old_name);
			break;
		case VALUE_BLOCK_TYPE:
			*(blocktype *)param_ptr->variable_ptr = parse_block_type();
			break;
		case VALUE_BOOL:
			*(bool *)param_ptr->variable_ptr = parse_bool();
			break;
		case VALUE_CHAR:
			*(char *)param_ptr->variable_ptr = parse_char();
			break;
		case VALUE_DEGREES:
			*(double *)param_ptr->variable_ptr = parse_degrees();
			break;
		case VALUE_DOUBLE:
			*(double *)param_ptr->variable_ptr = parse_double();
			break;
		case VALUE_INTEGER:
			*(int *)param_ptr->variable_ptr = parse_integer();
			break;
		case VALUE_PART_NAME:
			parse_string(old_name, 256);
			if (!parse_name(old_name, (char *)param_ptr->variable_ptr, false))
				file_error("Expected a valid part name rather than '%s'",
					old_name);
			break;
		case VALUE_PERCENTAGE:
			*(double *)param_ptr->variable_ptr = parse_percentage();
			break;
		case VALUE_REF_LIST:
			parse_ref_list((ref_list *)param_ptr->variable_ptr);
			break;
		case VALUE_RGB:
			*(RGBcolour *)param_ptr->variable_ptr = parse_RGB();
			break;
		case VALUE_STRING:
			parse_string((char *)param_ptr->variable_ptr, 256);
			break;
		case VALUE_TEXCOORDS_LIST:
			parse_texcoords_list((texcoords_list *)param_ptr->variable_ptr);
			break;
		case VALUE_TEXTURE_STYLE:
			*(texstyle *)param_ptr->variable_ptr = parse_texture_style();
			break;
		case VALUE_VERTEX_COORDS:
			*(vertex *)param_ptr->variable_ptr = parse_vertex_coordinates();
			break;
		default:
			file_error("internal error--unrecognised parameter value type");
		}
	}

	// If an end_token was specified, then verify that the end token parsed
	// matches it.

	if (end_token != TOKEN_NONE && file_token != end_token)
		expected_token(get_token_str(end_token));

	// If there was a parameter list, verify that all required parameters were
	// parsed.

	if (param_list) {
		param_index = 0;
		while (param_list[param_index].param_name != TOKEN_NONE) {
			if (param_list[param_index].required && 
				!matched_param[param_index])
				file_error("parameter '%s' is missing from tag '%s'", 
					get_token_str(param_list[param_index].param_name), 
					get_token_str(tag_name));
			param_index++;
		}
	}
}
Пример #7
0
param *
parse_next_param(param *param_list)
{
	token param_name;
	char param_name_str[256];
	int param_index;
	
	// Parse the next valid parameter, skipping over invalid parameters.

	while (true) {

		// If the next token is ">" or "/>" then there are no more parameters
		// to parse, so break out of the loop.

		read_next_file_token();
		if (file_token == TOKEN_CLOSE_TAG || 
			file_token == TOKEN_CLOSE_SINGLE_TAG)
			break;

		// If the token is a string token, this is an error. Otherwise store
		// it as the parameter token.

		if (file_token == VALUE_STRING)
			expected_token("a parameter name");
		param_name = file_token;
		strcpy(param_name_str, file_token_str);
	
		// Parse the equal sign and the parameter value, which must be a
		// string value.

		match_next_file_token(TOKEN_EQUAL);
		read_next_file_token();
		if (file_token != VALUE_STRING)
			expected_token("a string as a parameter value");

		// If the parameter token was unknown or there is no parameter list,
		// skip over this parameter.

		if (param_name == TOKEN_UNKNOWN || param_list == NULL)
			continue;

		// Compare the parameter name against the entries in the parameter list;
		// if we find a match that hasn't been matched before, return the index
		// of that parameter entry.  Otherwise ignore this parameter and parse
		// the next.

		param_index = 0;
		while (param_list[param_index].param_name != TOKEN_NONE) {
			if (param_name == param_list[param_index].param_name &&
				!matched_param[param_index]) {
				matched_param[param_index] = true;
				return(&param_list[param_index]);
			}
			param_index++;
		}
	}

	// Return a NULL pointer if the end of the parameter list was encountered.

	return(NULL);
}