Expand tabs (implement expand(1)) Your task this time is to implement a variant of the POSIX expand(1) utility which expands tabs to spaces.

Your program is to take a tabstop specification and then read input on standard in and replace tab characters in the input with the appropriate amount of spaces to reach the next tabstop.  The result should be written to standard out.

Tabstop specification

A tabstop specification consists of either a single number, or a comma-separated list of tabstops.  In the case of a single number, it is repeated as if multiples of it occurred in a comma-separated list (i.e. 4 acts as 4,8,12,16,20,...).  Each entry in a comma-separated list is a positive integer optionally prefixed by a +.  A + prefix indicates a relative difference to the previous value in the comma-separated list.  The first value in the list must be absolute (i.e. unprefixed).  The tabstops specify the column of the next non-space character (following the expanded tab), with the leftmost column taken as number 0.  Tabs should always expand to at least one space.

Input/output

The tabstop specification is either to be taken as the first command-line parameter to the program, or read from standard in as the first line of input (terminated by a newline), at your discretion.  After the tabstop has been read, the remaining input (all input, in the former case) until EOF is to be processed and expanded.  The expanded output shall be written to standard out.

All expanded tabstops, and all input, is assumed to be a maximum of 80 columns wide.  All expanded tabstops are strictly increasing.



Example

Tabstop specification 4,6,+2,+8 is equivalent to 4,6,8,16, and with both the input

ab&lt;Tab&gt;c
&lt;Tab&gt;&lt;Tab&gt;d&lt;Tab&gt;e&lt;Tab&gt;f


is expanded into (␣ indicates a space)

ab␣␣c
␣␣␣␣␣␣d␣e␣␣␣␣␣␣␣f




01234567890123456   (Ruler for the above, not part of the output)
          1111111




Scoring is pure code-golf; shortest code wins.
Ruby 161 145

Reads the tabstop specification on the first line of input.

i=t=[]
gets.scan(/(\+)?(\d+)/){t&lt;&lt;i=$2.to_i+($1?i:0)}
81.times{|j|t&lt;&lt;j*i}
while gets
$_.sub!$&amp;," "*(t.find{|s|s&gt;i=$`.size}-i)while~/\t/
print
end


edit: Added two lines that makes the last read tabstop repeat so that tabstop specifications of a single number also works correctly

i is a temporary variable for holding the last parsed tabstop. t is the list of tabstobs, parsed from the gets.scan line. For good measure we add 81 multiples of the last parsed tabstop. the while gets loop keeps going until there is no more input. For each line of input we substitute tabs for spaces, one tab at the time because the string moves as we add the spaces and we must recalculate the correct tabstop.