Home -> Comma Separated Values Library
Overview

CGI

Error reporting

Comma Separated Values

Singly Linked List
Maintained by suitti@uitti.net, Stephen Uitti

Name

parse_csv_line, format_csv_line, read_csv_file, read_fixed_file write_fixed_file

Synopsis

     #include <stdio.h>
     #include "csv.h"

     cc file.c -lcsv -lcgi -lerr -lsll

Description

The libcsv.a library provides a functions to write and parse comma separated value format files. The values are converted between linked list and CSV formats. The caller specifies how errors are reported using the liberr library.

Routines

struct sll *parse_csv_line(char *buf);

Given a pointer to one line of data, parse the comma separated value fields and return it in a list. The libsll key elements hold the field values, in left to right order. If any error is detected, errors are reported using the liberr library, and NULL is returned.

The caller is responsible for free'ing memory. For example,

slp = parse_csv_line(buf);
...
sll_rmlist(slp);
char *format_csv_line(struct sll *fields);

Take a libsll list (in order), and create a csv line. List keys are data - C style strings. Returns a pointer to malloc'ed space, which the call must free(). Returns a string (without a newline) of this form:

"field1","field2","field3"
Always uses quotes, does not end with a comma. Returns NULL if out of RAM. Never emits errors.

struct sll *read_csv_file(const char *filename, int comments)

Read a file into an sll list. Blank lines are ignored. If comments is TRUE, then lines beginning with '#' are comments and ignored. In that case, if a record's first field needs to begin with a '#', it should be in quotes.

#test
is ignored.
"#test."
is the field #test. Key fields have row lists. The format is similar to that returned by cgi_osql() or cgi_psql(). The first row is only titles if it is titles (see cgi_table()). Errors are emitted using liberr functions. If no data is found, NULL is returned.

For configuration files, the suggested format for each line is a name field followed by zero or more values. Allow comments.

Example

int
main(int argc, char *argv[])
{
    register int i;
    register FILE *fp;
    char buf[CSV_BS];
    register struct sll *sp;
    register struct sll *slp;
    register int first;

    for (i = 1; i < argc; i++) {
	if ((fp = fopen(argv[i], "r"))) {
	    while (fgets(buf, CSV_BS, fp) != NULL) {
		slp = parse_csv_line(buf);
		if (slp != NULL) {
		    first = TRUE;
		    for (sp = slp; sp != NULL; sp = sp->next) {
			printf("%s%s", 
			       first ? "" : "|",
			       (char *)sp->key);
			first = FALSE;
		    }
		    printf("\n");
		}
	    }
	}
    }
    exit(0);
}


struct sll *read_fixed_file(const char *filename, const char *ctlfile)

Read fixed length file - parse into sll list. The filename argument specifies the name of the data file to read. The ctlfile argument specifies the name of the control file to read. Returns NULL if error, with errors emitted via err(). Returns 2 dimensional list of data. First row is headers, built from control file. All data is lead and trailing space compressed.

Typical control file:

# Redemption Output File Layout
# CSV control file format for fixed length data files.
# Column name, 1st column, last column, format string
#
# Format Strings:
# "9(6).9(6)" - 1 to 6 digits, ".", and 1 to 6 digits.
# eg: "     0.000000"
#
# "9(6).99" - 1 to 6 digits, ".", and two digits.
# eg: "     0.00"
#
# "MM/DD/YYYY" - date, eg: "04/19/2000" is 19 April 2000.
# Slashes are required.
#
# "integer" - integer value.  Lead zero suppressed. [+-][0-9]*
#
# "number" - floating point value. [+-][0-9]*[.[0-9]*][e[+-][0-9]*]
#
# "text" - any ASCII text.
# Default is "text".
#
"Equity Symbol","1","8","text"
"Equity Cusip","9","17","text"
"Equity Descr","18","47","text"
"Shares","48","57","integer"
"Fund Descr","58","82","text"
"Fund Symbol","83","90","text"
"Account","91","98","text"
"Trade Date","99","108","MM/DD/YYYY"
"Share Price","109","121","9(6).9(6)"
"Commission","122","130","9(6).99"
"Fees","131","139","9(6).99"
"Proceeds","140","154","9(12).99"

Typical data:
CYN     178566105CITY NATIONAL CORP                   224AMERICAN FINCL INST 1    AFGR001   07112604/19/2000     0.000000     0.00     0.00           0.00
RSLN    778162107ROSLYN BANCORP INC                   411AMERICAN FINCL SVCS 2    AFGR002   07162704/19/2000     0.000000     0.00     0.00           0.00


int write_fixed_file(const char *data_file, const char *ctl_file, const struct sll *data)

Write fixed length records file. Takes as input an sll list, and a configuration file name. The configuration file format is the same as used by read_fixed_file. The configuration file is read in and used to generate output. The file is written to the named file. Returns TRUE for success, FALSE for failure.

Diagnostics

Routines that return pointers return NULL if an error is encountered.

Files

/usr/local/lib/libcsv.a
/usr/local/include/csv.h

See Also

libsll, liberr

Author

Stephen Uitti, 1998

Bugs

The library needs routines to write CSV files, parse and format fixed format lines.

Dependency on libccgi is due to write_fixed_file using a date formatting function. Essentially none of the date functions in libccgi need to be in that library and could be in a more primitive date library. This would fix circular dependencies, where libccgi depends on libcsv and libcsv depends on libccgi.