001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.cli2.option; 018 019import java.util.ArrayList; 020import java.util.Comparator; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Set; 024 025import org.apache.commons.cli2.Argument; 026import org.apache.commons.cli2.Option; 027import org.apache.commons.cli2.OptionException; 028import org.apache.commons.cli2.WriteableCommandLine; 029import org.apache.commons.cli2.resource.ResourceConstants; 030import org.apache.commons.cli2.resource.ResourceHelper; 031 032/** 033 * An Argument implementation that allows a variable size Argument to precede a 034 * fixed size argument. The canonical example of it's use is in the unix 035 * <code>cp</code> command where a number of source can be specified with 036 * exactly one destination specfied at the end. 037 */ 038public class SourceDestArgument 039 extends ArgumentImpl { 040 private final Argument source; 041 private final Argument dest; 042 043 /** 044 * Creates a SourceDestArgument using defaults where possible. 045 * 046 * @param source the variable size Argument 047 * @param dest the fixed size Argument 048 */ 049 public SourceDestArgument(final Argument source, 050 final Argument dest) { 051 this(source, dest, DEFAULT_INITIAL_SEPARATOR, DEFAULT_SUBSEQUENT_SEPARATOR, 052 DEFAULT_CONSUME_REMAINING, null); 053 } 054 055 /** 056 * Creates a SourceDestArgument using the specified parameters. 057 * 058 * @param source the variable size Argument 059 * @param dest the fixed size Argument 060 * @param initialSeparator the inistial separator to use 061 * @param subsequentSeparator the subsequent separator to use 062 * @param consumeRemaining the token triggering consume remaining behaviour 063 * @param defaultValues the default values for the SourceDestArgument 064 */ 065 public SourceDestArgument(final Argument source, 066 final Argument dest, 067 final char initialSeparator, 068 final char subsequentSeparator, 069 final String consumeRemaining, 070 final List defaultValues) { 071 super("SourceDestArgument", null, sum(source.getMinimum(), dest.getMinimum()), 072 sum(source.getMaximum(), dest.getMaximum()), initialSeparator, subsequentSeparator, 073 null, consumeRemaining, defaultValues, 0); 074 075 this.source = source; 076 this.dest = dest; 077 078 if (dest.getMinimum() != dest.getMaximum()) { 079 throw new IllegalArgumentException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.SOURCE_DEST_MUST_ENFORCE_VALUES)); 080 } 081 } 082 083 private static int sum(final int a, 084 final int b) { 085 return Math.max(a, Math.max(b, a + b)); 086 } 087 088 public void appendUsage(final StringBuffer buffer, 089 final Set helpSettings, 090 final Comparator comp) { 091 final int length = buffer.length(); 092 093 source.appendUsage(buffer, helpSettings, comp); 094 095 if (buffer.length() != length) { 096 buffer.append(' '); 097 } 098 099 dest.appendUsage(buffer, helpSettings, comp); 100 } 101 102 public List helpLines(int depth, 103 Set helpSettings, 104 Comparator comp) { 105 final List helpLines = new ArrayList(); 106 helpLines.addAll(source.helpLines(depth, helpSettings, comp)); 107 helpLines.addAll(dest.helpLines(depth, helpSettings, comp)); 108 109 return helpLines; 110 } 111 112 public void validate(WriteableCommandLine commandLine, 113 Option option) 114 throws OptionException { 115 final List values = commandLine.getValues(option); 116 117 final int limit = values.size() - dest.getMinimum(); 118 int count = 0; 119 120 final Iterator i = values.iterator(); 121 122 while (count++ < limit) { 123 commandLine.addValue(source, i.next()); 124 } 125 126 while (i.hasNext()) { 127 commandLine.addValue(dest, i.next()); 128 } 129 130 source.validate(commandLine, source); 131 dest.validate(commandLine, dest); 132 } 133 134 public boolean canProcess(final WriteableCommandLine commandLine, 135 final String arg) { 136 return source.canProcess(commandLine, arg) || dest.canProcess(commandLine, arg); 137 } 138}