| # Copyright (C) 2020 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| """This file reads entries from a Ninja rsp file.""" |
| |
| class NinjaRspFileReader: |
| """ |
| Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a |
| non-standard character by surrounding the whole entry with single quotes, and then replacing |
| any single quotes in the entry with the escape sequence '\''. |
| """ |
| |
| def __init__(self, filename): |
| self.f = open(filename, 'r') |
| self.r = self.character_reader(self.f) |
| |
| def __iter__(self): |
| return self |
| |
| def character_reader(self, f): |
| """Turns a file into a generator that returns one character at a time.""" |
| while True: |
| c = f.read(1) |
| if c: |
| yield c |
| else: |
| return |
| |
| def __next__(self): |
| entry = self.read_entry() |
| if entry: |
| return entry |
| else: |
| raise StopIteration |
| |
| def read_entry(self): |
| c = next(self.r, "") |
| if not c: |
| return "" |
| elif c == "'": |
| return self.read_quoted_entry() |
| else: |
| entry = c |
| for c in self.r: |
| if c == " " or c == "\n": |
| break |
| entry += c |
| return entry |
| |
| def read_quoted_entry(self): |
| entry = "" |
| for c in self.r: |
| if c == "'": |
| # Either the end of the quoted entry, or the beginning of an escape sequence, read the next |
| # character to find out. |
| c = next(self.r) |
| if not c or c == " " or c == "\n": |
| # End of the item |
| return entry |
| elif c == "\\": |
| # Escape sequence, expect a ' |
| c = next(self.r) |
| if c != "'": |
| # Malformed escape sequence |
| raise "malformed escape sequence %s'\\%s" % (entry, c) |
| entry += "'" |
| else: |
| raise "malformed escape sequence %s'%s" % (entry, c) |
| else: |
| entry += c |
| raise "unterminated quoted entry %s" % entry |