+static int
+parse_trim_spec(const char *trim_spec, TrimFlags *flags)
+{
+ std::string spec(trim_spec), word;
+ size_t start = 0, comma = 0;
+ *flags = 0;
+
+ while (start < spec.size()) {
+ comma = spec.find(',', start);
+
+ if (comma == std::string::npos)
+ word = std::string(spec, start);
+ else
+ word = std::string(spec, start, comma - start);
+
+ if (strcmp(word.c_str(), "no-side-effects") == 0)
+ *flags |= TRIM_FLAG_NO_SIDE_EFFECTS;
+ else if (strcmp(word.c_str(), "textures") == 0)
+ *flags |= TRIM_FLAG_TEXTURES;
+ else if (strcmp(word.c_str(), "shaders") == 0)
+ *flags |= TRIM_FLAG_SHADERS;
+ else if (strcmp(word.c_str(), "drawing") == 0)
+ *flags |= TRIM_FLAG_DRAWING;
+ else {
+ return 1;
+ }
+
+ if (comma == std::string::npos)
+ break;
+
+ start = comma + 1;
+ }
+
+ return 0;
+}
+
+static int
+command(int argc, char *argv[])
+{
+ struct trim_options options;
+
+ options.calls = trace::CallSet(trace::FREQUENCY_NONE);
+ options.frames = trace::CallSet(trace::FREQUENCY_NONE);
+ options.dependency_analysis = false;
+ options.prune_uninteresting = false;
+ options.output = "";
+ options.thread = -1;
+ options.print_callset = 0;
+ options.trim_flags = -1;
+
+ int opt;
+ while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ help();
+ return 0;
+ case CALLS_OPT:
+ options.calls = trace::CallSet(optarg);
+ break;
+ case FRAMES_OPT:
+ options.frames = trace::CallSet(optarg);
+ break;
+ case DEPS_OPT:
+ options.dependency_analysis = true;
+ break;
+ case PRUNE_OPT:
+ options.prune_uninteresting = true;
+ break;
+ case 'a':
+ options.dependency_analysis = true;
+ options.prune_uninteresting = true;
+ break;
+ case THREAD_OPT:
+ options.thread = atoi(optarg);
+ break;
+ case 'o':
+ options.output = optarg;
+ break;
+ case PRINT_CALLSET_OPT:
+ options.print_callset = 1;
+ break;
+ case TRIM_SPEC_OPT:
+ if (parse_trim_spec(optarg, &options.trim_flags)) {
+ std::cerr << "error: illegal value for trim-spec: " << optarg << "\n";
+ std::cerr << "See \"apitrace help trim\" for help.\n";
+ return 1;
+ }
+ break;
+ default:
+ std::cerr << "error: unexpected option `" << opt << "`\n";
+ usage();
+ return 1;
+ }
+ }
+
+ /* If neither of --calls nor --frames was set, default to the
+ * entire set of calls. */
+ if (options.calls.empty() && options.frames.empty()) {
+ options.calls = trace::CallSet(trace::FREQUENCY_ALL);
+ }
+
+ if (optind >= argc) {
+ std::cerr << "error: apitrace trim requires a trace file as an argument.\n";
+ usage();
+ return 1;
+ }
+
+ if (argc > optind + 1) {
+ std::cerr << "error: extraneous arguments:";
+ for (int i = optind + 1; i < argc; i++) {
+ std::cerr << " " << argv[i];
+ }
+ std::cerr << "\n";
+ usage();
+ return 1;
+ }
+
+ if (options.dependency_analysis) {
+ std::cerr <<
+ "Note: The dependency analysis in \"apitrace trim\" is still experimental.\n"
+ " We hope that it will be useful, but it may lead to incorrect results.\n"
+ " If you find a trace that misbehaves while trimming, please share that\n"
+ " by sending email to apitrace@lists.freedesktop.org, cworth@cworth.org\n";
+ }
+
+ return trim_trace(argv[optind], &options);
+}
+