xref: /llvm-project/llvm/tools/llvm-rc/ResourceScriptCppFilter.cpp (revision 586ecdf205aa8b3d162da6f955170a6736656615)
1 //===-- ResourceScriptCppFilter.cpp ----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===---------------------------------------------------------------------===//
8 //
9 // This file implements an interface defined in ResourceScriptCppFilter.h.
10 //
11 //===---------------------------------------------------------------------===//
12 
13 #include "ResourceScriptCppFilter.h"
14 #include "llvm/ADT/StringExtras.h"
15 
16 #include <vector>
17 
18 using namespace llvm;
19 
20 namespace {
21 
22 class Filter {
23 public:
Filter(StringRef Input)24   explicit Filter(StringRef Input) : Data(Input), DataLength(Input.size()) {}
25 
26   std::string run();
27 
28 private:
29   // Parse the line, returning whether the line should be included in
30   // the output.
31   bool parseLine(StringRef Line);
32 
33   bool streamEof() const;
34 
35   StringRef Data;
36   size_t DataLength;
37 
38   size_t Pos = 0;
39   bool Outputting = true;
40 };
41 
run()42 std::string Filter::run() {
43   std::vector<StringRef> Output;
44 
45   while (!streamEof() && Pos != StringRef::npos) {
46     size_t LineStart = Pos;
47     Pos = Data.find_first_of("\r\n", Pos);
48     Pos = Data.find_first_not_of("\r\n", Pos);
49     StringRef Line = Data.take_front(Pos).drop_front(LineStart);
50 
51     if (parseLine(Line))
52       Output.push_back(Line);
53   }
54 
55   return llvm::join(Output, "");
56 }
57 
parseLine(StringRef Line)58 bool Filter::parseLine(StringRef Line) {
59   Line = Line.ltrim();
60 
61   if (!Line.consume_front("#")) {
62     // A normal content line, filtered according to the current mode.
63     return Outputting;
64   }
65 
66   // Found a preprocessing directive line. From here on, we always return
67   // false since the preprocessing directives should be filtered out.
68 
69   Line.consume_front("line");
70   if (!Line.starts_with(" "))
71     return false; // Not a line directive (pragma etc).
72 
73   // #line 123 "path/file.h"
74   // # 123 "path/file.h" 1
75 
76   Line =
77       Line.ltrim(); // There could be multiple spaces after the #line directive
78 
79   size_t N;
80   if (Line.consumeInteger(10, N)) // Returns true to signify an error
81     return false;
82 
83   Line = Line.ltrim();
84 
85   if (!Line.consume_front("\""))
86     return false; // Malformed line, no quote found.
87 
88   // Split the string at the last quote (in case the path name had
89   // escaped quotes as well).
90   Line = Line.rsplit('"').first;
91 
92   StringRef Ext = Line.rsplit('.').second;
93 
94   if (Ext.equals_insensitive("h") || Ext.equals_insensitive("c")) {
95     Outputting = false;
96   } else {
97     Outputting = true;
98   }
99 
100   return false;
101 }
102 
streamEof() const103 bool Filter::streamEof() const { return Pos == DataLength; }
104 
105 } // anonymous namespace
106 
107 namespace llvm {
108 
filterCppOutput(StringRef Input)109 std::string filterCppOutput(StringRef Input) { return Filter(Input).run(); }
110 
111 } // namespace llvm
112