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