diff --git a/common/arg_parser.h b/common/arg_parser.h index 47c498b27..9e290d36c 100644 --- a/common/arg_parser.h +++ b/common/arg_parser.h @@ -124,6 +124,56 @@ class GetArgParser : public ArgParser { const char* str_; }; +class GetUsedArgsParser : public ArgParser { +public: + GetUsedArgsParser(const char* data) : ArgParser(data) { + for (size_t i = 0; i < NELEM(used_args_); i++) { + used_args_[0] = 0; + } + } + const char* GetArg(int arg_num, const char* name, const char* default_value) override { + int arg = arg_num + offset_; + used_args_[arg >> 5] |= 1UL << (arg & 31); + return ArgParser::GetArg(arg_num, name, default_value); + } + void Shift(int words) override { + ArgParser::Shift(words); + offset_ += words; + } + int used() { + int ret = 0; + for (size_t i = 0; i < NELEM(used_args_); i++) { + ret += __builtin_popcount(used_args_[i]); + } + return ret; + } + int next(int ARG) { + for (size_t j = 0; j <= NELEM(used_args_); j++) { + int arg = (ARG + j) % NELEM(used_args_); + if (used_args_[arg >> 5] & (1UL << (arg & 31))) return arg; + } + } + int prev(int ARG) { + for (size_t j = 0; j <= NELEM(used_args_); j++) { + int arg = ((NELEM(used_args_) * 64) + ARG - j) % (NELEM(used_args_) * 32); + if (used_args_[arg >> 5] & (1UL << (arg & 31))) return arg; + } + } + int nth(int ARG) { + for (size_t arg = 0; arg <= NELEM(used_args_); arg++) { + if (used_args_[arg >> 5] & (1UL << (arg & 31))) { + if (ARG-- <= 0) { + return arg; + } + } + } + return 0; + } +private: + int offset_ = 0; + uint32_t used_args_[8]; +}; + class GetMaxArgParser : public ArgParser { public: GetMaxArgParser(const char* data) : ArgParser(data) {} diff --git a/styles/style_parser.h b/styles/style_parser.h index 1afe6159b..0e2f64f5d 100644 --- a/styles/style_parser.h +++ b/styles/style_parser.h @@ -150,7 +150,7 @@ class StyleParser : public CommandParser { return ap.next(); } - // Returns true if the listed style refereces the specified argument. + // Returns the maximum argument used. int MaxUsedArgument(const char* str) { NamedStyle* style = FindStyle(str); if (!style) return false; @@ -162,6 +162,54 @@ class StyleParser : public CommandParser { return ap.max_arg(); } + // Returns the number of used arguments. + int UsedArguments(const char* str) { + NamedStyle* style = FindStyle(str); + if (!style) return false; + GetUsedArgsParser ap(SkipWord(str)); + CurrentArgParser = ≈ + delete style->style_allocator->make(); + // Ignore the two "builtin" arguments + if (FirstWord(str, "builtin") && ap.used() <= 2) return 0; + return ap.used(); + } + + // Returns the next used argument. + int NextUsedArguments(const char* str, int arg) { + NamedStyle* style = FindStyle(str); + if (!style) return false; + GetUsedArgsParser ap(SkipWord(str)); + CurrentArgParser = ≈ + delete style->style_allocator->make(); + // Ignore the two "builtin" arguments + if (FirstWord(str, "builtin") && ap.used() <= 2) return 0; + return ap.next(arg); + } + + // Returns the previous used argument. + int PrevUsedArguments(const char* str, int arg) { + NamedStyle* style = FindStyle(str); + if (!style) return false; + GetUsedArgsParser ap(SkipWord(str)); + CurrentArgParser = ≈ + delete style->style_allocator->make(); + // Ignore the two "builtin" arguments + if (FirstWord(str, "builtin") && ap.used() <= 2) return 0; + return ap.prev(arg); + } + + // Returns Nth used argument. + int GetNthUsedArguments(const char* str, int arg) { + NamedStyle* style = FindStyle(str); + if (!style) return false; + GetUsedArgsParser ap(SkipWord(str)); + CurrentArgParser = ≈ + delete style->style_allocator->make(); + // Ignore the two "builtin" arguments + if (FirstWord(str, "builtin") && ap.used() <= 2) return 0; + return ap.nth(arg); + } + // Get the Nth argument of a style string. // The output will be copied to |output|. // If the string itself doesn't contain that argument, the style