Skip to content
Browse files

Imported the exploded version of libcsv-3.0.

  • Loading branch information...
1 parent 7159e9a commit 5a4759edf6ab7fdd5370b55b5b11a279d8ea795f @robertpostill committed Jun 27, 2010
View
66 Changelog
@@ -0,0 +1,66 @@
+Fri Oct 13 08:40:13 EDT 2006
+libcsv version 0.9.0 released - initial public release
+
+Tue Oct 24 08:22:56 EDT 2006
+libcsv version 0.9.1 released
+ * Fixed LICENSE file to include LGPL text instead of GPL text, thanks to Alejandro Mery <amery@opensde.org> for pointing this out
+ * Included a Makefile for platforms supporting make, thanks to Alejandro Mery for creating the initial Makefile
+ * Updated INSTALL file to include Makefile directions
+
+
+Thu Mar 1 10:27:30 EST 2007
+libcsv version 0.9.5 released
+ * Fixed a bug in which the closing quote of a quoted field, along with any
+ trailing spaces, would be included as part of the field data for the last field when csv_fini was called if the last record did not end with a newline sequence. This was discovered while testing the Text-CSV-LibCSV Perl wrapper for libcsv created by Jiro Nishiguchi <jiro@cpan.org>
+ * Fixed incorrect prototype for csv_fini in the README file, thanks to Edd Edmondson <edward.edmondson@port.ac.uk> for pointing this out
+ * Minor modifications to clean up pedantic compiler warnings
+ * Added "Interfaces for other languages" to the README file
+
+Sun Mar 4 14:25:07 EST 2007
+libcsv version 1.0.0 released
+ * Changed the interface to allow arbitrary user data to be passed between the parser function and the callback functions via a void pointer eliminating the need for file-scope variables in cases where data needs to be shared and making it considerably easier to create interfaces to the library in other languages. This change makes this version of the library incompatible with previous versions. Thanks to Jiro Nishiguchi for suggesting this change
+ * man page is now included which obsoletes the old README, pdf version also included
+ * Updated examples to use new interface
+ * Updated documentation to reflect interface changes
+ * Cleaned up INSTALL file
+ * Included license statement in example programs
+
+Sun May 20 11:44:09 EDT 2007
+libcsv version 1.0.1 released
+ * Added CSV_STRICT_FINI option which can be used to cause csv_fini() to return an error when the quoted data being parsed doesn't contain a terminating quote character
+ * Added a test program to test the parsing and writer functions
+
+Fri Jun 1 11:18:28 EDT 2007
+libcsv version 2.0.0 released
+ * This major release contains features that break binary compatibility with earlier libcsv versions. The interface is backwards compatible with 1.x so existing programs only need to be recompiled to work with the new version, no source code modifications need to be made.
+ * Added csv_set_delim()/csv_get_delim() and csv_set_quote()/csv_get_quote() functions to set and get the field delimeter and quote characters respectively. Thanks to Martin Ugarte <ugarte.m@gmail.com> for his input
+ * Added csv_set_space_func() and csv_set_term_func() functions that allow a user provided function to specify which characters should be considered spaces and line terminators respectively
+ * Updated documentation to include new functions
+ * Included FAQ document to answer common questions about using libcsv to solve specific problems
+ * Updated test program to include ability to test new features
+ * Updated csvinfo to show the use of some of the new functions
+ * Added csv_write2 and csv_fwrite2 which allow the quote character to be specified
+
+Thu Jun 7 14:44:23 EDT 2007
+libcsv version 2.0.1 released
+ * Fixed bug in Makefile causing library to be installed as libcsv.so.0 instead of libcsv.so.2
+ * Fixed bug in csvvalid example program where location of malformed bytes past byte 1023 were misreported
+
+Fri Jul 25 22:17:35 EDT 2008
+libcsv version 3.0.0 released
+ * This release contains interface changes that are not compatible with
+ previous versions. Callback functions now use void * parameters
+ instead of char *, this eliminates the need to cast data read into a buffer
+ of unsigned char which is the proper way to read binary data, data is also
+ treated as an array of unsigned char internally. The cb2 callback function
+ now uses int instead of char, char has changed to unsigned char in several
+ places, csv_opts has been replaced with csv_get_opts and csv_set_opts, and
+ csv_fini returns -1 instead of 0 when no newline if present at the end of
+ the last record. New features also make this version binary-incompatible
+ with previous versions.
+ * Added CSV_APPEND_NULL option which will null-terminate all collected
+ fields making it easier to treat data as C strings when desired.
+ * Added C++ wrapper in csv.h to make it easier to call functions from C++.
+ * Added functions to change the memory allocation functions used, get the
+ size of the internal buffer, and get and set the size of the amount of
+ memory requested when the internal buffer gets too large.
View
149 FAQ
@@ -0,0 +1,149 @@
+My data contains unescaped quotes within quoted fields or quote
+characters in unquoted field.
+
+libcsv handles such malformed data by default, no special configuration
+is required. There are cases where such malformed data is ambigous and
+might not be parsed the way you would like, see the man page for libcsv
+for details. The csvfix and csvtest programs in the example directory
+may be useful when trying to determine how libcsv will parse your data.
+The csvvalid program can also be used to check for malformed data files.
+
+
+
+My csv file contains comments that should not be parsed as csv data,
+how can I handle this?
+
+Although there is no direct support for comment handling in libcsv you
+can preprocess the data before sending it to libcsv. For example, say
+that you wish to ignore all lines whose first non-space, non-tab
+character is a hash (#), you could use the following piece of code to
+accomplish that:
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "csv.h"
+
+int in_comment, in_record;
+
+void cb1(void *d, char *s, size_t size) { /* Data processing here */ }
+void cb2(void *d, char c) { in_record = 0; /* Record handling here */ }
+
+int main (void) {
+ int c;
+ char ch;
+ struct csv_parser *p;
+ if (csv_init(&p, 0))
+ return EXIT_FAILURE;
+
+ while ((c = getchar()) != EOF) {
+ ch = c;
+ if (in_comment) {
+ if (ch == '\012' || ch == '\015') {
+ in_comment = 0;
+ }
+ } else if (!in_record) {
+ if (ch == ' ' || ch == '\t') {
+ ;
+ } else if (ch == '#') {
+ in_comment = 1;
+ } else {
+ in_record = 1;
+ csv_parse(p, &ch, 1, cb1, cb2);
+ }
+ } else {
+ csv_parse(p, &ch, 1, cb1, cb2);
+ }
+ }
+ csv_fini(p, ...);
+ return 0;
+}
+
+If you determine that calling csv_parse for each character takes too
+much overhead (do some tests before making this decision, it usually
+doesn't) you can optimize this by processing a larger number of
+characters and calling csv_parse on a larger resulting buffer.
+If you know that your data is text-only, you can simplify this by
+reading one line at a time, checking the first non-space character,
+skipping the line if it is a comment character and calling csv_parse
+if it isn't.
+
+
+
+My data uses a semicolon as a delimiter instead of comma but otherwise
+follows CSV conventions, how can I use libcsv to read my data?
+
+Use the csv_set_delim function introduced in libcsv 2.0.0:
+struct csv_parser *p;
+csv_init(&p);
+csv_set_delim(p, ';');
+...
+
+You can use csv_set_delim to set the delimiter to any character. Any
+field that contains the delimiter must be quoted when using strict
+mode. Be careful not to set the delimiter to the same character used
+as the quote character, a space character or a line terminator
+character though as libcsv won't be able to determine if the character
+is a field delimiter or a quote, etc.
+
+
+
+My data uses a single quotes instead of double quotes for quoted
+fields, how can I accomidate this?
+
+Use the csv_set_quote function introduced in libcsv 2.0.0:
+struct csv_parser *p;
+csv_init(&p);
+csv_set_quote(p, '\'');
+...
+
+As with csv_set_delim you can set the quote character to any character
+but fields containing the quote character must still be quoted and are
+expected to be escaped by an instance of itself. For example, if you
+use csv_set_quote to change the quote character to a single quote,
+instances of a single quote in field data should be escaped by a
+preceding single quote.
+
+
+
+How can I preserve leading and trailing whitespace from non-quoted
+fields?
+
+By default libcsv ignores leading and trailing spaces and tabs from
+non-quoted fields as this is the most common practice and expected by
+many applications. The csv_set_space_func function introduced in
+libcsv 2.0.0 allows you to specify a function that will return 1 if
+the provided character should be considered a space character and 0
+otherwise. This allows you to change the characters that libcsv
+ignores around unquoted fields. If you create a function that always
+returns 0 then no character will be recognized as a space character
+and all characters will be preserved:
+
+int my_space(char c) { return 0;}
+
+struct csv_parser *p;
+csv_init(&p);
+csv_set_space_func(p, my_space);
+...
+
+
+How can I remove leading and trailing whitespace from quoted fields?
+
+By default libcsv removes surrounding space and tab characters from
+unquoted fields but not from quoted fields. The easiest way to remove
+unwanted characters from a quoted field is inside the field callback
+function, simply take the data provided to the callback function and
+perform any manipulations directly on it.
+
+
+
+I want to be able to do things like extract or search on specific
+fields from a CSV file, sort a CSV file, etc. but the common UNIX
+utilities (cut, grep, sort, etc.) don't work on CSV data that contains
+fields with embedded commas or newlines, etc. Are there any tools
+like this for managing CSV files?
+
+Take a look at csvutils at http://sourceforge.net/projects/csvutils.
+This package uses libcsv to provide a number of useful CSV utilities
+including csvcut, csvgrep, and others with option syntax resembling
+their non-CSV counterparts.
View
49 INSTALL
@@ -0,0 +1,49 @@
+[Installing on systems with make(1)]
+
+On systems with make, the installation process consists of:
+
+ make
+ make test
+ make install
+
+You may need to run ldconfig or a similiar command before dynamically
+linking your program to libcsv.
+
+This will install the csv.h header, libcsv shared and static libraries,
+and the csv(3) manual page. You can use one of the following targets to
+fine-tune the things that are installed:
+
+ make install_man - install only the man page
+ make install_headers - install only the header
+ make install_static_lib - install only the static version of the library
+ make install_shared_lib - install only the dynamic version of the library
+ make install_static - same as install_static_lib plus install_headers
+ mnake install_shared - same as install_shared_lib plus install_headers
+
+[Installing on systems without make]
+
+libcsv is written in pure ANSI C89 and does not have any prerequisites aside
+from a compiler and the Standard C library, it should compile on any
+conforming implementation. Below are examples of how to compile this on gcc,
+see your compiler's documentation for other compilers.
+
+libcsv can be installed as a shared library on systems that support it:
+ gcc -shared libcsv.c -o libcsv.so
+
+or simply compiled into object code an linked into your program:
+ gcc libcsv.c -c -o libcsv.o
+ gcc myproject.c libcsv.o -o myproject
+
+you can also compile libcsv as a static library:
+ gcc libcsv.c -c -o libcsv.o
+ ar -rc libcsv.a libcsv.o
+ ar -s libcsv.a
+
+
+The examples can be compiled with gcc like this:
+ gcc csvinfo.c libcsv.o -o csvinfo
+
+or using a shared library like this:
+ gcc csvinfo.c -lcsv -o csvinfo
+
+
View
458 LICENSE
@@ -0,0 +1,458 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
View
51 Makefile
@@ -0,0 +1,51 @@
+CC=gcc
+AR=ar
+
+VERSION=3.0.0
+DESTDIR=
+LIBDIR=/usr/lib
+INCDIR=/usr/include
+MANDIR=/usr/share/man/man3
+
+.PHONY: all install install_headers install_man install_shared install_static clean test
+
+all: libcsv.so libcsv.a
+
+install: install_headers install_shared_lib install_static_lib install_man
+
+install_shared: install_headers install_shared_lib
+install_static: install_headers install_static_lib
+
+install_man: csv.3.gz
+ cp -f $^ $(DESTDIR)$(MANDIR)/
+
+install_headers: csv.h
+ mkdir -p $(DESTDIR)$(INCDIR)/libcsv/
+ cp -f $^ $(DESTDIR)$(INCDIR)/libcsv/
+
+install_shared_lib: libcsv.so
+ cp -f $< $(DESTDIR)$(LIBDIR)/$<.$(VERSION)
+ ln -sf $<.$(VERSION) $(DESTDIR)$(LIBDIR)/$<.3
+ ln -sf $<.3 $(DESTDIR)$(LIBDIR)/$<
+
+install_static_lib: libcsv.a
+ cp -f $< $(DESTDIR)$(LIBDIR)/$<
+
+libcsv.o: libcsv.c csv.h
+ $(CC) $< -c -o $@
+
+libcsv.so: libcsv.o
+ $(CC) -shared $< -o $@
+
+libcsv.a: libcsv.o
+ $(AR) -rc $@ $^
+ $(AR) -s $@
+
+clean:
+ rm libcsv.o libcsv.so libcsv.a
+
+test: libcsv.o
+ $(CC) test_csv.c $< -o $@
+ ./test
+ rm ./test
+
View
27 README
@@ -0,0 +1,27 @@
+Installation
+------------
+installation usually consists of:
+make && make test && make install
+
+see the INSTALL file for details and instructions on other systems
+
+
+License
+-------
+The libcsv library is licensed under the LGPL, see the LICENSE file for details
+The example programs are licensed under the GPL, see the LICENSE file in the
+examples directory for details
+
+
+Documentation
+-------------
+See the accompanying man pages or pdf documentation
+
+
+libcsv interfaces for other programming languages
+-------------------------------------------------
+Perl - Text-CSV-LibCSV by Jiro Nishiguchi
+ http://search.cpan.org/dist/Text-CSV-LibCSV/
+
+Ruby - SimpleCSV by Ken Date
+ http://rubyforge.org/projects/simplecsv/
View
BIN csv.3.gz
Binary file not shown.
View
86 csv.h
@@ -0,0 +1,86 @@
+#ifndef LIBCSV_H__
+#define LIBCSV_H__
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CSV_MAJOR 3
+#define CSV_MINOR 0
+#define CSV_RELEASE 0
+
+/* Error Codes */
+#define CSV_SUCCESS 0
+#define CSV_EPARSE 1 /* Parse error in strict mode */
+#define CSV_ENOMEM 2 /* Out of memory while increasing buffer size */
+#define CSV_ETOOBIG 3 /* Buffer larger than SIZE_MAX needed */
+#define CSV_EINVALID 4 /* Invalid code,should never be received from csv_error*/
+
+
+/* parser options */
+#define CSV_STRICT 1 /* enable strict mode */
+#define CSV_REPALL_NL 2 /* report all unquoted carriage returns and linefeeds */
+#define CSV_STRICT_FINI 4 /* causes csv_fini to return CSV_EPARSE if last
+ field is quoted and doesn't containg ending
+ quote */
+#define CSV_APPEND_NULL 8 /* Ensure that all fields are null-ternimated */
+
+
+/* Character values */
+#define CSV_TAB 0x09
+#define CSV_SPACE 0x20
+#define CSV_CR 0x0d
+#define CSV_LF 0x0a
+#define CSV_COMMA 0x2c
+#define CSV_QUOTE 0x22
+
+struct csv_parser {
+ int pstate; /* Parser state */
+ int quoted; /* Is the current field a quoted field? */
+ size_t spaces; /* Number of continious spaces after quote or in a non-quoted field */
+ unsigned char * entry_buf; /* Entry buffer */
+ size_t entry_pos; /* Current position in entry_buf (and current size of entry) */
+ size_t entry_size; /* Size of entry buffer */
+ int status; /* Operation status */
+ unsigned char options;
+ unsigned char quote_char;
+ unsigned char delim_char;
+ int (*is_space)(unsigned char);
+ int (*is_term)(unsigned char);
+ size_t blk_size;
+ void *(*malloc_func)(size_t);
+ void *(*realloc_func)(void *, size_t);
+ void (*free_func)(void *);
+};
+
+/* Function Prototypes */
+int csv_init(struct csv_parser *p, unsigned char options);
+int csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
+void csv_free(struct csv_parser *p);
+int csv_error(struct csv_parser *p);
+char * csv_strerror(int error);
+size_t csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int, void *), void *data);
+size_t csv_write(void *dest, size_t dest_size, const void *src, size_t src_size);
+int csv_fwrite(FILE *fp, const void *src, size_t src_size);
+size_t csv_write2(void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote);
+int csv_fwrite2(FILE *fp, const void *src, size_t src_size, unsigned char quote);
+int csv_get_opts(struct csv_parser *p);
+int csv_set_opts(struct csv_parser *p, unsigned char options);
+void csv_set_delim(struct csv_parser *p, unsigned char c);
+void csv_set_quote(struct csv_parser *p, unsigned char c);
+unsigned char csv_get_delim(struct csv_parser *p);
+unsigned char csv_get_quote(struct csv_parser *p);
+void csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char));
+void csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char));
+void csv_set_realloc_func(struct csv_parser *p, void *(*)(void *, size_t));
+void csv_set_free_func(struct csv_parser *p, void (*)(void *));
+void csv_set_blk_size(struct csv_parser *p, size_t);
+size_t csv_get_buffer_size(struct csv_parser *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
View
BIN csv.pdf
Binary file not shown.
View
280 examples/LICENSE
@@ -0,0 +1,280 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
View
93 examples/csvfix.c
@@ -0,0 +1,93 @@
+/*
+csvfix - reads (possibly malformed) CSV data from input file
+ and writes properly formed CSV to output file
+
+Copyright (C) 2007 Robert Gamble
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libcsv/csv.h"
+
+void cb1 (void *s, size_t i, void *outfile) {
+ csv_fwrite((FILE *)outfile, s, i);
+ fputc(',',(FILE *)outfile);
+}
+
+void cb2 (int c, void *outfile) {
+ fseek((FILE *)outfile, -1, SEEK_CUR);
+ fputc('\n', (FILE *)outfile);
+}
+
+int main (int argc, char *argv[]) {
+ char buf[1024];
+ size_t i;
+ struct csv_parser p;
+ FILE *infile, *outfile;
+ csv_init(&p, 0);
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: csv_fix infile outfile\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!strcmp(argv[1], argv[2])) {
+ fprintf(stderr, "Input file and output file must not be the same!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ infile = fopen(argv[1], "rb");
+ if (infile == NULL) {
+ fprintf(stderr, "Failed to open file %s: %s\n", argv[1], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ outfile = fopen(argv[2], "wb");
+ if (outfile == NULL) {
+ fprintf(stderr, "Failed to open file %s: %s\n", argv[2], strerror(errno));
+ fclose(infile);
+ exit(EXIT_FAILURE);
+ }
+
+ while ((i=fread(buf, 1, 1024, infile)) > 0) {
+ if (csv_parse(&p, buf, i, cb1, cb2, outfile) != i) {
+ fprintf(stderr, "Error parsing file: %s\n", csv_strerror(csv_error(&p)));
+ fclose(infile);
+ fclose(outfile);
+ remove(argv[2]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ csv_fini(&p, cb1, cb2, outfile);
+ csv_free(&p);
+
+ if (ferror(infile)) {
+ fprintf(stderr, "Error reading from input file");
+ fclose(infile);
+ fclose(outfile);
+ remove(argv[2]);
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(infile);
+ fclose(outfile);
+ return EXIT_SUCCESS;
+}
+
View
104 examples/csvinfo.c
@@ -0,0 +1,104 @@
+/*
+csvinfo - reads CSV data from input file(s) and reports the number
+ of fields and rows encountered in each file
+
+Copyright (C) 2007 Robert Gamble
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "libcsv/csv.h"
+
+struct counts {
+ long unsigned fields;
+ long unsigned rows;
+};
+
+void cb1 (void *s, size_t len, void *data) { ((struct counts *)data)->fields++; }
+void cb2 (int c, void *data) { ((struct counts *)data)->rows++; }
+
+static int is_space(unsigned char c) {
+ if (c == CSV_SPACE || c == CSV_TAB) return 1;
+ return 0;
+}
+
+static int is_term(unsigned char c) {
+ if (c == CSV_CR || c == CSV_LF) return 1;
+ return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ FILE *fp;
+ struct csv_parser p;
+ char buf[1024];
+ size_t bytes_read;
+ unsigned char options = 0;
+ struct counts c = {0, 0};
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: csvinfo [-s] files\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (csv_init(&p, options) != 0) {
+ fprintf(stderr, "Failed to initialize csv parser\n");
+ exit(EXIT_FAILURE);
+ }
+
+ csv_set_space_func(&p, is_space);
+ csv_set_term_func(&p, is_term);
+
+ while (*(++argv)) {
+ if (strcmp(*argv, "-s") == 0) {
+ options = CSV_STRICT;
+ csv_set_opts(&p, options);
+ continue;
+ }
+
+ fp = fopen(*argv, "rb");
+ if (!fp) {
+ fprintf(stderr, "Failed to open %s: %s\n", *argv, strerror(errno));
+ continue;
+ }
+
+ while ((bytes_read=fread(buf, 1, 1024, fp)) > 0) {
+ if (csv_parse(&p, buf, bytes_read, cb1, cb2, &c) != bytes_read) {
+ fprintf(stderr, "Error while parsing file: %s\n", csv_strerror(csv_error(&p)));
+ }
+ }
+
+ csv_fini(&p, cb1, cb2, &c);
+
+ if (ferror(fp)) {
+ fprintf(stderr, "Error while reading file %s\n", *argv);
+ fclose(fp);
+ continue;
+ }
+
+ fclose(fp);
+ printf("%s: %lu fields, %lu rows\n", *argv, c.fields, c.rows);
+ }
+
+ csv_free(&p);
+ exit(EXIT_SUCCESS);
+}
+
View
63 examples/csvtest.c
@@ -0,0 +1,63 @@
+/*
+csvtest - reads CSV data from stdin and output properly formed equivalent
+ useful for testing the library
+
+Copyright (C) 2007 Robert Gamble
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libcsv/csv.h"
+
+static int put_comma;
+
+void cb1 (void *s, size_t i, void *p) {
+ if (put_comma)
+ putc(',', stdout);
+ csv_fwrite(stdout, s, i);
+ put_comma = 1;
+}
+
+void cb2 (int c, void *p) {
+ put_comma = 0;
+ putc('\n', stdout);
+}
+
+int main (void) {
+ struct csv_parser p;
+ int i;
+ char c;
+
+ csv_init(&p, 0);
+
+ while ((i=getc(stdin)) != EOF) {
+ c = i;
+ if (csv_parse(&p, &c, 1, cb1, cb2, NULL) != 1) {
+ fprintf(stderr, "Error: %s\n", csv_strerror(csv_error(&p)));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ csv_fini(&p, cb1, cb2, NULL);
+ csv_free(&p);
+
+ return EXIT_SUCCESS;
+}
+
View
78 examples/csvvalid.c
@@ -0,0 +1,78 @@
+/*
+csvvalid - determine if files are properly formed CSV files and display
+ position of first offending byte if not
+
+Copyright (C) 2007 Robert Gamble
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libcsv/csv.h"
+
+int
+main (int argc, char *argv[])
+{
+ FILE *fp;
+ int i;
+ struct csv_parser p;
+ char buf[1024];
+ size_t bytes_read;
+ size_t pos;
+ size_t retval;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: csvvalid files\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (csv_init(&p, CSV_STRICT) != 0) {
+ fprintf(stderr, "Failed to initialize csv parser\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 1; i < argc; i++) {
+ pos = 0;
+ fp = fopen(argv[i], "rb");
+ if (!fp) {
+ fprintf(stderr, "Failed to open %s: %s, skipping\n", argv[i], strerror(errno));
+ continue;
+ }
+ while ((bytes_read=fread(buf, 1, 1024, fp)) > 0) {
+ if ((retval = csv_parse(&p, buf, bytes_read, NULL, NULL, NULL)) != bytes_read) {
+ if (csv_error(&p) == CSV_EPARSE) {
+ printf("%s: malformed at byte %lu\n", argv[i], (unsigned long)pos + retval + 1);
+ goto end;
+ } else {
+ printf("Error while processing %s: %s\n", argv[i], csv_strerror(csv_error(&p)));
+ goto end;
+ }
+ }
+ pos += bytes_read;
+ }
+ printf("%s well-formed\n", argv[i]);
+
+ end:
+ fclose(fp);
+ csv_fini(&p, NULL, NULL, NULL);
+ pos = 0;
+ }
+
+ csv_free(&p);
+ return EXIT_SUCCESS;
+}
View
579 libcsv.c
@@ -0,0 +1,579 @@
+/*
+libcsv - parse and write csv data
+Copyright (C) 2008 Robert Gamble
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#if ___STDC_VERSION__ >= 199901L
+# include <stdint.h>
+#else
+# define SIZE_MAX ((size_t)-1) /* C89 doesn't have stdint.h or SIZE_MAX */
+#endif
+
+#include "csv.h"
+
+#define VERSION "3.0.0"
+
+#define ROW_NOT_BEGUN 0
+#define FIELD_NOT_BEGUN 1
+#define FIELD_BEGUN 2
+#define FIELD_MIGHT_HAVE_ENDED 3
+
+/*
+ Explanation of states
+ ROW_NOT_BEGUN There have not been any fields encountered for this row
+ FIELD_NOT_BEGUN There have been fields but we are currently not in one
+ FIELD_BEGUN We are in a field
+ FIELD_MIGHT_HAVE_ENDED
+ We encountered a double quote inside a quoted field, the
+ field is either ended or the quote is literal
+*/
+
+#define MEM_BLK_SIZE 128
+
+#define SUBMIT_FIELD(p) \
+ do { \
+ if (!quoted) \
+ entry_pos -= spaces; \
+ if (p->options & CSV_APPEND_NULL) \
+ ((p)->entry_buf[entry_pos+1]) = '\0'; \
+ if (cb1) \
+ cb1(p->entry_buf, entry_pos, data); \
+ pstate = FIELD_NOT_BEGUN; \
+ entry_pos = quoted = spaces = 0; \
+ } while (0)
+
+#define SUBMIT_ROW(p, c) \
+ do { \
+ if (cb2) \
+ cb2(c, data); \
+ pstate = ROW_NOT_BEGUN; \
+ entry_pos = quoted = spaces = 0; \
+ } while (0)
+
+#define SUBMIT_CHAR(p, c) ((p)->entry_buf[entry_pos++] = (c))
+
+static char *csv_errors[] = {"success",
+ "error parsing data while strict checking enabled",
+ "memory exhausted while increasing buffer size",
+ "data size too large",
+ "invalid status code"};
+
+int
+csv_error(struct csv_parser *p)
+{
+ /* Return the current status of the parser */
+ return p->status;
+}
+
+char *
+csv_strerror(int status)
+{
+ /* Return a textual description of status */
+ if (status >= CSV_EINVALID || status < 0)
+ return csv_errors[CSV_EINVALID];
+ else
+ return csv_errors[status];
+}
+
+int
+csv_get_opts(struct csv_parser *p)
+{
+ /* Return the currently set options of parser */
+ if (p == NULL)
+ return -1;
+
+ return p->options;
+}
+
+int
+csv_set_opts(struct csv_parser *p, unsigned char options)
+{
+ /* Set the options */
+ if (p == NULL)
+ return -1;
+
+ p->options = options;
+ return 0;
+}
+
+int
+csv_init(struct csv_parser *p, unsigned char options)
+{
+ /* Initialize a csv_parser object returns 0 on success, -1 on error */
+ if (p == NULL)
+ return -1;
+
+ p->entry_buf = NULL;
+ p->pstate = ROW_NOT_BEGUN;
+ p->quoted = 0;
+ p->spaces = 0;
+ p->entry_pos = 0;
+ p->entry_size = 0;
+ p->status = 0;
+ p->options = options;
+ p->quote_char = CSV_QUOTE;
+ p->delim_char = CSV_COMMA;
+ p->is_space = NULL;
+ p->is_term = NULL;
+ p->blk_size = MEM_BLK_SIZE;
+ p->malloc_func = NULL;
+ p->realloc_func = realloc;
+ p->free_func = free;
+
+ return 0;
+}
+
+void
+csv_free(struct csv_parser *p)
+{
+ /* Free the entry_buffer of csv_parser object */
+ if (p == NULL)
+ return;
+
+ if (p->entry_buf)
+ p->free_func(p->entry_buf);
+
+ p->entry_buf = NULL;
+ p->entry_size = 0;
+
+ return;
+}
+
+int
+csv_fini(struct csv_parser *p, void (*cb1)(void *, size_t, void *), void (*cb2)(int c, void *), void *data)
+{
+ /* Finalize parsing. Needed, for example, when file does not end in a newline */
+ int quoted = p->quoted;
+ int pstate = p->pstate;
+ size_t spaces = p->spaces;
+ size_t entry_pos = p->entry_pos;
+
+ if (p == NULL)
+ return -1;
+
+
+ if (p->pstate == FIELD_BEGUN && p->quoted && p->options & CSV_STRICT && p->options & CSV_STRICT_FINI) {
+ /* Current field is quoted, no end-quote was seen, and CSV_STRICT_FINI is set */
+ p->status = CSV_EPARSE;
+ return -1;
+ }
+
+ switch (p->pstate) {
+ case FIELD_MIGHT_HAVE_ENDED:
+ p->entry_pos -= p->spaces + 1; /* get rid of spaces and original quote */
+ /* Fall-through */
+ case FIELD_NOT_BEGUN:
+ case FIELD_BEGUN:
+ quoted = p->quoted, pstate = p->pstate;
+ spaces = p->spaces, entry_pos = p->entry_pos;
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, -1);
+ case ROW_NOT_BEGUN: /* Already ended properly */
+ ;
+ }
+
+ /* Reset parser */
+ p->spaces = p->quoted = p->entry_pos = p->status = 0;
+ p->pstate = ROW_NOT_BEGUN;
+
+ return 0;
+}
+
+void
+csv_set_delim(struct csv_parser *p, unsigned char c)
+{
+ /* Set the delimiter */
+ if (p) p->delim_char = c;
+}
+
+void
+csv_set_quote(struct csv_parser *p, unsigned char c)
+{
+ /* Set the quote character */
+ if (p) p->quote_char = c;
+}
+
+unsigned char
+csv_get_delim(struct csv_parser *p)
+{
+ /* Get the delimiter */
+ return p->delim_char;
+}
+
+unsigned char
+csv_get_quote(struct csv_parser *p)
+{
+ /* Get the quote character */
+ return p->quote_char;
+}
+
+void
+csv_set_space_func(struct csv_parser *p, int (*f)(unsigned char))
+{
+ /* Set the space function */
+ if (p) p->is_space = f;
+}
+
+void
+csv_set_term_func(struct csv_parser *p, int (*f)(unsigned char))
+{
+ /* Set the term function */
+ if (p) p->is_term = f;
+}
+
+void
+csv_set_realloc_func(struct csv_parser *p, void *(*f)(void *, size_t))
+{
+ /* Set the realloc function used to increase buffer size */
+ if (p && f) p->realloc_func = f;
+}
+
+void
+csv_set_free_func(struct csv_parser *p, void (*f)(void *))
+{
+ /* Set the free function used to free the buffer */
+ if (p && f) p->free_func = f;
+}
+
+void
+csv_set_blk_size(struct csv_parser *p, size_t size)
+{
+ /* Set the block size used to increment buffer size */
+ if (p) p->blk_size = size;
+}
+
+size_t
+csv_get_buffer_size(struct csv_parser *p)
+{
+ /* Get the size of the entry buffer */
+ if (p)
+ return p->entry_size;
+ return 0;
+}
+
+static int
+csv_increase_buffer(struct csv_parser *p)
+{
+ /* Increase the size of the entry buffer. Attempt to increase size by
+ * p->blk_size, if this is larger than SIZE_MAX try to increase current
+ * buffer size to SIZE_MAX. If allocation fails, try to allocate halve
+ * the size and try again until successful or increment size is zero.
+ */
+
+ size_t to_add = p->blk_size;
+ void *vp;
+
+ if ( p->entry_size >= SIZE_MAX - to_add )
+ to_add = SIZE_MAX - p->entry_size;
+
+ if (!to_add) {
+ p->status = CSV_ETOOBIG;
+ return -1;
+ }
+
+ while ((vp = p->realloc_func(p->entry_buf, p->entry_size + to_add)) == NULL) {
+ to_add /= 2;
+ if (!to_add) {
+ p->status = CSV_ENOMEM;
+ return -1;
+ }
+ }
+
+ /* Update entry buffer pointer and entry_size if successful */
+ p->entry_buf = vp;
+ p->entry_size += to_add;
+ return 0;
+}
+
+size_t
+csv_parse(struct csv_parser *p, const void *s, size_t len, void (*cb1)(void *, size_t, void *), void (*cb2)(int c, void *), void *data)
+{
+ unsigned const char *us = s; /* Access input data as array of unsigned char */
+ unsigned char c; /* The character we are currently processing */
+ size_t pos = 0; /* The number of characters we have processed in this call */
+
+ /* Store key fields into local variables for performance */
+ unsigned char delim = p->delim_char;
+ unsigned char quote = p->quote_char;
+ int (*is_space)(unsigned char) = p->is_space;
+ int (*is_term)(unsigned char) = p->is_term;
+ int quoted = p->quoted;
+ int pstate = p->pstate;
+ size_t spaces = p->spaces;
+ size_t entry_pos = p->entry_pos;
+
+
+ if (!p->entry_buf && pos < len) {
+ /* Buffer hasn't been allocated yet and len > 0 */
+ if (csv_increase_buffer(p) != 0) {
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+ }
+ }
+
+ while (pos < len) {
+ /* Check memory usage, increase buffer if neccessary */
+ if (entry_pos == ((p->options & CSV_APPEND_NULL) ? p->entry_size - 1 : p->entry_size) ) {
+ if (csv_increase_buffer(p) != 0) {
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+ }
+ }
+
+ c = us[pos++];
+
+ switch (pstate) {
+ case ROW_NOT_BEGUN:
+ case FIELD_NOT_BEGUN:
+ if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
+ continue;
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ if (pstate == FIELD_NOT_BEGUN) {
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else { /* ROW_NOT_BEGUN */
+ /* Don't submit empty rows by default */
+ if (p->options & CSV_REPALL_NL) {
+ SUBMIT_ROW(p, (unsigned char)c);
+ }
+ }
+ continue;
+ } else if (c == delim) { /* Comma */
+ SUBMIT_FIELD(p);
+ break;
+ } else if (c == quote) { /* Quote */
+ pstate = FIELD_BEGUN;
+ quoted = 1;
+ } else { /* Anything else */
+ pstate = FIELD_BEGUN;
+ quoted = 0;
+ SUBMIT_CHAR(p, c);
+ }
+ break;
+ case FIELD_BEGUN:
+ if (c == quote) { /* Quote */
+ if (quoted) {
+ SUBMIT_CHAR(p, c);
+ pstate = FIELD_MIGHT_HAVE_ENDED;
+ } else {
+ /* STRICT ERROR - double quote inside non-quoted field */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos-1;
+ }
+ SUBMIT_CHAR(p, c);
+ spaces = 0;
+ }
+ } else if (c == delim) { /* Comma */
+ if (quoted) {
+ SUBMIT_CHAR(p, c);
+ } else {
+ SUBMIT_FIELD(p);
+ }
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ if (!quoted) {
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else {
+ SUBMIT_CHAR(p, c);
+ }
+ } else if (!quoted && (is_space? is_space(c) : c == CSV_SPACE || c == CSV_TAB)) { /* Tab or space for non-quoted field */
+ SUBMIT_CHAR(p, c);
+ spaces++;
+ } else { /* Anything else */
+ SUBMIT_CHAR(p, c);
+ spaces = 0;
+ }
+ break;
+ case FIELD_MIGHT_HAVE_ENDED:
+ /* This only happens when a quote character is encountered in a quoted field */
+ if (c == delim) { /* Comma */
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
+ SUBMIT_FIELD(p);
+ } else if (is_term ? is_term(c) : c == CSV_CR || c == CSV_LF) { /* Carriage Return or Line Feed */
+ entry_pos -= spaces + 1; /* get rid of spaces and original quote */
+ SUBMIT_FIELD(p);
+ SUBMIT_ROW(p, (unsigned char)c);
+ } else if (is_space ? is_space(c) : c == CSV_SPACE || c == CSV_TAB) { /* Space or Tab */
+ SUBMIT_CHAR(p, c);
+ spaces++;
+ } else if (c == quote) { /* Quote */
+ if (spaces) {
+ /* STRICT ERROR - unescaped double quote */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos-1;
+ }
+ spaces = 0;
+ SUBMIT_CHAR(p, c);
+ } else {
+ /* Two quotes in a row */
+ pstate = FIELD_BEGUN;
+ }
+ } else { /* Anything else */
+ /* STRICT ERROR - unescaped double quote */
+ if (p->options & CSV_STRICT) {
+ p->status = CSV_EPARSE;
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos-1;
+ }
+ pstate = FIELD_BEGUN;
+ spaces = 0;
+ SUBMIT_CHAR(p, c);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ p->quoted = quoted, p->pstate = pstate, p->spaces = spaces, p->entry_pos = entry_pos;
+ return pos;
+}
+
+size_t
+csv_write (void *dest, size_t dest_size, const void *src, size_t src_size)
+{
+ unsigned char *cdest = dest;
+ const unsigned char *csrc = src;
+ size_t chars = 0;
+
+ if (src == NULL)
+ return 0;
+
+ if (cdest == NULL)
+ dest_size = 0;
+
+ if (dest_size > 0)
+ *cdest++ = '"';
+ chars++;
+
+ while (src_size) {
+ if (*csrc == '"') {
+ if (dest_size > chars)
+ *cdest++ = '"';
+ if (chars < SIZE_MAX) chars++;
+ }
+ if (dest_size > chars)
+ *cdest++ = *csrc;
+ if (chars < SIZE_MAX) chars++;
+ src_size--;
+ csrc++;
+ }
+
+ if (dest_size > chars)
+ *cdest = '"';
+ if (chars < SIZE_MAX) chars++;
+
+ return chars;
+}
+
+int
+csv_fwrite (FILE *fp, const void *src, size_t src_size)
+{
+ const unsigned char *csrc = src;
+
+ if (fp == NULL || src == NULL)
+ return 0;
+
+ if (fputc('"', fp) == EOF)
+ return EOF;
+
+ while (src_size) {
+ if (*csrc == '"') {
+ if (fputc('"', fp) == EOF)
+ return EOF;
+ }
+ if (fputc(*csrc, fp) == EOF)
+ return EOF;
+ src_size--;
+ csrc++;
+ }
+
+ if (fputc('"', fp) == EOF) {
+ return EOF;
+ }
+
+ return 0;
+}
+
+size_t
+csv_write2 (void *dest, size_t dest_size, const void *src, size_t src_size, unsigned char quote)
+{
+ unsigned char *cdest = dest;
+ const unsigned char *csrc = src;
+ size_t chars = 0;
+
+ if (src == NULL)
+ return 0;
+
+ if (dest == NULL)
+ dest_size = 0;
+
+ if (dest_size > 0)
+ *cdest++ = quote;
+ chars++;
+
+ while (src_size) {
+ if (*csrc == quote) {
+ if (dest_size > chars)
+ *cdest++ = quote;
+ if (chars < SIZE_MAX) chars++;
+ }
+ if (dest_size > chars)
+ *cdest++ = *csrc;
+ if (chars < SIZE_MAX) chars++;
+ src_size--;
+ csrc++;
+ }
+
+ if (dest_size > chars)
+ *cdest = quote;
+ if (chars < SIZE_MAX) chars++;
+
+ return chars;
+}
+
+int
+csv_fwrite2 (FILE *fp, const void *src, size_t src_size, unsigned char quote)
+{
+ const unsigned char *csrc = src;
+
+ if (fp == NULL || src == NULL)
+ return 0;
+
+ if (fputc(quote, fp) == EOF)
+ return EOF;
+
+ while (src_size) {
+ if (*csrc == quote) {
+ if (fputc(quote, fp) == EOF)
+ return EOF;
+ }
+ if (fputc(*csrc, fp) == EOF)
+ return EOF;
+ src_size--;
+ csrc++;
+ }
+
+ if (fputc(quote, fp) == EOF) {
+ return EOF;
+ }
+
+ return 0;
+}
View
463 test_csv.c
@@ -0,0 +1,463 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include "./csv.h"
+
+#define CSV_END 0
+#define CSV_COL 1
+#define CSV_ROW 2
+#define CSV_ERR 3
+
+#define DO_TEST(name, options) test_parser("test" #name, options, test ## name ## _data, \
+ sizeof(test ## name ## _data) - 1, test ## name ## _results, \
+ CSV_COMMA, CSV_QUOTE, NULL, NULL)
+
+#define DO_TEST_CUSTOM(name, options, d, q, s, t) test_parser("custom" #name, options, custom ## name ## _data, \
+ sizeof(custom ## name ## _data) - 1, custom ## name ## _results, d, q, s, t)
+
+struct event {
+ int event_type;
+ int retval;
+ size_t size; /* Number of bytes in this event or return value from csv_fini */
+ char *data; /* Data for this event */
+};
+
+struct event *event_ptr;
+int event_idx;
+size_t row, col;
+
+void
+fail_parser (char * test_name, char * message)
+{
+ fprintf(stderr, "Parser test %s failed on event %d: %s\n", test_name, event_idx, message);
+ exit(EXIT_FAILURE);
+}
+
+void
+fail_writer (char * test_name, char * message)
+{
+ fprintf(stderr, "Writer test %s failed: %s\n", test_name, message);
+ exit(EXIT_FAILURE);
+}
+
+void
+cb1 (void *data, size_t len, void *t)
+{
+ char * test_name = t;
+
+ /* Make sure we were expecting a column */
+ if (event_ptr->event_type != CSV_COL)
+ fail_parser(test_name, "didn't expect a column");
+
+ /* Check the actual size against the expected size */
+ if (event_ptr->size != len)
+ fail_parser(test_name, "actual data length doesn't match expected data length");
+
+ /* Check the actual data against the expected data */
+ if (memcmp(event_ptr->data, data, len) != 0)
+ fail_parser(test_name, "actual data doesn't match expected data");
+
+ event_idx++;
+ event_ptr++;
+ col++;
+}
+
+void
+cb2 (int c, void *t)
+{
+ char * test_name = t;
+
+ /* Make sure we were expecting an the end of a row */
+ if (event_ptr->event_type != CSV_ROW)
+ fail_parser(test_name, "didn't expect end of row");
+
+ /* Check that the row ended with the character we expected */
+ if (event_ptr->retval != c)
+ fail_parser(test_name, "row ended with unexpected character");
+
+ event_idx++;
+ event_ptr++;
+ col = 1;
+ row++;
+}
+
+void
+test_parser (char *test_name, unsigned char options, void *input, size_t len, struct event expected[],
+ char delimiter, char quote, int (*space_func)(unsigned char), int (*term_func)(unsigned char))
+{
+ int result = 0;
+ size_t retval;
+ struct csv_parser p;
+ size_t size;
+
+ for (size = 1; size <= len; size++) {
+ size_t bytes_processed = 0;
+ csv_init(&p, options);
+ csv_set_delim(&p, delimiter);
+ csv_set_quote(&p, quote);
+ csv_set_space_func(&p, space_func);
+ csv_set_term_func(&p, term_func);
+
+ row = col = 1;
+ event_ptr = &expected[0];
+ event_idx = 1;
+
+ do {
+ size_t bytes = size < len - bytes_processed ? size : len - bytes_processed;
+ retval = csv_parse(&p, input + bytes_processed, bytes, cb1, cb2, test_name);
+ if (retval != bytes) {
+ if (event_ptr->event_type != CSV_ERR) {
+ fail_parser(test_name, "unexpected parse error occured");
+ } else {
+ csv_free(&p);
+ return;
+ }
+ }
+ bytes_processed += bytes;
+ } while (bytes_processed < len);
+
+ result = csv_fini(&p, cb1, cb2, test_name);
+
+ if (result != 0) {
+ if (event_ptr->event_type != CSV_ERR) {
+ fail_parser(test_name, "unexpected parse error occured");
+ } else {
+ csv_free(&p);
+ return;
+ }
+ }
+
+ csv_free(&p);
+
+ if (event_ptr->event_type != CSV_END)
+ fail_parser(test_name, "unexpected end of input");
+ }
+}
+
+void
+test_writer (char * test_name, char *input, size_t input_len, char *expected, size_t expected_len)
+{
+ size_t actual_len;
+ char *temp = malloc(input_len*2 + 2);
+ if (!temp) {
+ fprintf(stderr, "Failed to allocate memory in test_writer!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ actual_len = csv_write(temp, input_len*2 + 2, input, input_len);
+ if (actual_len != expected_len)
+ fail_writer(test_name, "actual length doesn't match expected length");
+ if (memcmp(temp, expected, actual_len) != 0)
+ fail_writer(test_name, "actual data doesn't match expected data");
+}
+
+void
+test_writer2 (char * test_name, char *input, size_t input_len, char *expected, size_t expected_len, char quote)
+{
+ size_t actual_len;
+ char *temp = malloc(input_len*2 + 2);
+ if (!temp) {
+ fprintf(stderr, "Failed to allocate memory in test_writer!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ actual_len = csv_write2(temp, input_len*2 + 2, input, input_len, quote);
+ if (actual_len != expected_len)
+ fail_writer(test_name, "actual length doesn't match expected length");
+ if (memcmp(temp, expected, actual_len) != 0)
+ fail_writer(test_name, "actual data doesn't match expected data");
+}
+
+
+int main (void) {
+
+ /* Parser Tests */
+
+ /* Parser tests presented here consist of two parts:
+ 1. the raw data to be parsed as an array of char
+ 2. the behavior expected from attempting to parse the data
+
+ The latter is encapsulated into an array of struct event, each event
+ described the type of event that was expected at that point and details
+ of the event. There are four event types:
+ 1. CSV_END - signifies the successful end of parsing, no events should
+ follow in this test
+ 2. CSV_COL - signifies that a column or CSV element is expected to be
+ submitted to the appropriate callback function
+ 3. CSV_ROW - specifies the end of a row has been reached
+ 4. CSV_ERR - signifies that an error is expected at this point, no
+ further events should follow in this test
+
+ In addition to the event type, an event is also characterized by a size
+ and a data member in the event structure. The meaning of these fields
+ depends on the event type.
+
+ The size member for CSV_COL is the size of the expected data column,
+ for CSV_ROW is it the size of the terminating character which should
+ always be 1. The size for CSV_END should always be zero, for CSV_ERR
+ the size is not used.
+
+ The data member represents the actual data after parsing for a CSV_COL,
+ the terminating character for CSV_ROW (the first character of the provided
+ char array is the one used), and is not used for CSV_END or CSV_ERR, it
+ should be NULL in these cases.
+ */
+
+
+ char test01_data[] = " 1,2 , 3 ,4,5\x0d\x0a";
+ char test02_data[] = ",,,,,\x0a";
+ char test03_data[] = "\",\",\",\",\"\"";
+ char test04_data[] = "\"I call our world Flatland,\x0a"
+ "not because we call it so,\x0a"
+ "but to make its nature clearer\x0a"
+ "to you, my happy readers,\x0a"
+ "who are privileged to live in Space.\"";
+ char test05_data[] = "\"\"\"a,b\"\"\",,\" \"\"\"\" \",\"\"\"\"\" \",\" \"\"\"\"\",\"\"\"\"\"\"";
+ char test06_data[] = "\" a, b ,c \", a b c,";
+ char test07_data[] = "\" \"\" \" \" \"\" \"";
+ char test07b_data[] = "\" \"\" \" \" \"\" \"";
+ char test08_data[] = "\" abc\" "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " \", \"123\"";
+ char test09_data[] = "";
+ char test10_data[] = "a\x0a";
+ char test11_data[] = "1,2 ,3,4\x0a";
+ char test12_data[] = "\x0a\x0a\x0a\x0a";
+ char test12b_data[] = "\x0a\x0a\x0a\x0a";
+ char test13_data[] = "\"abc\"";
+ char test14_data[] = "1, 2, 3,\x0a\x0d\x0a \"4\", \x0d,";
+ char test15_data[] = "1, 2, 3,\x0a\x0d\x0a \"4\", \x0d\"\"";
+ char test16_data[] = "\"1\",\"2\",\" 3 ";
+ char test16b_data[] = "\"1\",\"2\",\" 3 ";
+ char test17_data[] = " a\0b\0c ";
+ char test18_data[] = "12345678901234567890123456789012";
+
+ /* Custom tests */
+ char custom01_data[] = "'''a;b''';;' '''' ';''''' ';' ''''';''''''";
+
+ /* |1|2|3|4|5| */
+ struct event test01_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},
+ {CSV_COL, 0, 1, "3"},
+ {CSV_COL, 0, 1, "4"},
+ {CSV_COL, 0, 1, "5"},
+ {CSV_ROW, '\x0d', 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* ||||||| */
+ struct event test02_results[] =
+ { {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, '\x0a', 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |,|,|| */
+ struct event test03_results[] =
+ { {CSV_COL, 0, 1, ","},
+ {CSV_COL, 0, 1, ","},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ struct event test04_results[] =
+ { {CSV_COL, 0, 147, "I call our world Flatland,\x0a"
+ "not because we call it so,\x0a"
+ "but to make its nature clearer\x0a"
+ "to you, my happy readers,\x0a"
+ "who are privileged to live in Space."},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |"a,b"|| "" |"" | ""|""| */
+ struct event test05_results[] =
+ { {CSV_COL, 0, 5, "\"a,b\""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 4, " \"\" "},
+ {CSV_COL, 0, 3, "\"\" "},
+ {CSV_COL, 0, 3, " \"\""},
+ {CSV_COL, 0, 2, "\"\""},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* | a, b ,c |a b c|| */
+ struct event test06_results[] =
+ { {CSV_COL, 0, 9, " a, b ,c "},
+ {CSV_COL, 0, 6, "a b c"},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* | " " " " | */
+ struct event test07_results[] =
+ { {CSV_COL, 0, 9, " \" \" \" \" "},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* Will cause error with CSV_STRICT set */
+ struct event test07b_results[] =
+ { {CSV_ERR, 0, 0, NULL} };
+
+ struct event test08_results[] =
+ { {CSV_COL, 0, 463, " abc\" "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "
+ " "},
+ {CSV_COL, 0, 3, "123"},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* empty */
+ struct event test09_results[] =
+ { {CSV_END, 0, 0, NULL} };
+
+ /* |a| */
+ struct event test10_results[] =
+ { {CSV_COL, 0, 1, "a"},
+ {CSV_ROW, '\x0a', 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |1|2|3|4| */
+ struct event test11_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},
+ {CSV_COL, 0, 1, "3"},
+ {CSV_COL, 0, 1, "4"},
+ {CSV_ROW, '\x0a', 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* empty */
+ struct event test12_results[] =
+ { {CSV_END, 0, 0, NULL} };
+
+ /* Test CSV_REPALL_NL */
+ struct event test12b_results[] =
+ { {CSV_ROW, '\x0a', 1, NULL},
+ {CSV_ROW, '\x0a', 1, NULL},
+ {CSV_ROW, '\x0a', 1, NULL},
+ {CSV_ROW, '\x0a', 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |abc| */
+ struct event test13_results[] =
+ { {CSV_COL, 0, 3, "abc"},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |1|2|3||
+ |4||
+ ||| */
+ struct event test14_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},
+ {CSV_COL, 0, 1, "3"},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, '\x0a', 1, NULL},
+ {CSV_COL, 0, 1, "4"},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, '\x0d', 1, NULL},
+ {CSV_COL, 0, 0, ""},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, -1, 0, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* |1|2|3||
+ |4||
+ || */
+ struct event test15_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},
+ {CSV_COL, 0, 1, "3"},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, '\x0a', 1, NULL},
+ {CSV_COL, 0, 1, "4"},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, '\x0d', 1, NULL},
+ {CSV_COL, 0, 0, ""},
+ {CSV_ROW, -1, 0, NULL}, {CSV_END, 0, 0, NULL} };
+
+
+ /* |1|2| 3 | */
+ struct event test16_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},
+ {CSV_COL, 0, 3, " 3 "},
+ {CSV_ROW, -1, 1, NULL}, {CSV_END, 0, 0, NULL} };
+
+ /* Will cause an error with CSV_STRICT_FINI set */
+ struct event test16b_results[] =
+ { {CSV_COL, 0, 1, "1"},
+ {CSV_COL, 0, 1, "2"},