| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.felix.gogo.runtime; |
| |
| import java.util.regex.Pattern; |
| |
| public class Tokenizer extends BaseTokenizer |
| { |
| |
| private final Pattern redir = Pattern.compile("[0-9&]?>|[0-9]?>>|[0-9]?>&|[0-9]?<|[0-9]?<>|<<<|<<\\-?"); |
| |
| protected boolean inArray; |
| protected int word = 0; |
| |
| protected Token pushed; |
| protected Token last; |
| |
| public Tokenizer(CharSequence text) |
| { |
| super(text); |
| } |
| |
| public Token text() |
| { |
| return text; |
| } |
| |
| public Token next() |
| { |
| if (pushed != null) |
| { |
| Token t = pushed; |
| pushed = null; |
| return t; |
| } |
| skipSpace(last == null || Token.eq(last, "\n")); |
| int start = index - 1; |
| Token t, tn; |
| while (true) |
| { |
| switch (ch) |
| { |
| case EOT: |
| return token(start); |
| case '[': |
| word = 0; |
| inArray = true; |
| return token(start); |
| case ']': |
| inArray = false; |
| word++; |
| return token(start); |
| case '{': |
| if (start == index - 1 && Character.isWhitespace(peek())) |
| { |
| word = 0; |
| return token(start); |
| } |
| else |
| { |
| if (ch == '{') |
| { |
| find('}', '{'); |
| } |
| else |
| { |
| find(')', '('); |
| } |
| getch(); |
| break; |
| } |
| case '(': |
| if (start == index - 1) |
| { |
| word = 0; |
| return token(start); |
| } |
| else |
| { |
| if (ch == '{') |
| { |
| find('}', '{'); |
| } |
| else |
| { |
| find(')', '('); |
| } |
| getch(); |
| break; |
| } |
| case '>': |
| case '<': |
| t = text.subSequence(start, index); |
| if (!eot()) |
| { |
| tn = text.subSequence(start, index + 1); |
| if (redir.matcher(tn).matches()) |
| { |
| getch(); |
| break; |
| } |
| } |
| if (redir.matcher(t).matches() && start < index - 1) |
| { |
| getch(); |
| } |
| word = 0; |
| return token(start); |
| case '-': |
| t = text.subSequence(start, index); |
| if (redir.matcher(t).matches()) |
| { |
| getch(); |
| return token(start); |
| } |
| else { |
| getch(); |
| break; |
| } |
| case '&': |
| // beginning of token |
| if (start == index - 1) { |
| if (peek() == '&' || peek() == '>') |
| { |
| getch(); |
| getch(); |
| } |
| word = 0; |
| return token(start); |
| } |
| // in the middle of a redirection |
| else if (redir.matcher(text.subSequence(start, index)).matches()) |
| { |
| getch(); |
| break; |
| } |
| else |
| { |
| word = 0; |
| return token(start); |
| } |
| case '|': |
| if (start == index - 1 && (peek() == '|' || peek() == '&')) |
| { |
| getch(); |
| getch(); |
| } |
| word = 0; |
| return token(start); |
| case ';': |
| word = 0; |
| return token(start); |
| case '}': |
| case ')': |
| case ' ': |
| case '\t': |
| case '\n': |
| case '\r': |
| word++; |
| return token(start); |
| case '=': |
| if (inArray || word < 1 || index == start + 1) |
| { |
| word++; |
| return token(start); |
| } |
| getch(); |
| break; |
| case '\\': |
| escape(); |
| getch(); |
| break; |
| case '\'': |
| case '"': |
| skipQuote(); |
| getch(); |
| break; |
| default: |
| getch(); |
| break; |
| } |
| } |
| } |
| |
| private Token token(int start) |
| { |
| if (start == index - 1) |
| { |
| if (ch == EOT) |
| { |
| return null; |
| } |
| if (ch == '\r' && peek() == '\n') |
| { |
| getch(); |
| } |
| getch(); |
| last = text.subSequence(index - 2, index - 1); |
| } |
| else |
| { |
| last = text.subSequence(start, index - 1); |
| } |
| return last; |
| } |
| |
| public void push(Token token) |
| { |
| this.pushed = token; |
| } |
| |
| public Token readHereDoc(boolean ignoreLeadingTabs) |
| { |
| final short sLine = line; |
| final short sCol = column; |
| int start; |
| int nlIndex; |
| boolean nl; |
| // Find word |
| skipSpace(); |
| start = index - 1; |
| while (ch != '\n' && ch != EOT) { |
| getch(); |
| } |
| if (ch == EOT) { |
| throw new EOFError(sLine, sCol, "expected here-doc start", "heredoc", "foo\n"); |
| } |
| Token token = text.subSequence(start, index - 1); |
| getch(); |
| start = index - 1; |
| nlIndex = start; |
| nl = true; |
| // Get heredoc |
| while (true) |
| { |
| if (nl) |
| { |
| if (ignoreLeadingTabs && ch == '\t') |
| { |
| nlIndex++; |
| } |
| else |
| { |
| nl = false; |
| } |
| } |
| if (ch == '\n' || ch == EOT) |
| { |
| Token s = text.subSequence(nlIndex, index - 1); |
| if (Token.eq(s, token)) |
| { |
| Token hd = text.subSequence(start, s.start()); |
| getch(); |
| return hd; |
| } |
| nlIndex = index; |
| nl = true; |
| } |
| if (ch == EOT) |
| { |
| throw new EOFError(sLine, sCol, "unexpected eof found in here-doc", "heredoc", "\n" + token.toString() + "\n"); |
| } |
| getch(); |
| } |
| } |
| } |