Esempio n. 1
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;
}
Esempio n. 2
0
void
secondPass (int argc, char *argv[])
{
	const char * pcolon = NULL;
	char *daemonname;
	for (int i = 1; i < argc; i++) {
		// omit parameters which qualify switches
		if( matchPrefix(argv[i],"-pool", 2) || matchPrefix(argv[i],"-direct", 4) ) {
			i++;
			continue;
		}
		if( matchPrefix(argv[i],"-subsystem", 5) ) {
			i++;
			continue;
		}
		if (matchPrefix (argv[i], "-format", 2)) {
			pm.registerFormat (argv[i+1], argv[i+2]);

			StringList attributes;
			ClassAd ad;
			if(!ad.GetExprReferences(argv[i+2],NULL,&attributes)){
				fprintf( stderr, "Error:  Parse error of: %s\n", argv[i+2]);
				exit(1);
			}

			attributes.rewind();
			char const *s;
			while( (s=attributes.next()) ) {
				projList.AppendArg(s);
			}

			if (diagnose) {
				printf ("Arg %d --- register format [%s] for [%s]\n",
						i, argv[i+1], argv[i+2]);
			}
			i += 2;
			continue;
		}
		if (*argv[i] == '-' &&
			(is_arg_colon_prefix(argv[i]+1, "autoformat", &pcolon, 5) || 
			 is_arg_colon_prefix(argv[i]+1, "af", &pcolon, 2)) ) {
				// make sure we have at least one more argument
			if ( !argv[i+1] || *(argv[i+1]) == '-') {
				fprintf( stderr, "Error: Argument %s requires "
						 "at last one attribute parameter\n", argv[i] );
				fprintf( stderr, "Use \"%s -help\" for details\n", myName );
				exit( 1 );
			}

			bool flabel = false;
			bool fCapV  = false;
			bool fRaw = false;
			bool fheadings = false;
			const char * prowpre = NULL;
			const char * pcolpre = " ";
			const char * pcolsux = NULL;
			if (pcolon) {
				++pcolon;
				while (*pcolon) {
					switch (*pcolon)
					{
						case ',': pcolsux = ","; break;
						case 'n': pcolsux = "\n"; break;
						case 'g': pcolpre = NULL; prowpre = "\n"; break;
						case 't': pcolpre = "\t"; break;
						case 'l': flabel = true; break;
						case 'V': fCapV = true; break;
						case 'r': case 'o': fRaw = true; break;
						case 'h': fheadings = true; break;
					}
					++pcolon;
				}
			}
			pm.SetAutoSep(prowpre, pcolpre, pcolsux, "\n");

			while (argv[i+1] && *(argv[i+1]) != '-') {
				++i;
				ClassAd ad;
				StringList attributes;
				if(!ad.GetExprReferences(argv[i],NULL,&attributes)){
					fprintf( stderr, "Error:  Parse error of: %s\n", argv[i]);
					exit(1);
				}

				attributes.rewind();
				char const *s;
				while ((s = attributes.next())) {
					projList.AppendArg(s);
				}

				MyString lbl = "";
				int wid = 0;
				int opts = FormatOptionNoTruncate;
				if (fheadings || pm_head.Length() > 0) { 
					const char * hd = fheadings ? argv[i] : "(expr)";
					wid = 0 - (int)strlen(hd); 
					opts = FormatOptionAutoWidth | FormatOptionNoTruncate; 
					pm_head.Append(hd);
				}
				else if (flabel) { lbl.formatstr("%s = ", argv[i]); wid = 0; opts = 0; }
				lbl += fRaw ? "%r" : (fCapV ? "%V" : "%v");
				if (diagnose) {
					printf ("Arg %d --- register format [%s] width=%d, opt=0x%x for [%s]\n",
							i, lbl.Value(), wid, opts,  argv[i]);
				}
				pm.registerFormat(lbl.Value(), wid, opts, argv[i]);
			}
			// if autoformat list ends in a '-' without any characters after it, just eat the arg and keep going.
			if (i+1 < argc && '-' == (argv[i+1])[0] && 0 == (argv[i+1])[1]) {
				++i;
			}
			continue;
		}
		if (is_dash_arg_colon_prefix(argv[i], "print-format", &pcolon, 2)) {
			if ( (i+1 >= argc)  || (*(argv[i+1]) == '-' && (argv[i+1])[1] != 0)) {
				fprintf( stderr, "Error: Argument -print-format requires a filename argument\n");
				exit( 1 );
			}
			// hack allow -pr ! to disable use of user-default print format files.
			if (MATCH == strcmp(argv[i+1], "!")) {
				++i;
				disable_user_print_files = true;
				continue;
			}
			ppTotalStyle = ppStyle;
			setPPstyle (PP_CUSTOM, i, argv[i]);
			setPPwidth();
			++i; // skip to the next argument.
			if (set_status_print_mask_from_stream(argv[i], true, &mode_constraint) < 0) {
				fprintf(stderr, "Error: invalid select file %s\n", argv[i]);
				exit (1);
			}
			if (mode_constraint) {
				query->addANDConstraint(mode_constraint);
			}
			using_print_format = true; // so we can hack totals.
			continue;
		}
		if (matchPrefix (argv[i], "-target", 5)) {
			i++;
			continue;
		}
		if (is_dash_arg_prefix(argv[i], "ads", 2)) {
			++i;
			continue;
		}
		if( matchPrefix(argv[i], "-sort", 3) ) {
			i++;
			if ( ! noSort) {
				sprintf( buffer, "%s =!= UNDEFINED", argv[i] );
				query->addANDConstraint( buffer );
			}
			continue;
		}
		
		if (matchPrefix (argv[i], "-statistics", 6)) {
			i += 2;
            sprintf(buffer,"STATISTICS_TO_PUBLISH = \"%s\"", statistics);
            if (diagnose) {
               printf ("[%s]\n", buffer);
               }
            query->addExtraAttribute(buffer);
            continue;
        }

		if (matchPrefix (argv[i], "-attributes", 3) ) {
			// parse attributes to be selected and split them along ","
			StringList more_attrs(argv[i+1],",");
			char const *s;
			more_attrs.rewind();
			while( (s=more_attrs.next()) ) {
				projList.AppendArg(s);
				dashAttributes.append(s);
			}
			i++;
			continue;
		}
		


		// figure out what the other parameters should do
		if (*argv[i] != '-') {
			// display extra information for diagnosis
			if (diagnose) {
				printf ("Arg %d (%s) --- adding constraint", i, argv[i]);
			}

			if( !(daemonname = get_daemon_name(argv[i])) ) {
				if ( (mode==MODE_SCHEDD_SUBMITTORS) && strchr(argv[i],'@') ) {
					// For a submittor query, it is possible that the
					// hostname is really a UID_DOMAIN.  And there is
					// no requirement that UID_DOMAIN actually have
					// an inverse lookup in DNS...  so if get_daemon_name()
					// fails with a fully qualified submittor lookup, just
					// use what we are given and do not flag an error.
					daemonname = strnewp(argv[i]);
				} else {
					dprintf_WriteOnErrorBuffer(stderr, true);
					fprintf( stderr, "%s: unknown host %s\n",
								 argv[0], get_host_part(argv[i]) );
					exit(1);
				}
			}

			switch (mode) {
			  case MODE_DEFRAG_NORMAL:
			  case MODE_STARTD_NORMAL:
			  case MODE_STARTD_COD:
#ifdef HAVE_EXT_POSTGRESQL
			  case MODE_QUILL_NORMAL:
#endif /* HAVE_EXT_POSTGRESQL */
			  case MODE_SCHEDD_NORMAL:
			  case MODE_SCHEDD_SUBMITTORS:
			  case MODE_MASTER_NORMAL:
			  case MODE_COLLECTOR_NORMAL:
			  case MODE_CKPT_SRVR_NORMAL:
			  case MODE_NEGOTIATOR_NORMAL:
			  case MODE_STORAGE_NORMAL:
			  case MODE_ANY_NORMAL:
			  case MODE_GENERIC_NORMAL:
			  case MODE_STARTD_AVAIL:
			  case MODE_OTHER:
			  case MODE_GRID_NORMAL:
			  case MODE_HAD_NORMAL:
			  	sprintf(buffer,"(%s==\"%s\") || (%s==\"%s\")",
						ATTR_NAME, daemonname, ATTR_MACHINE, daemonname );
				if (diagnose) {
					printf ("[%s]\n", buffer);
				}
				query->addORConstraint (buffer);
				break;

			  case MODE_STARTD_RUN:
				sprintf (buffer,"%s == \"%s\"",ATTR_REMOTE_USER,argv[i]);
				if (diagnose) {
					printf ("[%s]\n", buffer);
				}
				query->addORConstraint (buffer);
				break;

			  default:
				fprintf(stderr,"Error: Don't know how to process %s\n",argv[i]);
			}
			delete [] daemonname;
			daemonname = NULL;
		} else
		if (matchPrefix (argv[i], "-constraint", 4)) {
			if (diagnose) {
				printf ("[%s]\n", argv[i+1]);
			}
			query->addANDConstraint (argv[i+1]);
			i++;
		}
	}
}