CSV spreadsheet files are suitable for storing tabular data in a relatively portable way.

The CSV format is flexible but somewhat ill-defined.

For present purposes, authors may assume that the data fields contain no commas, backslashes, or quotation marks.



Task

Read a CSV file, change some values and save the changes back to a file.

For this task we will use the following CSV file:

C1,C2,C3,C4,C5
1,5,9,13,17
2,6,10,14,18
3,7,11,15,19
4,8,12,16,20

Suggestions


 Show how to add a column, headed 'SUM', of the sums of the rows.
 If possible, illustrate the use of built-in or standard functions, methods, or libraries, that handle generic CSV files.



\ csvsum.fs     Add a new column named SUM that contain sums from rows of CommaSeparatedValues
\ USAGE:
\       gforth-fast csvsum.fs -e "stdout stdin csvsum bye" <input.csv >output.csv
 
        CHAR ,  CONSTANT SEPARATOR
        3       CONSTANT DECIMALS
        1E1 DECIMALS S>D D>F F** FCONSTANT FSCALE
 
: colsum        ( ca u -- F: -- sum ;return SUM from CSV-string )
        0E0 OVER SWAP BOUNDS
        ?DO     ( a )
                I C@ SEPARATOR =
                IF      ( a )
                        I TUCK OVER - >FLOAT  IF F+ THEN
                        1+
                THEN
        LOOP    DROP
;
: f>string      ( -- ca u F: x -- )
        FSCALE F*
        F>D TUCK DABS <# DECIMALS 0 DO # LOOP [CHAR] . HOLD #S ROT SIGN #>
;
: rowC!+        ( offs char -- u+1  ;store CHAR at here+OFFS,increment offset )
        OVER HERE + C! 1+
;
: row$!+        ( offs ca u -- offs+u ;store STRING at here+OFFS,update offset )
        ROT 2DUP + >R HERE + SWAP MOVE R>
;
\ If run program with '-m 4G'option, we have practically 4G to store a row
: csvsum        ( fo fi --  ;write into FILEID-OUTPUT processed input from FILEID-INPUT )
        2DUP
        HERE UNUSED ROT READ-LINE THROW
        IF      ( fo fi fo u )
                HERE SWAP               ( fo fi fo ca u )
                SEPARATOR rowC!+
                s\" SUM" row$!+         ( fo fi fo ca u' )
                ROT WRITE-LINE THROW
                BEGIN   ( fo fi )
                        2DUP HERE UNUSED ROT READ-LINE THROW
                WHILE   ( fo fi fo u )
                        HERE SWAP                       ( fo fi fo ca u )
                        SEPARATOR rowC!+
                        HERE OVER colsum f>string       ( fo fi fo ca u ca' u' )
                        row$!+                          ( fo fi fo ca u'+u )
                        ROT WRITE-LINE THROW
                REPEAT
        THEN
        2DROP 2DROP
;