summaryrefslogtreecommitdiff
path: root/tools/llvm-rc
diff options
context:
space:
mode:
authorMarek Sokolowski <mnbvmar@gmail.com>2017-08-28 23:46:30 +0000
committerMarek Sokolowski <mnbvmar@gmail.com>2017-08-28 23:46:30 +0000
commit233d2b81e8b307be4294df5540f4f21c0a3696fb (patch)
treee50506ad2cd81385e38dc95a22b222ba262b7cb8 /tools/llvm-rc
parentcc308a061570ca2c8cca83a9b6527892588d5638 (diff)
[llvm-rc] Add MENU parsing ability (parser, pt 4/8).
This extends llvm-rc parsing tool by MENU resource (msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx). As for now, MENUEX (msdn.microsoft.com/en-us/library/windows/desktop/aa381023(v=vs.85).aspx) seems unnecessary. Thanks for Nico Weber for his original work in this area. Differential Revision: https://reviews.llvm.org/D36898 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311956 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-rc')
-rw-r--r--tools/llvm-rc/ResourceScriptParser.cpp67
-rw-r--r--tools/llvm-rc/ResourceScriptParser.h4
-rw-r--r--tools/llvm-rc/ResourceScriptStmt.cpp40
-rw-r--r--tools/llvm-rc/ResourceScriptStmt.h86
4 files changed, 197 insertions, 0 deletions
diff --git a/tools/llvm-rc/ResourceScriptParser.cpp b/tools/llvm-rc/ResourceScriptParser.cpp
index 8d08396e615..5cc171c49af 100644
--- a/tools/llvm-rc/ResourceScriptParser.cpp
+++ b/tools/llvm-rc/ResourceScriptParser.cpp
@@ -71,6 +71,8 @@ RCParser::ParseType RCParser::parseSingleResource() {
Result = parseIconResource();
else if (TypeToken->equalsLower("HTML"))
Result = parseHTMLResource();
+ else if (TypeToken->equalsLower("MENU"))
+ Result = parseMenuResource();
else
return getExpectedError("resource type", /* IsAlreadyRead = */ true);
@@ -285,6 +287,71 @@ RCParser::ParseType RCParser::parseHTMLResource() {
return make_unique<HTMLResource>(*Arg);
}
+RCParser::ParseType RCParser::parseMenuResource() {
+ ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+ ASSIGN_OR_RETURN(Items, parseMenuItemsList());
+ return make_unique<MenuResource>(std::move(*OptStatements),
+ std::move(*Items));
+}
+
+Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
+ RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+ MenuDefinitionList List;
+
+ // Read a set of items. Each item is of one of three kinds:
+ // MENUITEM SEPARATOR
+ // MENUITEM caption:String, result:Int [, menu flags]...
+ // POPUP caption:String [, menu flags]... { items... }
+ while (!consumeOptionalType(Kind::BlockEnd)) {
+ ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
+
+ bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM");
+ bool IsPopup = ItemTypeResult->equals_lower("POPUP");
+ if (!IsMenuItem && !IsPopup)
+ return getExpectedError("MENUITEM, POPUP, END or '}'", true);
+
+ if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
+ // Now, expecting SEPARATOR.
+ ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
+ if (SeparatorResult->equals_lower("SEPARATOR")) {
+ List.addDefinition(make_unique<MenuSeparator>());
+ continue;
+ }
+
+ return getExpectedError("SEPARATOR or string", true);
+ }
+
+ // Not a separator. Read the caption.
+ ASSIGN_OR_RETURN(CaptionResult, readString());
+
+ // If MENUITEM, expect also a comma and an integer.
+ uint32_t MenuResult = -1;
+
+ if (IsMenuItem) {
+ RETURN_IF_ERROR(consumeType(Kind::Comma));
+ ASSIGN_OR_RETURN(IntResult, readInt());
+ MenuResult = *IntResult;
+ }
+
+ ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr));
+
+ if (IsPopup) {
+ // If POPUP, read submenu items recursively.
+ ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
+ List.addDefinition(make_unique<PopupItem>(*CaptionResult, *FlagsResult,
+ std::move(*SubMenuResult)));
+ continue;
+ }
+
+ assert(IsMenuItem);
+ List.addDefinition(
+ make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
+ }
+
+ return std::move(List);
+}
+
RCParser::ParseType RCParser::parseStringTableResource() {
ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
diff --git a/tools/llvm-rc/ResourceScriptParser.h b/tools/llvm-rc/ResourceScriptParser.h
index e286f83160c..3fd1c27d928 100644
--- a/tools/llvm-rc/ResourceScriptParser.h
+++ b/tools/llvm-rc/ResourceScriptParser.h
@@ -130,8 +130,12 @@ private:
ParseType parseCursorResource();
ParseType parseIconResource();
ParseType parseHTMLResource();
+ ParseType parseMenuResource();
ParseType parseStringTableResource();
+ // Helper MENU parser.
+ Expected<MenuDefinitionList> parseMenuItemsList();
+
// Optional statement parsers.
ParseOptionType parseLanguageStmt();
ParseOptionType parseCharacteristicsStmt();
diff --git a/tools/llvm-rc/ResourceScriptStmt.cpp b/tools/llvm-rc/ResourceScriptStmt.cpp
index 150b668bd91..9f61ce451de 100644
--- a/tools/llvm-rc/ResourceScriptStmt.cpp
+++ b/tools/llvm-rc/ResourceScriptStmt.cpp
@@ -65,6 +65,46 @@ raw_ostream &HTMLResource::log(raw_ostream &OS) const {
return OS << "HTML (" << ResName << "): " << HTMLLoc << "\n";
}
+StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = {
+ "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"};
+
+raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint8_t Flags) {
+ for (size_t i = 0; i < NumFlags; ++i)
+ if (Flags & (1U << i))
+ OS << " " << OptionsStr[i];
+ return OS;
+}
+
+raw_ostream &MenuDefinitionList::log(raw_ostream &OS) const {
+ OS << " Menu list starts\n";
+ for (auto &Item : Definitions)
+ Item->log(OS);
+ return OS << " Menu list ends\n";
+}
+
+raw_ostream &MenuItem::log(raw_ostream &OS) const {
+ OS << " MenuItem (" << Name << "), ID = " << Id;
+ logFlags(OS, Flags);
+ return OS << "\n";
+}
+
+raw_ostream &MenuSeparator::log(raw_ostream &OS) const {
+ return OS << " Menu separator\n";
+}
+
+raw_ostream &PopupItem::log(raw_ostream &OS) const {
+ OS << " Popup (" << Name << ")";
+ logFlags(OS, Flags);
+ OS << ":\n";
+ return SubItems.log(OS);
+}
+
+raw_ostream &MenuResource::log(raw_ostream &OS) const {
+ OS << "Menu (" << ResName << "):\n";
+ OptStatements.log(OS);
+ return Elements.log(OS);
+}
+
raw_ostream &StringTableResource::log(raw_ostream &OS) const {
OS << "StringTable:\n";
OptStatements.log(OS);
diff --git a/tools/llvm-rc/ResourceScriptStmt.h b/tools/llvm-rc/ResourceScriptStmt.h
index cf1406e043f..7166138a517 100644
--- a/tools/llvm-rc/ResourceScriptStmt.h
+++ b/tools/llvm-rc/ResourceScriptStmt.h
@@ -166,6 +166,92 @@ public:
raw_ostream &log(raw_ostream &) const override;
};
+// -- MENU resource and its helper classes --
+// This resource describes the contents of an application menu
+// (usually located in the upper part of the dialog.)
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
+
+// Description of a single submenu item.
+class MenuDefinition {
+public:
+ enum Options {
+ CHECKED = (1 << 0),
+ GRAYED = (1 << 1),
+ HELP = (1 << 2),
+ INACTIVE = (1 << 3),
+ MENUBARBREAK = (1 << 4),
+ MENUBREAK = (1 << 5)
+ };
+
+ static constexpr size_t NumFlags = 6;
+ static StringRef OptionsStr[NumFlags];
+ static raw_ostream &logFlags(raw_ostream &, uint8_t Flags);
+ virtual raw_ostream &log(raw_ostream &OS) const {
+ return OS << "Base menu definition\n";
+ }
+ virtual ~MenuDefinition() {}
+};
+
+// Recursive description of a whole submenu.
+class MenuDefinitionList : public MenuDefinition {
+ std::vector<std::unique_ptr<MenuDefinition>> Definitions;
+
+public:
+ void addDefinition(std::unique_ptr<MenuDefinition> Def) {
+ Definitions.push_back(std::move(Def));
+ }
+ raw_ostream &log(raw_ostream &) const override;
+};
+
+// Separator in MENU definition (MENUITEM SEPARATOR).
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuSeparator : public MenuDefinition {
+public:
+ raw_ostream &log(raw_ostream &) const override;
+};
+
+// MENUITEM statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuItem : public MenuDefinition {
+ StringRef Name;
+ uint32_t Id;
+ uint8_t Flags;
+
+public:
+ MenuItem(StringRef Caption, uint32_t ItemId, uint8_t ItemFlags)
+ : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
+ raw_ostream &log(raw_ostream &) const override;
+};
+
+// POPUP statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
+class PopupItem : public MenuDefinition {
+ StringRef Name;
+ uint8_t Flags;
+ MenuDefinitionList SubItems;
+
+public:
+ PopupItem(StringRef Caption, uint8_t ItemFlags,
+ MenuDefinitionList &&SubItemsList)
+ : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
+ raw_ostream &log(raw_ostream &) const override;
+};
+
+// Menu resource definition.
+class MenuResource : public RCResource {
+ OptionalStmtList OptStatements;
+ MenuDefinitionList Elements;
+
+public:
+ MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
+ : OptStatements(std::move(OptStmts)), Elements(std::move(Items)) {}
+ raw_ostream &log(raw_ostream &) const override;
+};
+
// STRINGTABLE resource. Contains a list of strings, each having its unique ID.
//
// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx