/** * $Id: $ * $Date: $ * */ package org.xmlsh.sh.shell; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; /* * "Input Field Seperator" */ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.xmlsh.util.Util; /* * 2.6.5 Field Splitting * * After parameter expansion ( Parameter Expansion), command substitution ( * Command Substitution), and arithmetic expansion ( Arithmetic Expansion), the * shell shall scan the results of expansions and substitutions that did not * occur in double-quotes for field splitting and multiple fields can result. * * The shell shall treat each character of the IFS as a delimiter and use the * delimiters to split the results of parameter expansion and command * substitution into fields. * * If the value of IFS is a <space>, <tab>, and <newline>, or if it is unset, * any sequence of <space>s, <tab>s, or <newline>s at the beginning or end of * the input shall be ignored and any sequence of those characters within the * input shall delimit a field. For example, the input: * * <newline><space><tab>foo<tab><tab>bar<space> * * yields two fields, foo and bar. * * If the value of IFS is null, no field splitting shall be performed. * * Otherwise, the following rules shall be applied in sequence. The term * " IFS white space" is used to mean any sequence (zero or more instances) of * white space characters that are in the IFS value (for example, if IFS * contains <space>/ <comma>/ <tab>, any sequence of <space>s and <tab>s is * considered IFS white space). * * IFS white space shall be ignored at the beginning and end of the input. * * Each occurrence in the input of an IFS character that is not IFS white space, * along with any adjacent IFS white space, shall delimit a field, as described * previously. * * Non-zero-length IFS white space shall delimit a field. * */ public class IFS { static final String DEFAULT_IFS = " \t\n"; private boolean bDefault; private String ifs; // IFS private boolean bInit = false; private boolean bValid = false; private String ws; // whitespace in IFS private String nws; // NOT whitepsace in IFS private Pattern leading_ws; // Leading IFSWS pattern private Pattern trailing_ws; // Trailing IFSWS pattern private Pattern delim; // intraword delimiter pattern private static Logger mLogger = LogManager.getLogger(); public IFS(String sIFS) { if(sIFS == null) { ifs = DEFAULT_IFS; bDefault = true; } else { ifs = sIFS; bDefault = DEFAULT_IFS.equals(ifs); } } private void compile() { if(bDefault) { ws = ifs; nws = ""; } else { // get all whitespace - use regex to define whitespace ws = ifs.replaceAll("[^\\s]", ""); nws = ifs.replaceAll("\\s", ""); } /* * Compiling can produce runtime exceptions ! */ try { // Leading ws pattern - no escaping needed leading_ws = Util.isEmpty(ws) ? null : Pattern.compile("^[" + ws + "]+"); trailing_ws = Util.isEmpty(ws) ? null : Pattern.compile("[" + ws + "]+$"); if(bDefault) // delim is ifs delim = Pattern.compile("[" + ifs + "]+"); else { String nwsDelim = "[" + Pattern.quote(nws) + "]"; if(Util.isEmpty(ws)) { delim = Pattern.compile(nwsDelim); } else // Delim is (nws)(ws*) -- nws needs possible escaping delim = Pattern.compile(nwsDelim + "[" + ws + "]*"); } bValid = true; } catch (IllegalArgumentException e) { mLogger.info("Exception compiling IFS - bypassing", e); ifs = DEFAULT_IFS; bDefault = true; } finally { bInit = true; } } boolean isNull() { return Util.isEmpty(ifs); } boolean isDefault() { return bDefault; } public char getFirstChar() { return isNull() ? '\0' : ifs.charAt(0); } // Trim leading and trailing WS as per rules private String trimWS(String word) { if(!bValid) return word.trim(); if(leading_ws != null) word = leading_ws.matcher(word).replaceFirst(""); if(trailing_ws != null) word = trailing_ws.matcher(word).replaceFirst(""); return word; } public List<String> split(String word) throws IOException { // SNH if(isNull()) return Collections.singletonList(word); if(!bInit) compile(); word = trimWS(word); if(word.isEmpty()) return Collections.emptyList(); if(!bValid) return Arrays.asList(word.split("\\s+")); // split by the delimiter return Arrays.asList(delim.split(word, 0)); } public boolean isCurrent(String sIFS) { if(sIFS == null) return isDefault(); return sIFS.equals(ifs); } } /* * Copyright (C) 2008-2012 David A. Lee. * * The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights and limitations * under the License. * * The Original Code is: all this file. * * The Initial Developer of the Original Code is David A. Lee * * Portions created by (your name) are Copyright (C) (your legal entity). All * Rights Reserved. * * Contributor(s): David A. Lee * */