summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS7
-rw-r--r--COPYING503
-rw-r--r--ChangeLog5
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am4
-rw-r--r--NEWS20
-rw-r--r--README207
-rwxr-xr-xautogen.sh15
-rw-r--r--common/types.h87
-rw-r--r--config.h.in87
-rw-r--r--configure.ac31
-rw-r--r--doc/Makefile.am16
-rw-r--r--src/Makefile.am11
-rw-r--r--src/vf_access.c661
-rw-r--r--src/vf_access_calendar.c528
-rw-r--r--src/vf_access_wrappers.c541
-rw-r--r--src/vf_config.h85
-rw-r--r--src/vf_create_object.c158
-rw-r--r--src/vf_delete.c327
-rw-r--r--src/vf_internals.h223
-rw-r--r--src/vf_malloc.c270
-rw-r--r--src/vf_malloc.h166
-rw-r--r--src/vf_malloc_stdlib.c392
-rw-r--r--src/vf_malloc_stdlib.h90
-rw-r--r--src/vf_modified.c159
-rw-r--r--src/vf_modified.h84
-rw-r--r--src/vf_parser.c1182
-rw-r--r--src/vf_reader.c277
-rw-r--r--src/vf_search.c457
-rw-r--r--src/vf_string_arrays.c435
-rw-r--r--src/vf_string_arrays.h177
-rw-r--r--src/vf_strings.c472
-rw-r--r--src/vf_strings.h230
-rw-r--r--src/vf_writer.c616
-rw-r--r--stamp-h.in0
-rw-r--r--test/Makefile.am7
-rw-r--r--test/tests/access/access_1.vcf17
-rw-r--r--test/tests/adhoc/group_1.vcf6
-rw-r--r--test/tests/adhoc/group_2.vcf9
-rw-r--r--test/tests/adhoc/group_3.vcf13
-rw-r--r--test/tests/adhoc/group_4.vcf16
-rw-r--r--test/tests/adhoc/group_5.vcf16
-rw-r--r--test/tests/adhoc/group_6.vcf23
-rw-r--r--test/tests/adhoc/group_7.vcf46
-rw-r--r--test/tests/adhoc/mail_list_1.vcf4
-rw-r--r--test/tests/adhoc/mail_list_2.vcf4
-rw-r--r--test/tests/adhoc/mail_list_3.vcf3
-rw-r--r--test/tests/adhoc/mail_list_4.vcf13
-rw-r--r--test/tests/adhoc/mail_list_5.vcf19
-rw-r--r--test/tests/adhoc/mail_list_6.vcf4
-rw-r--r--test/tests/adhoc/multiple_objs_1.vcf21
-rw-r--r--test/tests/adhoc/straight_1.vcf2
-rw-r--r--test/tests/adhoc/straight_2.vcf3
-rw-r--r--test/tests/adhoc/straight_3.vcf3
-rw-r--r--test/tests/adhoc/straight_4.vcf3
-rw-r--r--test/tests/adhoc/straight_5.vcf3
-rw-r--r--test/tests/adhoc/straight_6.vcf3
-rw-r--r--test/tests/adhoc/straight_7.vcf3
-rw-r--r--test/tests/adhoc/straight_8.vcf4
-rw-r--r--test/tests/adhoc/straight_9.vcf4
-rw-r--r--test/tests/adhoc/straight_A.vcf7
-rw-r--r--test/tests/adhoc/straight_B.vcf4
-rw-r--r--test/tests/adhoc/straight_C.vcf4
-rw-r--r--test/tests/adhoc/straight_D.vcf4
-rw-r--r--test/tests/adhoc/straight_E.vcf4
-rw-r--r--test/tests/adhoc/straight_F.vcf5
-rw-r--r--test/tests/adhoc/straight_G.vcf8
-rw-r--r--test/tests/adhoc/straight_H.vcf11
-rw-r--r--test/tests/adhoc/straight_I.vcf12
-rw-r--r--test/tests/adhoc/straight_qp_1.vcf3
-rw-r--r--test/tests/adhoc/straight_qp_2.vcf3
-rw-r--r--test/tests/adhoc/straight_qp_3.vcf5
-rw-r--r--test/tests/adhoc/straight_qp_4.vcf5
-rw-r--r--test/tests/adhoc/vcal_1.vcs20
-rw-r--r--test/tests/spec/2_1_1-begin-1.vcf3
-rw-r--r--test/tests/spec/2_1_1-begin-2.vcf23
-rw-r--r--test/tests/spec/2_1_2-property.vcf7
-rw-r--r--test/tests/spec/2_1_3-delimiters.vcf7
-rw-r--r--test/tests/spec/2_1_4_1-grouping-nested.vcf9
-rw-r--r--test/tests/spec/2_1_4_1-grouping-sequential.vcf9
-rw-r--r--test/tests/spec/2_1_4_2-property-grouping.vcf4
-rw-r--r--test/tests/spec/2_1_6-charset.vcf3
-rw-r--r--test/tests/spec/2_1_7-language.vcf3
-rw-r--r--test/tests/spec/2_1_8-valuelocation.vcf4
-rw-r--r--test/tests/spec/2_2_1-fn.vcf3
-rw-r--r--test/tests/spec/2_2_2-name.vcf4
-rw-r--r--test/tests/spec/2_2_3-photo.vcf7
-rw-r--r--test/tests/spec/2_2_4-birthdate.vcf4
-rw-r--r--test/tests/spec/2_3_1-address.vcf3
-rw-r--r--test/tests/spec/2_3_2-label.vcf12
-rw-r--r--test/tests/spec/2_4_1-tel.vcf3
-rw-r--r--test/tests/spec/2_4_2-email.vcf16
-rw-r--r--test/tests/spec/2_4_3-mailer.vcf3
-rw-r--r--test/tests/spec/2_4_5-tz.vcf4
-rw-r--r--test/tests/spec/2_4_6-geo.vcf3
-rw-r--r--test/tests/spec/2_5_1-title.vcf3
-rw-r--r--test/tests/spec/2_5_2-role.vcf3
-rw-r--r--test/tests/spec/2_5_3-logo.vcf6
-rw-r--r--test/tests/spec/2_5_4-agent.vcf9
-rw-r--r--test/tests/spec/2_5_5-org.vcf3
-rw-r--r--test/tests/spec/2_6_1-comment.vcf6
-rw-r--r--test/tests/spec/2_6_2-revision.vcf4
-rw-r--r--test/tests/spec/2_6_3-sound.vcf8
-rw-r--r--test/tests/spec/2_6_4-url.vcf3
-rw-r--r--test/tests/spec/2_6_5-uid.vcf3
-rw-r--r--test/tests/utf-8/S15cx8.vcf352
-rw-r--r--test/tests/utf-8/S15cxu.vcf6
-rw-r--r--test/testsuppt.c409
-rw-r--r--test/testsuppt.h211
-rw-r--r--test/vformat.c858
-rw-r--r--vf_iface.h35
-rw-r--r--vformat/Makefile.am2
-rw-r--r--vformat/vf_iface.h1269
113 files changed, 12373 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..6ee2191
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+Main author of vformat
+
+Nick <Tilda@indigo8.freeserve.co.uk>
+
+Porting to Linux
+
+Mathias Palm <Mathias.Palm@gmx.net> \ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..1691fad
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,503 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+^L
+ 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.
+^L
+ 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.
+^L
+ 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.
+^L
+ 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.
+^L
+ 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.
+^L
+ 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.
+^L
+ 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
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Main author of vformat
+
+Nick <Tilda@indigo8.freeserve.co.uk>
+
+Porting to Linux
+
+Mathias Palm <Mathias.Palm@gmx.net>
+
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..4fe7df9
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,5 @@
+2002-11-22 Mathias Palm <mathias.palm@gmx.net>
+
+ * manpages are generated from the header file and installed
+
+see README \ No newline at end of file
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..9ea4543
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src vformat test doc
+
+EXTRA_DIST = common/types.h vf_iface.h
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..c35d277
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,20 @@
+Posted By: tilda
+Date: 2001-12-16 10:19
+Summary:Alpha 5
+
+Alpha-5 is here!
+
+This is mostly a bugfix release over Alpha-4, new functionality will go into Alpha-6, which may be the last Alpha.
+
+Please note that from Alpha-5 onwards you will need DevIL from SourceForge.
+
+
+Cheers,
+
+Nick
+
+Posted By: tilda
+Date: 2001-10-24 13:47
+Summary:Alpha-2
+
+Well; Alpha-2 is here - this is about as exciting as it gets isn't it... \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..d27d423
--- /dev/null
+++ b/README
@@ -0,0 +1,207 @@
+/-----------------------------------------------------------------------------
+| $Log: README,v $
+| Revision 1.1 2002/10/11 14:08:59 monos
+| *** empty log message ***
+|
+| Revision 1.13 2001/12/28 17:29:29 tilda
+| Minor tidy ups after updating to DevIL-1.2.4
+|
+| Revision 1.12 2001/12/16 16:01:15 tilda
+| Update release notes before Alpha-5
+|
+| Revision 1.11 2001/12/10 09:28:35 tilda
+| Typo.
+|
+| Revision 1.10 2001/12/10 09:21:47 tilda
+| Describe image librrary build options.
+|
+| Revision 1.9 2001/12/02 21:20:25 tilda
+| Update prior to Alpha-4
+|
+| Revision 1.8 2001/11/27 18:32:59 tilda
+| Reword LICENCING section in README.txt. Move docs into vformatl.dsp
+|
+\-----------------------------------------------------------------------------
+
+Welcome to the vFormat Library!
+
+LICENCE
+=======
+
+All this software (the library and the demo apps) is distributed under the
+GNU Lesser General Public Licence. A copy of this is distributed with the
+library - see the file LICENCE.txt in the libraries root directory.
+
+Please read and understand the comments at the top of vf_iface.h before use.
+
+
+RELEASES
+========
+This will be considered "alpha" until all the features I think should be
+there are there. It'll be "beta" until I know of no outstanding issues.
+Release history:
+
+Alpha-1 : first cut at a release, known problems with BASE64, no create/modify API
+
+Alpha-2 : BASE64 encoding fixed, first pass at create/modify functionality
+
+Alpha-3 : including first usable version of vfedit demo app
+
+Alpha-4 : Add basic framework support for vCalendar to VFEDIT. Sort out tools menu
+ and font manager. Fix IIDs 485069, 485071, 488003, 484956, 488006, 488011.
+ Sort out various bugs in IMGHLP DLLs.
+
+Alpha-5 : Various bug fixes and move to use of a image library (DevIL from SourceForge)
+ rather than various dodgy home-grown bits'n'pieces. Fix IIDs 484685, 491475
+ 489753, 484684, 488021, 484958, 484844, 484843. vfedit now reasonably usable
+ (for VCARDs).
+
+
+BUILDING
+========
+
+Under Windows, the build uses Microsoft's Visual C++ version 6.0 - the
+project & workspace files are included in the distribution. The workspace
+at .../build/vformat/vformat.dsw references will build and install the
+library (ie. the .DLL) and builds the test harness. In detail:
+
+ .../build/vformat/vformat.dsw - workspace including other project files
+ .../build/vformatl/vformatl.dsp - builds (and installs) DLL version
+ .../build/tools - various tools & utilities
+
+ .../build/vfdisplay - minimal app enumerating contents of a vobject
+ .../build/vfedit - demo app supporting VCARDs & VCALENDARs.
+
+Beware - vformatl.dsp and the other DSPs will install the DLLs in your
+windows/system directory using the INSDLL.BAT file in the tools directory
+which is invoked as a post-build step (see the post-build tab on the
+projects/settings dialog). If you don't like this, delete the post
+build step or edit the script to put the DLL somewhere else.
+
+
+
+IMAGE LIBRARY
+=============
+Imaging formats (.JPG etc) are handled in the demo applications using a 3rd party
+open source image library. Early releases of VFEDIT used various bits of garbage
+I'd collected over the years wrapped up in an .DLL (deliberately hiding the crap).
+
+As of Alpha-5, VFEDIT includes support for DevIL - the Developer's Image Libray.
+Details of this can be found at http://OpenIL.sourceforge.net.
+
+To enable image support you need to download & install DevIL and change the line
+at the top of ImageManager.cpp to #define USE_IMAGE_LIBRARY (rather than #undef).
+
+Here are the instructions to get a basic version of this going, this is based on
+the install instructions included in DevIL & various things about my machine. The
+basic version supports .BMP files, I've not (yet) got round to adding .JPG etc to
+my build of DevIL.
+
+ - download DevIL-1.2.4.zip from the page in SourceForge.
+ - unpack the .ZIP file somewhere convenient eg. D:\DevIL
+ - change your global include paths (eg. Tools->Options->Directories in MSVC6)
+ to include DevIL's include dirs (eg. D:\DevIL\ImageLib\Include)
+ - change your global library paths to include DevIL's include dirs
+ (eg. D:\DevIL\ImageLib\lib and D:\DevIL\ImageLib\lib\debug)
+ - change the post build steps as appropriate for your system
+ - uncomment IL_NO_GIF, IL_NO_JPG, IL_NO_MNG, IL_NO_PNG, IL_NO_TIF
+ - uncomment IL_NO_LCMS and comment out ilApplyProfile from IL.DEF
+ - comment out ILUT_USE_DIRECTX8 in il/ilut.h (I don't have it installed)
+ - comment out ilutD3D8LoadSurface ... ilutD3D8VolTexFromResource from ILUT.def
+ - change the USE_IMAGE_LIBRARY #define in ImageManager.cpp
+
+
+
+
+REFERENCES
+==========
+[1] vCard, The Electronic Business Card Version 2.1 from Versit.
+
+
+OUTSTANDING ISSUES
+==================
+
+After Alpha-4, this section transferred to the SourceForge database.
+
+
+THE TEST HARNESS
+================
+
+Running the test harness will produce a load of output similar to
+the following:
+
+--tests//adhoc//straight_qp_4.vcf------------------------------------------
+Successfully read file 'tests//adhoc//straight_qp_4.vcf'
+Successfully wrote file 'vobject.vcf'
+Successfully wrote file 'tests//adhoc//straight_qp_4.out-1'
+ Sizes difference :
+ tests//adhoc//straight_qp_4.out-1 (139 bytes) Vs.
+ tests//adhoc//straight_qp_4.vcf (151 bytes)
+ Warning - differences after 1st read/write
+Successfully read file 'tests//adhoc//straight_qp_4.out-1'
+Successfully wrote file 'tests//adhoc//straight_qp_4.out-2'
+ OK - no differences after 2nd read/write
+ [60 tests, 0 errors, 13 warnings]
+
+What does it all mean? All the warnings are a result of size differences
+between the original file & the result of reading/writing the file back.
+The size differences are a result of:
+ * slightly different conventions for line length
+ * line ends (eg <LF> not <CR><LF>)
+ * different selection of quoted chars in QP format
+ * excess whitespace at the end of the file
+ * characters ignored before the first BEGIN: or between END: and BEGIN:
+
+Each such difference is clocked up as a warning. The [...] stuff is
+a rolling count of tests, errors & warnings. An error is logged if
+after the file is "canonicalised" (well; into the format assumed by
+this library anyway) we fail to read & write and get the same output.
+
+The files in tests/spec are named after sections of the (very fine)
+vcard 2.1 specification eg. 2_1_4_1-grouping-sequential.vcf will refer
+to something like "sequential grouping" in section 2.1.4.1 of the
+Versit doc (see http://www.imc.org/pdi/ for the docs).
+
+(There is no intention to infringe the copyright anyone might consider
+they have vested in the text of these examples)
+
+The files in tests/adhoc are just sample scripts I knocked up
+during development.
+
+
+FUTURE PLANS
+============
+
+1) Convert this document to some decent on-line docs on the project website.
+
+2) Write a vobjects library .../src/vobjects & .../build/vobjectsl which
+ provides C++ classes modelling a vformat object with derived classes
+ for vCard, vNote etc. Functions on the base class provide file handling
+ and change logs. Functions on the derived classes handle a user's
+ normal interaction with the relevant objects eg:
+
+ typedef enum
+ {
+ Work,
+ Home,
+ Cellular,
+ Mobile = Cellular
+ }
+ vf_phone_type_t;
+
+ bool_t vformat::vcard::set_phone_no(
+ vf_phone_type_t t, /* Type of phone number */
+ bool_t is_pref, /* Should this entry be given the PREF flag? */
+ const char *phone_no /* The phone number itself */
+ );
+
+4) Duplicate the MFC app as a GTK app.
+
+
+
+CREDITS
+=======
+
+Enjoy!
+
+Nick <Tilda@indigo8.freeserve.co.uk>
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..3292973
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+gprefix=`which glibtoolize 2>&1 >/dev/null`
+if [ $? -eq 0 ]; then
+ glibtoolize --force
+else
+ libtoolize --force
+fi
+aclocal -I m4
+autoheader
+automake --add-missing
+autoconf
+
+if [ -z "$NOCONFIGURE" ]; then
+ ./configure "$@"
+fi
diff --git a/common/types.h b/common/types.h
new file mode 100644
index 0000000..7eed375
--- /dev/null
+++ b/common/types.h
@@ -0,0 +1,87 @@
+/*******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.5 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ In the abscence of suitable typedefs provided by whatever environment you're
+ building under, this defines the minimal set of types required by vformat library.
+
+MODIFICATION HISTORY
+ * $Log: types.h,v $
+ * Revision 1.5 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.4 2002/10/08 20:23:16 tilda
+ * Improve comments. Tidy header.
+ *
+ * Revision 1.3 2002/10/08 20:20:10 tilda
+ * Comments (!). Removed unused types.
+ *******************************************************************************/
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#ifndef NORCSID
+static const char _types_h_vss_id[] = "$Header: /cvsroot/vformat/src/common/types.h,v 1.5 2002/11/15 09:15:00 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+
+#undef NULL
+#define NULL 0
+
+#undef FALSE
+#define FALSE ((bool_t)(0))
+
+#undef TRUE
+#define TRUE ((bool_t)(1))
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+
+/*
+ * Basic types.
+ */
+#if defined(USE_INTTYPES_H)
+#include <inttypes.h>
+#else
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned long int uint32_t;
+#endif
+
+/*
+ * Please avoide 'BOOL' (from Windows) and 'bool' (from C++) - vformat is used
+ * extensively in pure C embedded applications where neither are relevant.
+ */
+typedef unsigned char bool_t;
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_TYPES_H_*/
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..54168ab
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,87 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the `atexit' function. */
+#undef HAVE_ATEXIT
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+#undef HAVE_STAT_EMPTY_STRING_BUG
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..d1b1041
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,31 @@
+# Process this file with autoconf to produce a configure script.
+AC_INIT(libvformat, 1.13, Nick <Tilda@indigo8.freeserve.co.uk>)
+AC_CONFIG_SRCDIR([vf_iface.h])
+#AC_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE(libvformat, 1.13)
+AM_CONFIG_HEADER(config.h)
+
+# Checks for programs.
+# AC_PROG_CC
+
+# Checks for libraries.
+AC_PROG_RANLIB
+AC_PROG_LIBTOOL
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h string.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_STRUCT_TM
+
+# Checks for library functions.
+AC_FUNC_MKTIME
+AC_FUNC_STAT
+AC_CHECK_FUNCS([atexit memset strstr])
+
+AC_OUTPUT([Makefile src/Makefile vformat/Makefile test/Makefile doc/Makefile])
+AC_CONFIG_FILES([])
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..57591c5
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,16 @@
+# No automatisation found. Write me if any idea.
+
+install-data-hook:
+ c2man -P "gcc -E -C -I.." ../vformat/vf_iface.h
+
+ $(mkinstalldirs) $(mandir)/man3
+
+ for i in *.3; do \
+ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
+ else file=$$i; fi; \
+ ext=`echo $$i | sed -e 's/^.*\\.//'`; \
+ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
+ inst=`echo $$inst | sed '$(transform)'`.$$ext; \
+ echo " $(INSTALL_DATA) $$file $(mandir)/man3/$$inst"; \
+ $(INSTALL_DATA) $$file $(mandir)/man3/$$inst; \
+ done
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..19b2d85
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,11 @@
+lib_LTLIBRARIES = libvformat.la
+
+libvformat_la_SOURCES = vf_access.c vf_malloc.c vf_strings.c vf_access_wrappers.c \
+ vf_parser.c vf_writer.c vf_create_object.c \
+ vf_access_calendar.c vf_reader.c vf_delete.c \
+ vf_search.c vf_malloc_stdlib.c vf_modified.c vf_string_arrays.c
+
+EXTRA_DIST = *.h
+
+libvformat_la_LDFLAGS = -version-info 0
+
diff --git a/src/vf_access.c b/src/vf_access.c
new file mode 100644
index 0000000..7504150
--- /dev/null
+++ b/src/vf_access.c
@@ -0,0 +1,661 @@
+/****************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Revision: 1.23 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Core access functions for VF_OBJECT_Ts. The library includes other access
+ functions (see vf_access_wrappers.c) which are often just alternative slightly
+ higher level versions of what's found below.
+
+ The intention is to provide a basic interface which covers all the required
+ functionality and also some quick'n'easy functions which can be used but don't
+ bloat the code (in a static library build anyway).
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_access.c,v $
+ * Revision 1.23 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.22 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.21 2002/11/02 08:56:17 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.20 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.19 2002/10/08 21:45:06 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.18 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.17 2002/02/24 17:10:34 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.16 2002/01/06 16:18:48 tilda
+ * Add dialog box for events / todos.
+ *
+ * Revision 1.15 2001/11/18 21:45:58 tilda
+ * Ensure parameters changed to QP are updated correctly.
+ *
+ * Revision 1.14 2001/11/17 17:40:29 tilda
+ * Image / sound dialog box now works.
+ *
+ * Revision 1.13 2001/11/05 21:07:20 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.12 2001/10/24 18:36:06 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.11 2001/10/24 05:30:39 tilda
+ * Start work on object create/modify API.
+ *
+ * Revision 1.10 2001/10/16 05:50:53 tilda
+ * Debug support for lists of vobjects from single file (ie. a phonebook).
+ *
+ * Revision 1.9 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.8 2001/10/14 16:40:05 tilda
+ * Initial testing of access functions.
+ *
+ * Revision 1.7 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.6 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.5 2001/10/13 14:49:30 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ * Revision 1.4 2001/10/12 16:20:03 tilda
+ * Correctly parse compound quoted printable properties.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *****************************************************************************/
+
+#ifndef NORCSID
+static const char vf_access_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_access.c,v 1.23 2002/11/03 18:43:16 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+/*===========================================================================*
+ Interface Header Files
+ *===========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*===========================================================================*
+ Local Header File
+ *===========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+#include "vf_modified.h"
+
+/*===========================================================================*
+ Public Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Defines
+ *===========================================================================*/
+
+#define MAXINCREMENT (5)
+#define MAXNUMTAGS (10)
+
+/*===========================================================================*
+ Private Data Types
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Function Prototypes
+ *===========================================================================*/
+
+static bool_t strings_valid_index(
+ VPROP_T *p_vprop, /* The property */
+ uint32_t n_string /* Index required */
+ );
+
+static bool_t ensure_value_encoding_tag(
+ VPROP_T *p_vprop, /* The property */
+ vf_encoding_t encoding /* Encoding required */
+ );
+
+static bool_t set_prop_value_string(
+ VPROP_T *p_vprop, /* The property */
+ uint32_t n_string, /* Index required */
+ const char *p_string /* String required */
+ );
+
+static bool_t set_prop_value_base64(
+ VPROP_T *p_vprop, /* The property */
+ const uint8_t *p_data, /* Pointer to the binary data */
+ uint32_t length, /* Length of the binary data */
+ bool_t copy /* Copy or keep pointer */
+ );
+
+
+
+
+/*===========================================================================*
+ Private Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Public Function Implementations
+ *===========================================================================*/
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_name()
+ *
+ * DESCRIPTION
+ * Build the property name string in the indicated buffer.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+void vf_get_prop_name(
+ VF_PROP_T *p_prop, /* The property */
+ char *p_buffer, /* The buffer */
+ uint32_t bufsize /* Size of the buffer */
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ uint32_t i;
+
+ if (p_vprop->p_group)
+ {
+ p_strcpy(p_buffer, p_vprop->p_group);
+ p_strcat(p_buffer, ".");
+ }
+ else
+ {
+ p_buffer[0] = '\0';
+ }
+
+ for (i = 0;i < p_vprop->name.n_strings;i++)
+ {
+ if (0 < i)
+ p_strcat(p_buffer, ";");
+
+ if (p_vprop->name.pp_strings[i])
+ {
+ p_strcat(p_buffer, p_vprop->name.pp_strings[i]);
+ }
+ }
+}
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_object_type()
+ *
+ * DESCRIPTION
+ * Return the type string identifying the indicated vformat object.
+ *
+ * RETURNS
+ * Ptr to string.
+ *---------------------------------------------------------------------------*/
+
+const char *vf_get_object_type(
+ VF_OBJECT_T *p_object
+ )
+{
+ const char *p_ret = NULL;
+
+ if (p_object)
+ {
+ p_ret = ((VOBJECT_T *)p_object)->p_type;
+ }
+
+ return p_ret;
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value()
+ *
+ * DESCRIPTION
+ * Get hold of raw fields associated with the property. These are of
+ * various types:
+ *
+ * VF_ENC_VOBJECT
+ * - *pp_value = pointer to contained VF_OBJECT_T which can be
+ * passed back to any of the object manipulation functions.
+ *
+ * VF_ENC_7BIT, VF_ENC_QUOTEDPRINTABLE
+ * - *pp_value = ptr to array of char*, *p_size = number of elts.
+ *
+ * VF_ENC_8BIT, VF_BASE64
+ * - *pp_value = ptr to bytes, *p_size = number of bytes
+ *
+ * RETURNS
+ * TRUE <=> encoding is valid, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_prop_value(
+ VF_PROP_T *p_prop, /* The property */
+ void **pp_value, /* Pointer value */
+ uint32_t *p_size, /* Integer value */
+ vf_encoding_t *p_encoding /* Type of return values */
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ bool_t ret = TRUE;
+
+ switch (p_vprop->value.encoding)
+ {
+ case VF_ENC_VOBJECT:
+ if (pp_value)
+ {
+ *pp_value = p_vprop->value.v.o.p_object;
+ }
+ break;
+
+ case VF_ENC_7BIT:
+ case VF_ENC_QUOTEDPRINTABLE:
+ if (pp_value)
+ {
+ *pp_value = p_vprop->value.v.s.pp_strings;
+ }
+ if (p_size)
+ {
+ *p_size = p_vprop->value.v.s.n_strings;
+ }
+ break;
+
+ case VF_ENC_8BIT:
+ case VF_ENC_BASE64:
+ if (pp_value)
+ {
+ *pp_value = p_vprop->value.v.b.p_buffer;
+ }
+ if (p_size)
+ {
+ *p_size = p_vprop->value.v.b.n_bufsize;
+ }
+ break;
+
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ if (p_encoding)
+ {
+ *p_encoding = p_vprop->value.encoding;
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value()
+ *
+ * DESCRIPTION
+ * Set values associated with a property.
+ *
+ * Passing a value of encoding not the same as the current property
+ * encoding will cause the property contents to be freed prior to
+ * setting the indicated value.
+ *
+ * RETURNS
+ * TRUE <=> re-allocation success & encoding correct, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_value(
+ VF_PROP_T *p_prop, /* The property */
+ void *p_value, /* Pointer to the data */
+ uint32_t n_param, /* Data size or index */
+ vf_encoding_t encoding, /* Encoding in use */
+ bool_t copy /* Copy the data? */
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ bool_t ret = TRUE;
+
+ if (!copy)
+ return FALSE;
+
+ if (encoding == p_vprop->value.encoding)
+ {
+ /* Leave it as is */
+ }
+ else
+ {
+ delete_prop_contents(p_prop, FALSE);
+
+ ensure_value_encoding_tag(p_vprop, encoding);
+ }
+
+ switch (p_vprop->value.encoding)
+ {
+ case VF_ENC_VOBJECT:
+ {
+ if (p_vprop->value.v.o.p_object != p_value)
+ {
+ mark_property_modified(p_vprop, TRUE);
+ }
+
+ p_vprop->value.v.o.p_object = p_value;
+ }
+ break;
+
+ case VF_ENC_7BIT:
+ case VF_ENC_QUOTEDPRINTABLE:
+ {
+ ret = set_prop_value_string(p_vprop, n_param, p_value);
+ }
+ break;
+
+ case VF_ENC_8BIT:
+ case VF_ENC_BASE64:
+ {
+ ret = set_prop_value_base64(p_vprop, p_value, n_param, copy);
+ }
+ break;
+
+ default:
+ ret = FALSE;
+ break;
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*===========================================================================*
+ Private Function Implementations
+ *===========================================================================*/
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * set_prop_value_string()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t set_prop_value_string(
+ VPROP_T *p_vprop,
+ uint32_t n_string,
+ const char *p_string
+ )
+{
+ bool_t ret = FALSE;
+
+ if (strings_valid_index(p_vprop, n_string))
+ {
+ if ((p_vprop->value.v.s.pp_strings[n_string] && !p_string) ||
+ (!p_vprop->value.v.s.pp_strings[n_string] && p_string) ||
+ (p_vprop->value.v.s.pp_strings[n_string] && p_string &&
+ p_stricmp(p_vprop->value.v.s.pp_strings[n_string], p_string)))
+ {
+ mark_property_modified(p_vprop, TRUE);
+ }
+
+ ret = set_string_array_entry(&(p_vprop->value.v.s), p_string, n_string);
+ }
+
+ return ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * set_prop_value_base64()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t set_prop_value_base64(
+ VPROP_T *p_vprop,
+ const uint8_t *p_data, /* Pointer to the binary data */
+ uint32_t length, /* Length of the binary data */
+ bool_t copy /* Copy or keep pointer */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (copy)
+ {
+ p_vprop->value.v.b.p_buffer = vf_malloc(length);
+
+ if (p_vprop->value.v.b.p_buffer)
+ {
+ p_memcpy(p_vprop->value.v.b.p_buffer, p_data, length);
+ p_vprop->value.v.b.n_bufsize = length;
+
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /* TBD */
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * strings_valid_index()
+ *
+ * DESCRIPTION
+ * Check request for indicated string. If it's either in the current
+ * object or represents a reasonable exapansion the request is allowed.
+ *
+ * RETURNS
+ * TRUE <=> object can include indicated string.
+ *---------------------------------------------------------------------------*/
+
+bool_t strings_valid_index(
+ VPROP_T *p_vprop,
+ uint32_t n_string
+ )
+{
+ bool_t ret = FALSE;
+
+ if (n_string < p_vprop->value.v.s.n_strings)
+ {
+ /* String in current extent of object */
+
+ ret = TRUE;
+ }
+ else
+ if ((p_vprop->value.v.s.n_strings <= n_string) && (n_string < p_vprop->value.v.s.n_strings + MAXINCREMENT))
+ {
+ /* Set string within reasonable expansion of object */
+
+ void *p_tmp = vf_realloc(p_vprop->value.v.s.pp_strings, (1 + n_string) * sizeof(char *));
+
+ if (p_tmp)
+ {
+ uint32_t i;
+
+ p_vprop->value.v.s.pp_strings = p_tmp;
+
+ for (i = p_vprop->value.v.s.n_strings;i < (uint32_t)(1 + n_string);i++)
+ {
+ p_vprop->value.v.s.pp_strings[i] = NULL;
+ }
+
+ p_vprop->value.v.s.n_strings = (1 + n_string);
+
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /* Invalid request */
+ }
+
+ return ret;
+}
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * ensure_value_encoding_tag()
+ *
+ * DESCRIPTION
+ * Check/set encoding.
+ *
+ * RETURNS
+ * TRUE <=> encoding was set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t ensure_value_encoding_tag(
+ VPROP_T *p_vprop,
+ vf_encoding_t encoding
+ )
+{
+ int n;
+ uint32_t i;
+ bool_t ret = TRUE;
+
+ /*
+ * Locate the encoding value.
+ */
+ for (i = 0, n = (-1);n == (-1) && (i < p_vprop->name.n_strings);i++)
+ {
+ const char *p_string = p_vprop->name.pp_strings[i];
+
+ if (p_string)
+ {
+ if (p_stristr(p_string, VFP_ENCODING)
+ || p_stristr(p_string, VFP_QUOTEDPRINTABLE)
+ || p_stristr(p_string, VFP_BASE64)
+ || p_stristr(p_string, VFP_8BIT)
+ || p_stristr(p_string, VFP_7BIT))
+ {
+ n = i;
+ }
+ }
+ }
+
+ /*
+ * Remove previous encoding
+ */
+ if (0 <= n)
+ {
+ ret = set_string_array_entry(&(p_vprop->name), NULL, n);
+ }
+
+ if (ret)
+ {
+ char *p_enc_string;
+
+ switch (encoding)
+ {
+ case VF_ENC_QUOTEDPRINTABLE:
+ p_enc_string = VFP_QUOTEDPRINTABLE;
+ break;
+
+ case VF_ENC_BASE64:
+ p_enc_string = VFP_BASE64;
+ break;
+
+ default:
+ p_enc_string = NULL;
+ }
+
+ if (p_enc_string)
+ {
+ if ((-1) == n)
+ {
+ ret = add_string_to_array(&(p_vprop->name), p_enc_string);
+ }
+ else
+ {
+ ret = set_string_array_entry(&(p_vprop->name), p_enc_string, n);
+ }
+ }
+ }
+
+ if (ret)
+ {
+ p_vprop->value.encoding = encoding;
+ }
+
+ return ret;
+}
+
+
+/*===========================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_access_calendar.c b/src/vf_access_calendar.c
new file mode 100644
index 0000000..159c432
--- /dev/null
+++ b/src/vf_access_calendar.c
@@ -0,0 +1,528 @@
+/****************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_access.c $
+ $Revision: 1.7 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Wrappers on the core access functions & other utility functions.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_access_calendar.c,v $
+ * Revision 1.7 2002/11/24 14:26:22 tilda
+ * IID484686 - More vcard work.
+ *
+ * Revision 1.6 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.5 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.4 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.3 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.2 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.1 2002/01/06 16:18:48 tilda
+ * Add dialog box for events / todos.
+ *
+ *****************************************************************************/
+
+#ifndef NORCSID
+static const char vf_access_calendar_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_access_calendar.c,v 1.7 2002/11/24 14:26:22 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <ctype.h>
+
+/*===========================================================================*
+ Interface Header Files
+ *===========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*===========================================================================*
+ Local Header File
+ *===========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*===========================================================================*
+ Public Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Defines
+ *===========================================================================*/
+
+#define ISO8061_TOKEN_YEARS 'Y'
+#define ISO8061_TOKEN_MONTHS 'M'
+#define ISO8061_TOKEN_WEEKS 'W'
+#define ISO8061_TOKEN_DAYS 'D'
+#define ISO8061_TOKEN_HOURS 'H'
+#define ISO8061_TOKEN_MINUTES 'M'
+#define ISO8061_TOKEN_SECONDS 'S'
+
+#define ISO8061_TOKEN_TIME 'T'
+#define ISO8061_TOKEN_PERIOD 'P'
+
+/*===========================================================================*
+ Private Data Types
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Function Prototypes
+ *===========================================================================*/
+
+static void append_iso8061_value(char *p_string, uint32_t value, char symbol);
+static void append_iso8061_tag(char *p_string, char symbol);
+
+/*===========================================================================*
+ Private Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Public Function Implementations
+ *===========================================================================*/
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_time()
+ *
+ * DESCRIPTION
+ * Set a time_t value into a VF property.
+ *
+ * RETURNS
+ * TRUE iff property added & set OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_value_time(
+ VF_PROP_T *p_prop, /* The property */
+ uint32_t n_string, /* Which string we're encoding to */
+ const time_t t_value /* Time value */
+ )
+{
+ bool_t ret;
+ struct tm *p_tm;
+
+ p_tm = localtime(&t_value);
+
+ if (p_tm)
+ {
+ char value[256];
+
+ if (p_tm->tm_hour || p_tm->tm_min || p_tm->tm_sec)
+ {
+ sprintf(value, "%4d%02d%02dT%02d%02d%02d",
+ 1900 + p_tm->tm_year,
+ 1 + p_tm->tm_mon,
+ p_tm->tm_mday,
+ p_tm->tm_hour,
+ p_tm->tm_min,
+ p_tm->tm_sec);
+ }
+ else
+ {
+ sprintf(value, "%4d%02d%02d",
+ 1900 + p_tm->tm_year,
+ 1 + p_tm->tm_mon,
+ p_tm->tm_mday);
+ }
+
+ ret = vf_set_prop_value_string(p_prop, n_string, value);
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_time()
+ *
+ * DESCRIPTION
+ * Fetch a time_t value from a VF property.
+ *
+ * RETURNS
+ * TRUE iff foudn & converted OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_prop_value_time(
+ VF_PROP_T *p_prop, /* The property */
+ uint32_t n_string, /* Which string we're decoding */
+ time_t *p_t_value /* Pointer to output time value */
+ )
+{
+ bool_t ret;
+ const char *p_value;
+
+ p_value = vf_get_prop_value_string(p_prop, n_string);
+
+ if (p_value)
+ {
+ ret = vf_date_string_to_time(p_t_value, p_value);
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_date_string_to_time()
+ *
+ * DESCRIPTION
+ * Convert calendar string to absolute time. The basic formats are
+ * 19960401, 19960401T073000Z
+ *
+ * RETURNS
+ * TRUE <=> conversion OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_date_string_to_time(
+ uint32_t *p_time, /* Output time value */
+ const char *p_string /* Input string */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (p_string && p_time)
+ {
+ time_t t;
+ struct tm tm;
+
+ p_memset(&tm, '\0', sizeof(tm));
+
+ /*
+ * p_string[8] is either 'T' or '\0' or an error.
+ */
+
+ if (ISO8061_TOKEN_TIME == p_string[8])
+ {
+ if (6 == sscanf(p_string, "%4d%2d%2dT%2d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec))
+ {
+ if ((1970 <= tm.tm_year) &&
+ ((1 <= tm.tm_mon) && (tm.tm_mon <= 12)) &&
+ ((1 <= tm.tm_mday) && (tm.tm_mday <= 28)) &&
+ ((0 <= tm.tm_hour) && (tm.tm_hour <= 23)) &&
+ ((0 <= tm.tm_min) && (tm.tm_hour <= 59)) &&
+ ((0 <= tm.tm_sec) && (tm.tm_sec <= 59)))
+ {
+ ret = TRUE;
+ }
+ }
+ }
+ else
+ if ('\0' == p_string[8])
+ {
+ if (3 == sscanf(p_string, "%4d%2d%2d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday))
+ {
+ if ((1970 <= tm.tm_year) &&
+ ((1 <= tm.tm_mon) && (tm.tm_mon <= 12)) &&
+ ((1 <= tm.tm_mday) && (tm.tm_mday <= 28)))
+ {
+ ret = TRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Nor flesh nor fish nor fowl */
+ }
+
+ /*
+ * Reduce the year value to correct range & convert to time_t.
+ */
+
+ if (ret)
+ {
+ tm.tm_mon -= 1;
+ tm.tm_year -= 1900;
+ tm.tm_isdst = -1;
+
+ t = mktime(&tm);
+
+ if ((-1) == t)
+ {
+ ret = FALSE;
+ }
+ else
+ {
+ *p_time = (uint32_t)t;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_period_string_to_time()
+ *
+ * DESCRIPTION
+ * Convert period definition string to time value. The format is
+ * P[aaaY][bbbM][cccW][dddD]T[eeeH][fffM][gggS] where 'aaa' is a
+ * number of years, bbb months etc.
+ *
+ * RETURNS
+ * TRUE <=> conversion OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_period_string_to_time(
+ VF_ISO8601_PERIOD_T *p_period, /* Output time value */
+ const char *p_string /* Input string */
+ )
+{
+ bool_t ret = TRUE;
+ bool_t in_time_part = FALSE;
+
+ p_memset(p_period, '\0', sizeof(*p_period));
+
+ if (p_string && ('P' == p_string[0]) && *(++p_string))
+ {
+ while (ret && *p_string)
+ {
+ uint32_t value = 0;
+
+ while (isdigit((int)*p_string))
+ {
+ value = (value * 10) + *(p_string++) - '0';
+ }
+
+ switch (*p_string++)
+ {
+ case '\0':
+ {
+ ret = FALSE;
+ }
+ break;
+
+ case ISO8061_TOKEN_YEARS:
+ {
+ p_period->years = value;
+ }
+ break;
+
+ case ISO8061_TOKEN_MONTHS:
+ /*case ISO8061_TOKEN_MINUTES:*/
+ {
+ if (in_time_part)
+ {
+ p_period->minutes = value;
+ }
+ else
+ {
+ p_period->months = value;
+ }
+ }
+ break;
+
+ case ISO8061_TOKEN_WEEKS:
+ {
+ p_period->weeks = value;
+ }
+ break;
+
+ case ISO8061_TOKEN_DAYS:
+ {
+ p_period->days = value;
+ }
+ break;
+
+ case ISO8061_TOKEN_TIME:
+ {
+ if (in_time_part)
+ {
+ ret = FALSE;
+ }
+ else
+ {
+ in_time_part = TRUE;
+ }
+ }
+ break;
+
+ case ISO8061_TOKEN_HOURS:
+ {
+ p_period->hours = value;
+ }
+ break;
+
+ case ISO8061_TOKEN_SECONDS:
+ {
+ p_period->seconds = value;
+ }
+ break;
+
+ default:
+ {
+ ret = FALSE;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_period_time_to_string()
+ *
+ * DESCRIPTION
+ * Convert a VF_ISO8601_PERIOD_T to a string.
+ *
+ * RETURNS
+ * Number of characters written.
+ *---------------------------------------------------------------------------*/
+
+uint32_t vf_period_time_to_string(
+ char *p_string, /* Output string */
+ const VF_ISO8601_PERIOD_T *p_period /* Input period value */
+ )
+{
+ uint32_t ret = 0;
+
+ if (p_string && p_period)
+ {
+ p_string[0] = '\0';
+
+ append_iso8061_tag(p_string, ISO8061_TOKEN_PERIOD);
+
+ append_iso8061_value(p_string, p_period->years, ISO8061_TOKEN_YEARS);
+ append_iso8061_value(p_string, p_period->months, ISO8061_TOKEN_MONTHS);
+ append_iso8061_value(p_string, p_period->weeks, ISO8061_TOKEN_WEEKS);
+ append_iso8061_value(p_string, p_period->days, ISO8061_TOKEN_DAYS);
+
+ if (p_period->hours || p_period->minutes || p_period->seconds)
+ {
+ append_iso8061_tag(p_string, ISO8061_TOKEN_TIME);
+ }
+
+ append_iso8061_value(p_string, p_period->hours, ISO8061_TOKEN_HOURS);
+ append_iso8061_value(p_string, p_period->minutes, ISO8061_TOKEN_MINUTES);
+ append_iso8061_value(p_string, p_period->seconds, ISO8061_TOKEN_SECONDS);
+
+ ret = p_strlen(p_string);
+ }
+
+ return ret;
+}
+
+
+
+/*===========================================================================*
+ Private Function Implementations
+ *===========================================================================*/
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * append_iso8061_value()
+ *
+ * DESCRIPTION
+ * Append xxxY value to the current encoded string.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+void append_iso8061_value(char *p_string, uint32_t value, char symbol)
+{
+ if (value)
+ {
+ sprintf(p_string + p_strlen(p_string), "%lu%c", (unsigned long)value, symbol);
+ }
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * append_iso8061_tag()
+ *
+ * DESCRIPTION
+ * Append indicated character to string.
+ *
+ * RETURNS
+ * (none).
+ *---------------------------------------------------------------------------*/
+
+void append_iso8061_tag(char *p_string, char symbol)
+{
+ p_string += p_strlen(p_string);
+
+ *p_string++ = symbol;
+ *p_string++ = '\0';
+}
+
+
+/*===========================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_access_wrappers.c b/src/vf_access_wrappers.c
new file mode 100644
index 0000000..2eea457
--- /dev/null
+++ b/src/vf_access_wrappers.c
@@ -0,0 +1,541 @@
+/****************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_access.c $
+ $Revision: 1.16 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Wrappers on the core access functions & other utility functions.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_access_wrappers.c,v $
+ * Revision 1.16 2002/11/16 13:19:10 tilda
+ * IID639288 - Implement method for adding subobjects.
+ *
+ * Revision 1.15 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.14 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.13 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.12 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.11 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.10 2001/11/18 22:07:02 tilda
+ * Ensure empty BASE64 properties get the encoding set correctly.
+ *
+ * Revision 1.9 2001/11/18 21:48:18 tilda
+ * Remove redundant code.
+ *
+ * Revision 1.8 2001/11/17 17:40:29 tilda
+ * Image / sound dialog box now works.
+ *
+ * Revision 1.7 2001/11/16 22:34:50 tilda
+ * New vf_get_property() allows append as well as find,
+ *
+ * Revision 1.6 2001/11/15 08:56:06 tilda
+ * Fix bug in qualifier location code.
+ *
+ * Revision 1.5 2001/11/14 22:36:56 tilda
+ * Add parameter to vf_find_prop_qual_index()
+ *
+ * Revision 1.4 2001/11/14 16:05:06 tilda
+ * Extend capabilities of vf_find_prop_qual_index().
+ *
+ * Revision 1.3 2001/11/06 22:51:05 tilda
+ * Supporting access functions for image selection / deletion.
+ *
+ * Revision 1.2 2001/10/24 18:56:29 tilda
+ * Tidy headers after import. Fix include path in release build.
+ *
+ * Revision 1.1 2001/10/24 18:34:35 tilda
+ * Initial Version.
+ *
+ *****************************************************************************/
+
+#ifndef NORCSID
+static const char vf_access_wrappers_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_access_wrappers.c,v 1.16 2002/11/16 13:19:10 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+/*===========================================================================*
+ Interface Header Files
+ *===========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*===========================================================================*
+ Local Header File
+ *===========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*===========================================================================*
+ Public Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Defines
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Data Types
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Function Prototypes
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Public Function Implementations
+ *===========================================================================*/
+
+bool_t vf_prop_belongs_to_object(
+ VF_PROP_T *p_prop,
+ VF_OBJECT_T *p_object
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_string()
+ *
+ * DESCRIPTION
+ * Obtain string pointer value from VF_PROP_T. If the array contains
+ * an entry for the indicated string return it. Return NULL if out of
+ * range request, ie. n_string=3 for N=0;1;2
+ *
+ * RETURNS
+ * Pointer to string value if value present, NULL if index too large.
+ *---------------------------------------------------------------------------*/
+
+char *vf_get_prop_value_string(
+ VF_PROP_T *p_prop,
+ uint32_t n_string
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ char *p_ret = NULL;
+
+ if (p_vprop->value.v.s.pp_strings)
+ {
+ if (n_string < p_vprop->value.v.s.n_strings)
+ {
+ p_ret = p_vprop->value.v.s.pp_strings[n_string];
+ }
+ }
+
+ return p_ret;
+}
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_string()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_value_string(
+ VF_PROP_T *p_prop,
+ uint32_t n_string,
+ const char *p_string
+ )
+{
+ return vf_set_prop_value(p_prop, (char *)p_string, n_string, VF_ENC_7BIT, TRUE);
+}
+
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_base64()
+ *
+ * DESCRIPTION
+ * Obtain data pointer for BASE64 data.
+ *
+ * RETURNS
+ * Pointer to data.
+ *---------------------------------------------------------------------------*/
+
+const uint8_t *vf_get_prop_value_base64(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ uint32_t *p_length /* Length of the binary data */
+ )
+{
+ const uint8_t *p_return = NULL;
+
+ if (p_prop)
+ {
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+
+ p_return = p_vprop->value.v.b.p_buffer;
+
+ if (p_length)
+ {
+ *p_length = p_vprop->value.v.b.n_bufsize;
+ }
+ }
+
+ return p_return;
+}
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_base64()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_value_base64(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ const uint8_t *p_data, /* Pointer to the binary data */
+ uint32_t length, /* Length of the binary data */
+ bool_t copy /* Copy or keep pointer */
+ )
+{
+ return vf_set_prop_value(p_prop, (char *)p_data, length, VF_ENC_BASE64, copy);
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_object()
+ *
+ * DESCRIPTION
+ * Obtain object pointer value from VF_PROP_T.
+ *
+ * RETURNS
+ * Pointer to vobject value (or NULL if not found).
+ *---------------------------------------------------------------------------*/
+
+VF_OBJECT_T *vf_get_prop_value_object(
+ VF_PROP_T *p_prop
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+
+ if (VF_ENC_VOBJECT == p_vprop->value.encoding)
+ {
+ return (VF_OBJECT_T *)(p_vprop->value.v.o.p_object);
+ }
+
+ return NULL;
+}
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_object()
+ *
+ * DESCRIPTION
+ * Set the value of the indicated property to be a VOBJECT.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_value_object(
+ VF_PROP_T *p_prop,
+ VF_OBJECT_T *p_object
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ bool_t ret = FALSE;
+
+ /*
+ * Avoid various sillies.
+ */
+ if (p_prop && p_object && !vf_prop_belongs_to_object(p_prop, p_object))
+ {
+ delete_prop_contents(p_prop, FALSE);
+
+ p_vprop->value.v.o.p_object = (VOBJECT_T *)p_object;
+ p_vprop->value.encoding = VF_ENC_VOBJECT;
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_name_string()
+ *
+ * DESCRIPTION
+ * Get n'th name string.
+ *
+ * RETURNS
+ * Pointer to string value if value present, NULL if index too large.
+ *---------------------------------------------------------------------------*/
+
+char *vf_get_prop_name_string(
+ VF_PROP_T *p_prop,
+ uint32_t n_string
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ char *p_ret = NULL;
+
+ if (p_vprop->name.pp_strings)
+ {
+ if (n_string < p_vprop->name.n_strings)
+ {
+ p_ret = p_vprop->name.pp_strings[n_string];
+ }
+ }
+
+ return p_ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_name_string()
+ *
+ * DESCRIPTION
+ * Set n'th name string.
+ *
+ * RETURNS
+ * TRUE iff allocation OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_prop_name_string(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ uint32_t n_string, /* Index to string */
+ const char *p_string /* Pointer to string */
+ )
+{
+ VPROP_T *p_vprop;
+ bool_t ret = FALSE;
+
+ p_vprop = (VPROP_T *)p_prop;
+
+ if (p_vprop)
+ {
+ if ((-1) == n_string)
+ {
+ ret = add_string_to_array(&p_vprop->name, p_string);
+ }
+ else
+ {
+ ret = set_string_array_entry(&p_vprop->name, p_string, n_string);
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_find_prop_qual_index()
+ *
+ * DESCRIPTION
+ * Locate property qualifier given either an array of possible values
+ * or a single token that is either present or absent. For example
+ * if we have a property:
+ *
+ * NAME;THIRD;TIME;LUCKY:VALUE1;VALUE2;VALUE3
+ *
+ * Then there are two possible searches.
+ *
+ * Firstly we can look for the property qualifier which can take values
+ * from the array { "FIRST", "SECOND", THIRD" } in which case the array
+ * is passed as pp_possible_values and the function returns with the
+ * values *p_found_value_index=2, p_qualifier_index=1
+ *
+ * Secondly we can look for the token with value "TIME" in which case
+ * p_token is set to "TIME" and the function returns *p_qualifier_index=2.
+ *
+ * RETURNS
+ * TRUE iff found, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_find_prop_qual_index(
+ VF_PROP_T *p_prop, /* The property we're querying */
+ uint32_t *p_qualifier_index, /* Ptr to output name index */
+ uint32_t *p_found_value_index, /* Ptr to output index in array */
+ const char **pp_possible_values, /* Array of possible values */
+ const char *p_token, /* Token searched for */
+ vf_search_flags_t match /* String comparison flags */
+ )
+{
+ uint32_t n;
+ bool_t ret;
+
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+
+ for (n = 0, ret = FALSE;!ret && (n < p_vprop->name.n_strings);n++)
+ {
+ const char *p_string = p_vprop->name.pp_strings[n];
+
+ if (p_string)
+ {
+ if (pp_possible_values)
+ {
+ uint32_t i;
+
+ for (i = 0;!ret && pp_possible_values[i];i++)
+ {
+ if (0 == p_stricmp(pp_possible_values[i], p_string))
+ {
+ if (p_found_value_index)
+ *p_found_value_index = i;
+ if (p_qualifier_index)
+ *p_qualifier_index = n;
+
+ ret = TRUE;
+ }
+ }
+ }
+ else
+ if (p_token)
+ {
+ if (0 == p_stricmp(p_token, p_string))
+ {
+ if (p_qualifier_index)
+ *p_qualifier_index = n;
+
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /*???*/
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_find_charset()
+ *
+ * DESCRIPTION
+ * Locate the charset
+ *
+ * RETURNS
+ * vf_charset_t.
+ *---------------------------------------------------------------------------*/
+
+const char *vf_find_charset(
+ VF_PROP_T *p_prop
+ )
+{
+ VPROP_T *p_vprop = (VPROP_T *)p_prop;
+ char *ret;
+
+ if (!string_array_contains_string(&p_vprop->name, &ret, -1, VFP_CHARSET, FALSE))
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret += 1 + p_strlen(VFP_CHARSET);
+ }
+
+ return ret;
+}
+
+
+
+
+
+/*===========================================================================*
+ Private Function Implementations
+ *===========================================================================*/
+
+bool_t vf_prop_belongs_to_object(
+ VF_PROP_T *p_prop,
+ VF_OBJECT_T *p_object
+ )
+{
+ return FALSE;
+}
+
+/*===========================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_config.h b/src/vf_config.h
new file mode 100644
index 0000000..2a4ff8f
--- /dev/null
+++ b/src/vf_config.h
@@ -0,0 +1,85 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_common.h $
+ $Revision: 1.1 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Common header file for vformat library. This file is internal to vformat
+ (ie. changes here don't affect the interface) but contains the definitions
+ which affect the operation of various components eg. the memory debug.
+
+ This file is #included before all other header files within the library.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_config.h,v $
+ * Revision 1.1 2002/10/26 15:57:11 tilda
+ * Initial Version
+ *
+ *
+ *******************************************************************************/
+
+#ifndef _VF_CONFIG_H_
+#define _VF_CONFIG_H_
+
+#ifndef NORCSID
+static const char vf_config_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_config.h,v 1.1 2002/10/26 15:57:11 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+
+/*
+ * If building debug version under windows then include the memory debug interface.
+ */
+#if (defined(WIN) || defined(WIN32)) && defined(_DEBUG)
+#if !defined(VFORMAT_MEM_DEBUG)
+#define VFORMAT_MEM_DEBUG
+#endif
+#endif
+
+/*
+ * Conditional compiles allowing configuration of various string portability functions.
+ */
+/* #define HAVE_STRLEN */
+/* #define HAVE_STRCPY */
+/* #define HAVE_STRCMP */
+/* #define HAVE_STRCAT */
+/* #define HAVE_STRSTR */
+/* #define HAVE_STRICMP */
+/* #define HAVE_MEMCPY */
+/* #define HAVE_MEMSET */
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_CONFIG_H_*/
diff --git a/src/vf_create_object.c b/src/vf_create_object.c
new file mode 100644
index 0000000..ab540b9
--- /dev/null
+++ b/src/vf_create_object.c
@@ -0,0 +1,158 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Revision: 1.8 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley.
+
+DESCRIPTION
+ The vf_create_object() function.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_create_object.c,v $
+ * Revision 1.8 2002/11/16 13:19:10 tilda
+ * IID639288 - Implement method for adding subobjects.
+ *
+ * Revision 1.7 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.6 2002/10/29 07:19:20 tilda
+ * Tidy headers.
+ *
+ * Revision 1.5 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.4 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.3 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.2 2002/01/06 13:11:55 tilda
+ * Update header.
+ *
+ * Revision 1.1 2002/01/06 13:08:15 tilda
+ * Change file name from vf_createobject.c
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_create_object_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_create_object.c,v 1.8 2002/11/16 13:19:10 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *===========================================================================*/
+
+#include <common/types.h>
+
+/*===========================================================================*
+ Interface Header Files
+ *==========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*===========================================================================*
+ Local Header File
+ *==========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*===========================================================================*
+ Public Data
+ *==========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Defines
+ *==========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Data Types
+ *==========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Function Prototypes
+ *==========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Data
+ *==========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Public Function Implementations
+ *==========================================================================*/
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_create_object()
+ *
+ * DESCRIPTION
+ * Creates and empty vformat object.
+ *
+ * RETURNS
+ * Ptr to object if created else NULL.
+ *---------------------------------------------------------------------------*/
+
+VF_OBJECT_T *vf_create_object(
+ const char *p_type, /* Type of object to create */
+ VF_OBJECT_T *p_parent /* Parent object if any */
+ )
+{
+ VOBJECT_T *p_new = NULL;
+
+ if (p_type)
+ {
+ p_new = vf_malloc(sizeof(VOBJECT_T));
+
+ if (p_new)
+ {
+ p_memset(p_new, '\0', sizeof(VOBJECT_T));
+
+ p_new->p_type = vf_malloc(1 + p_strlen(p_type));
+
+ p_new->p_parent = (VOBJECT_T *)p_parent;
+
+ if (p_new->p_type)
+ {
+ p_strcpy(p_new->p_type, p_type);
+ }
+ else
+ {
+ vf_free(p_new);
+ p_new = NULL;
+ }
+ }
+ }
+
+ return (VF_OBJECT_T *)p_new;
+}
+
+
+/*===========================================================================*
+ Private Function Implementations
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_delete.c b/src/vf_delete.c
new file mode 100644
index 0000000..d70b8e4
--- /dev/null
+++ b/src/vf_delete.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_delete.c $
+ $Revision: 1.14 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Delete a vformat object.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_delete.c,v $
+ * Revision 1.14 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.13 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.12 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.11 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.10 2001/11/05 21:07:20 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.9 2001/10/24 18:36:06 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.8 2001/10/14 19:53:36 tilda
+ * Group handling. NO group searching functions.
+ *
+ * Revision 1.7 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.6 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.5 2001/10/13 14:49:30 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ * Revision 1.4 2001/10/12 16:20:03 tilda
+ * Correctly parse compound quoted printable properties.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_delete_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_delete.c,v 1.14 2002/11/03 18:43:16 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *=============================================================================*/
+
+#include <common/types.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_string_arrays.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+
+static void free_prop_list(
+ VPROP_T *p_props /* List of properties to free */
+ );
+
+
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_delete_object()
+ *
+ * DESCRIPTION
+ * Cleans up the memory used by the indicated vformat object.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void vf_delete_object(
+ VF_OBJECT_T *p_object,
+ bool_t all
+ )
+{
+ VOBJECT_T *p_obj = (VOBJECT_T *)p_object;
+
+ if (p_obj)
+ {
+ VOBJECT_T *p_next = p_obj->p_next;
+
+ free_prop_list(p_obj->p_props);
+
+ if (p_obj->p_type)
+ {
+ vf_free(p_obj->p_type);
+ }
+
+ vf_free(p_obj);
+
+ if (all )
+ {
+ vf_delete_object((VF_OBJECT_T *)p_next, TRUE);
+ }
+ }
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_delete_prop()
+ *
+ * DESCRIPTION
+ * Deletes indicated property from the indicated object. Deletes prop
+ * contents if dc is set.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void vf_delete_prop(
+ VF_OBJECT_T *p_object, /* The object we're deleting from */
+ VF_PROP_T *p_prop, /* The property we're removing */
+ bool_t dc /* Should property contents be deleted? */
+ )
+{
+ VOBJECT_T *p_obj = (VOBJECT_T *)p_object;
+
+ if (p_obj)
+ {
+ VPROP_T **p_vprop = &(p_obj->p_props);
+
+ while (*p_vprop)
+ {
+ if ((*p_vprop) == (VPROP_T *)p_prop)
+ {
+ *p_vprop = ((VPROP_T *)p_prop)->p_next;
+
+ if (dc)
+ {
+ delete_prop_contents(p_prop, TRUE);
+ }
+
+ vf_free(p_prop);
+
+ break;
+ }
+ else
+ {
+ p_vprop = &((*p_vprop)->p_next);
+ }
+ }
+ }
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * delete_prop_contents()
+ *
+ * DESCRIPTION
+ * Cleans up the memory used by the value associated with the property.
+ * The property is not deleted => can be a statically allocated variable.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void delete_prop_contents(
+ VF_PROP_T *p_vprop, /* The VF_PROP_T to clean */
+ bool_t delname /* Delete the name as well? */
+ )
+{
+ VPROP_T *p_prop = (VPROP_T *)p_vprop;
+
+ if (delname)
+ {
+ free_string_array_contents(&p_prop->name);
+
+ if (p_prop->p_group)
+ {
+ vf_free(p_prop->p_group);
+ p_prop->p_group = NULL;
+ }
+ }
+
+ if (p_prop->value.v.b.p_buffer)
+ {
+ vf_free(p_prop->value.v.b.p_buffer);
+ p_prop->value.v.b.p_buffer = NULL;
+ }
+
+ if (p_prop->value.v.s.pp_strings)
+ {
+ uint32_t n;
+
+ for (n = 0;n < p_prop->value.v.s.n_strings;n++)
+ {
+ if (p_prop->value.v.s.pp_strings[n])
+ {
+ vf_free(p_prop->value.v.s.pp_strings[n]);
+ p_prop->value.v.s.pp_strings[n] = NULL;
+ }
+ }
+
+ vf_free(p_prop->value.v.s.pp_strings);
+ p_prop->value.v.s.pp_strings = NULL;
+
+ p_prop->value.v.s.n_strings = 0;
+ }
+
+ if (p_prop->value.v.o.p_object)
+ {
+ vf_delete_object((VF_OBJECT_T *)p_prop->value.v.o.p_object, TRUE);
+ p_prop->value.v.o.p_object = NULL;
+ }
+}
+
+
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * free_prop_list()
+ *
+ * DESCRIPTION
+ * Cleans up the memory used by the indicated property list.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void free_prop_list(
+ VPROP_T *p_props /* List of properties to free */
+ )
+{
+ VPROP_T *p_tmp;
+
+ for (p_tmp = p_props;p_tmp;)
+ {
+ VPROP_T *p_next = p_tmp->p_next;
+
+ delete_prop_contents((VF_PROP_T *)p_tmp, TRUE);
+
+ vf_free(p_tmp);
+
+ p_tmp = p_next;
+ }
+}
+
+
+
+
+
+
+
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_internals.h b/src/vf_internals.h
new file mode 100644
index 0000000..98ddacc
--- /dev/null
+++ b/src/vf_internals.h
@@ -0,0 +1,223 @@
+/*******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_internals.h $
+ $Revision: 1.15 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Definition of the internal representation used for VOBJECTs.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_internals.h,v $
+ * Revision 1.15 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.14 2002/11/02 08:56:17 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.13 2002/10/26 16:09:24 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.12 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.11 2002/02/24 17:10:34 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.10 2001/10/24 18:36:06 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.9 2001/10/14 19:53:36 tilda
+ * Group handling. NO group searching functions.
+ *
+ * Revision 1.8 2001/10/14 16:40:04 tilda
+ * Initial testing of access functions.
+ *
+ * Revision 1.7 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.6 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.5 2001/10/13 14:49:30 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ * Revision 1.4 2001/10/12 16:20:03 tilda
+ * Correctly parse compound quoted printable properties.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *******************************************************************************/
+
+#ifndef _VF_INTERNALS_H_
+#define _VF_INTERNALS_H_
+
+#ifndef NORCSID
+static const char vf_internals_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_internals.h,v 1.15 2002/11/02 18:29:26 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+
+#define VFP_BEGIN "BEGIN"
+#define VFP_END "END"
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VSTRARRAY_T encapsulates an array of strings.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VSTRARRAY_T
+{
+ uint32_t n_strings; /* Then number of strings */
+ char **pp_strings; /* The strings */
+}
+VSTRARRAY_T;
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VBINDATA_T encapsulates a chunk of binary data. Yes, you could encode
+ * any and all vformat attributes in BASE64 but custom is to use BASE64
+ * for images etc.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VBINDATA_T
+{
+ char *p_buffer; /* Binary data */
+ uint32_t n_bufsize;
+}
+VBINDATA_T;
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VOBJDATA_T
+ *----------------------------------------------------------------------------*/
+
+typedef struct VOBJDATA_T
+{
+ struct VOBJECT_T *p_object; /* Another vformat object */
+}
+VOBJDATA_T;
+
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VPROPVALUE_T encapsulates the "value" half of a property.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VPROPVALUE_T
+{
+ vf_encoding_t encoding;
+
+ struct
+ {
+ VSTRARRAY_T s;
+ VBINDATA_T b;
+ VOBJDATA_T o;
+ }
+ v;
+}
+VPROPVALUE_T;
+
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VPROP_T defines a single property. It's an association of a name
+ * and value pair. A vformat object is simply a list of properties.
+ * Associated with a property is (possibly) a group name.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VPROP_T
+{
+ char *p_group; /* Group - we keep the A.B.C format */
+ VSTRARRAY_T name; /* Name fields */
+ VPROPVALUE_T value; /* Value fields */
+
+ struct VPROP_T *p_next; /* Next property */
+ struct VPROP_T *p_next_srch; /* Next in current search */
+
+ bool_t modified; /* Property modified? */
+
+ struct VOBJECT_T *p_parent; /* Owning object (if any) */
+}
+VPROP_T;
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VOBJECT_T defines a single vformat object.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VOBJECT_T
+{
+ char *p_type; /* "VCARD" or "VCALENDAR" etc. */
+ VPROP_T *p_props; /* List of properties */
+
+ bool_t modified; /* Object modified? */
+
+ struct VOBJECT_T *p_parent; /* Owning object (if any) */
+ struct VOBJECT_T *p_next; /* Next object (if any) */
+}
+VOBJECT_T;
+
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * delete_prop_contents()
+ *
+ * DESCRIPTION
+ * Cleans up the memory used by the value associated with the property.
+ * The property is not deleted => can be a statically allocated variable.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+extern void delete_prop_contents(
+ VF_PROP_T *p_vprop, /* The VF_PROP_T to clean */
+ bool_t delname /* Delete the name as well? */
+ );
+
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_INTERNALS_H_*/
+
diff --git a/src/vf_malloc.c b/src/vf_malloc.c
new file mode 100644
index 0000000..ef405d9
--- /dev/null
+++ b/src/vf_malloc.c
@@ -0,0 +1,270 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_malloc.c $
+ $Revision: 1.7 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Implements the memory allocation functions used by the rest of the vformat
+ library, defaulting to the functions provided by vf_malloc_stdlib.c which
+ uses malloc() etc.
+
+ Code below knows nothing about the specific allocation scheme in use or it's
+ debugging facilities and is simply provides the common functions and the
+ ability to point vformat at an alternative allocation module.
+
+ The only conditional compile option recognised is VFORMAT_MEM_DEBUG which
+ is described in the accompanying header file.
+
+ Note
+ ====
+ The original code merged the malloc() implementation with the debug facility
+ and also included a conditional compile VFORMAT_EXT_MALLOC to control the use
+ of external allocation functions. Given that this tripped up the _author_ on
+ at least one public test event (UPF-9, where the sync engine was unable to read
+ VCARDS & extract the X-IRMC stuff) it was considered overcomplicated and has
+ been considerably simplified ;) - T.
+
+MODIFICATION HISTORY
+ * $Log: vf_malloc.c,v $
+ * Revision 1.7 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.6 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.5 2002/10/08 21:08:43 tilda
+ * Improve memory debugging functions.
+ *
+ * Revision 1.4 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_malloc_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_malloc.c,v 1.7 2002/10/26 16:09:23 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#if !defined(VFORMAT_EXCLUDE_MALLOC)
+#include "vf_malloc_stdlib.h"
+#endif
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+
+/*
+ * Pointers to the functions in use - initialised to the default CRT based allocation
+ * functions unless VFORMAT_EXCLUDE_MALLOC is set in which case they are initialised
+ * to NULL in the expectation that the user calls vf_set_mem_functions() at some point.
+ */
+
+#if defined(VFORMAT_EXCLUDE_MALLOC)
+static vf_malloc_fn_t vf_malloc_fn;
+static vf_realloc_fn_t vf_realloc_fn;
+static vf_free_fn_t vf_free_fn;
+#else
+static vf_malloc_fn_t vf_malloc_fn = _vf_stdlib_malloc;
+static vf_realloc_fn_t vf_realloc_fn = _vf_stdlib_realloc;
+static vf_free_fn_t vf_free_fn = _vf_stdlib_free;
+#endif
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_set_mem_functions()
+ *
+ * DESCRIPTION
+ * Set the memory allocation functions we're using.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void vf_set_mem_functions(
+ vf_malloc_fn_t malloc_fn, /* Allocation function */
+ vf_realloc_fn_t realloc_fn, /* Reallocation function */
+ vf_free_fn_t free_fn /* Free function */
+ )
+{
+ vf_realloc_fn = realloc_fn;
+ vf_malloc_fn = malloc_fn;
+ vf_free_fn = free_fn;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_malloc()
+ *
+ * DESCRIPTION
+ * Allocate chunk of memory.
+ *
+ * RETURNS
+ * Ptr to new block, or NULL if failed.
+ *----------------------------------------------------------------------------*/
+
+void *_vf_malloc(
+ uint32_t s /* Size required */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* Filename */
+ int line /* Line number */
+#endif
+ )
+{
+ void *p = NULL;
+
+ if (vf_malloc_fn)
+ {
+#if defined(VFORMAT_MEM_DEBUG)
+ p = vf_malloc_fn(s, file, line);
+#else
+ p = vf_malloc_fn(s);
+#endif
+ }
+
+ return p;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_realloc()
+ *
+ * DESCRIPTION
+ * Re-allocate chunk of memory allocated by _vf_malloc().
+ *
+ * RETURNS
+ * Ptr to new block, or NULL if failed.
+ *----------------------------------------------------------------------------*/
+
+void *_vf_realloc(
+ void *p, /* Original pointer */
+ uint32_t s /* Size required */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* filename */
+ int line /* line number */
+#endif
+ )
+{
+ void *np = NULL;
+
+ if (vf_realloc_fn)
+ {
+#if defined(VFORMAT_MEM_DEBUG)
+ np = vf_realloc_fn(p, s, file, line);
+#else
+ np = vf_realloc_fn(p, s);
+#endif
+ }
+
+ return np;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_free()
+ *
+ * DESCRIPTION
+ * De-allocate chunk of memory allocated by _vf_malloc().
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void _vf_free(
+ void *p /* Pointer */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* Filename */
+ int line /* Line number */
+#endif
+ )
+{
+ if (vf_free_fn)
+ {
+#if defined(VFORMAT_MEM_DEBUG)
+ vf_free_fn(p, file, line);
+#else
+ vf_free_fn(p);
+#endif
+ }
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_malloc.h b/src/vf_malloc.h
new file mode 100644
index 0000000..7116d64
--- /dev/null
+++ b/src/vf_malloc.h
@@ -0,0 +1,166 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_malloc.h $
+ $Revision: 1.6 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Memory allocation functions / macros for vformat code. The code always uses
+ vf_malloc(), vf_realloc() and vf_free() which are replaced by macros with the
+ names of functions implemented in vf_malloc.c.
+
+ If the conditional compile VFORMAT_MEM_DEBUG is set then in addition to the
+ caller's allocation parameters, filename and line number information is
+ provided to the lower layer which may record this for debugging.
+
+ Additionally, a function vf_set_mem_functions() is provided which allows an
+ application to replace the allocation functions with it's own. This should
+ be done before vformat allocates any memory ie. during initialisation.
+
+ Unless the library is built with the symbol VFORMAT_EXCLUDE_MALLOC defined
+ then the library defaults to using malloc() etc.
+
+MODIFICATION HISTORY
+ * $Log: vf_malloc.h,v $
+ * Revision 1.6 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.5 2002/10/08 21:08:43 tilda
+ * Improve memory debugging functions.
+ *
+ * Revision 1.4 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *******************************************************************************/
+
+#ifndef _VF_MALLOC_H_
+#define _VF_MALLOC_H_
+
+#ifndef NORCSID
+static const char vf_malloc_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_malloc.h,v 1.6 2002/10/26 16:09:23 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+
+/*
+ * If VFORMAT_MEM_DEBUG is defined, map the vf_xxx() allocation calls to
+ * the debugging versions found in vf_malloc.c
+ */
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+#define vf_malloc(x) _vf_malloc(x, __FILE__, __LINE__)
+#define vf_realloc(x, y) _vf_realloc(x, y, __FILE__, __LINE__)
+#define vf_free(x) _vf_free(x, __FILE__, __LINE__)
+
+#else /*defined(VFORMAT_MEM_DEBUG)*/
+
+#define vf_malloc(x) _vf_malloc(x)
+#define vf_realloc(x, y) _vf_realloc(x, y)
+#define vf_free(x) _vf_free(x)
+
+#endif /*defined(VFORMAT_MEM_DEBUG)*/
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+typedef void *(*vf_malloc_fn_t)(uint32_t s, const char *file, int line);
+typedef void *(*vf_realloc_fn_t)(void *p, uint32_t ns, const char *file, int line);
+typedef void (*vf_free_fn_t)(void *p, const char *file, int line);
+
+#else /*defined(VFORMAT_MEM_DEBUG)*/
+
+typedef void *(*vf_malloc_fn_t)(uint32_t s);
+typedef void *(*vf_realloc_fn_t)(void *p, uint32_t ns);
+typedef void (*vf_free_fn_t)(void *p);
+
+#endif /*defined(VFORMAT_MEM_DEBUG)*/
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_malloc(), _vf_realloc(), _vf_free()
+ *
+ * DESCRIPTION
+ * Memory allocation functions in use. If VFORMAT_MEM_DEBUG is defined
+ * the line & file are recorded as well.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+extern void *_vf_malloc(uint32_t s, const char *file, int line);
+extern void *_vf_realloc(void *p, uint32_t ns, const char *file, int line);
+extern void _vf_free(void *p, const char *file, int line);
+
+#else
+
+extern void *_vf_malloc(uint32_t s);
+extern void *_vf_realloc(void *p, uint32_t ns);
+extern void _vf_free(void *p);
+
+#endif
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_set_mem_functions()
+ *
+ * DESCRIPTION
+ * Set the memory allocation functions we're using.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC void vf_set_mem_functions(
+ vf_malloc_fn_t malloc_fn,
+ vf_realloc_fn_t realloc_fn,
+ vf_free_fn_t free_fn
+ );
+
+
+
+
+/*=============================================================================*
+ FIN
+ *============================================================================*/
+
+#endif /*_VF_MALLOC_H_*/
diff --git a/src/vf_malloc_stdlib.c b/src/vf_malloc_stdlib.c
new file mode 100644
index 0000000..6318fa5
--- /dev/null
+++ b/src/vf_malloc_stdlib.c
@@ -0,0 +1,392 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_malloc.c $
+ $Revision: 1.2 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ C standard library based memory allocation functions referenced by default in
+ the accompanying vf_malloc.c file. These are excluded from the build entirely
+ if VFORMAT_EXCLUDE_MALLOC is set in the build options.
+
+MODIFICATION HISTORY
+ * $Log: vf_malloc_stdlib.c,v $
+ * Revision 1.2 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.1 2002/10/26 15:57:11 tilda
+ * Initial Version
+ *
+ *******************************************************************************/
+
+#if !defined(VFORMAT_EXCLUDE_MALLOC)
+
+#ifndef NORCSID
+static const char vf_malloc_stdlib_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_malloc_stdlib.c,v 1.2 2002/11/15 09:15:00 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_strings.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+
+#define NUMMEMBLOCKS (1024)
+
+#if defined(WIN) || defined(WIN32)
+#define DEBUGBREAK _asm { int 3 }
+#endif
+
+#ifndef DEBUGBREAK
+#define DEBUGBREAK
+#endif
+
+#define ALLOCBREAK (-1)
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+
+typedef struct MEMBLOCK_T
+{
+ void *p; /* The block */
+ uint32_t s; /* The size */
+ char *file; /* filename it was allocated in */
+ int line; /* line number */
+}
+MEMBLOCK_T;
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+
+#if defined(VFORMAT_MEM_DEBUG)
+static void init_mem_debug(void);
+static void atexit_dump_mem(void);
+#endif
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+
+static MEMBLOCK_T blocks[NUMMEMBLOCKS];
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_stdlib_malloc()
+ *
+ * DESCRIPTION
+ * vformat compatible memory allocator using C standard library functions.
+ *
+ * RETURNS
+ * Ptr to new block, or NULL if failed.
+ *----------------------------------------------------------------------------*/
+
+void *_vf_stdlib_malloc(
+ uint32_t s /* Size required */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* filename */
+ int line /* line number */
+#endif
+ )
+{
+ void *p = NULL;
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+ uint32_t i;
+
+ init_mem_debug();
+
+ for (i = 0;i < NUMMEMBLOCKS;i++)
+ {
+ if (blocks[i].p)
+ {
+ }
+ else
+ {
+ p = malloc(s);
+
+ if (p)
+ {
+ blocks[i].p = p;
+ blocks[i].s = s;
+ blocks[i].file = (char *)file;
+ blocks[i].line = line;
+ }
+
+ if (i == ALLOCBREAK)
+ {
+ DEBUGBREAK;
+ }
+
+ break;
+ }
+ }
+
+#else /*defined(VFORMAT_MEM_DEBUG)*/
+
+ p = malloc(s);
+
+#endif
+
+ return p;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_stdlib_realloc()
+ *
+ * DESCRIPTION
+ * Re-allocate chunk of memory allocated by _vf_malloc().
+ *
+ * RETURNS
+ * Ptr to new block, or NULL if failed.
+ *----------------------------------------------------------------------------*/
+
+void *_vf_stdlib_realloc(
+ void *p, /* Original pointer */
+ uint32_t s /* Size required */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* Filename */
+ int line /* Line number */
+#endif
+ )
+{
+ void *np = NULL;
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+ uint32_t i;
+
+ init_mem_debug();
+
+ if (!p)
+ return _vf_stdlib_malloc(s, file, line);
+
+ for (i = 0;i < NUMMEMBLOCKS;i++)
+ {
+ if (blocks[i].p == p)
+ {
+ np = realloc(p, s);
+
+ if (np)
+ {
+ blocks[i].p = np;
+ blocks[i].s = s;
+ }
+
+ break;
+ }
+ }
+
+#else /*defined(VFORMAT_MEM_DEBUG)*/
+
+ np = realloc(p, s);
+
+#endif /*defined(VFORMAT_MEM_DEBUG)*/
+
+ return np;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_stdlib_free()
+ *
+ * DESCRIPTION
+ * De-allocate chunk of memory allocated by _vf_malloc().
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void _vf_stdlib_free(
+ void *p /* Pointer */
+#if defined(VFORMAT_MEM_DEBUG)
+ , const char *file, /* Filename */
+ int line /* Line number */
+#endif
+ )
+{
+#if defined(VFORMAT_MEM_DEBUG)
+
+ uint32_t i;
+
+ init_mem_debug();
+
+ for (i = 0;i < NUMMEMBLOCKS;i++)
+ {
+ if (blocks[i].p == p)
+ {
+ blocks[i].p = NULL;
+ blocks[i].s = 0;
+ blocks[i].line = 0;
+ blocks[i].file = NULL;
+
+ free(p);
+
+ break;
+ }
+ }
+
+#else
+
+ free(p);
+
+#endif
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_stdlib_dump_alloc_info()
+ *
+ * DESCRIPTION
+ * Display current state of memory allocator.
+ *
+ * RETURNS
+ * TRUE if blocks are currently allocated, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t vf_stdlib_dump_alloc_info()
+{
+ unsigned long i;
+ unsigned long c, s;
+
+ for (i = 0, c = 0, s = 0;i < NUMMEMBLOCKS;i++)
+ {
+ if (blocks[i].p)
+ {
+ c += 1;
+ s += blocks[i].s;
+
+ printf("block[%lu] size %lu, file %s, line %d\n",
+ i, (unsigned long)blocks[i].s, blocks[i].file, blocks[i].line);
+ }
+ }
+
+ if (c)
+ {
+ printf("... a total of %lu blocks, %lu bytes\n", c, s);
+ }
+
+ return (0 < c) ? TRUE : FALSE;
+}
+
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * init_mem_debug()
+ *
+ * DESCRIPTION
+ * Initialisation function.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void init_mem_debug()
+{
+ static bool_t init_yet = FALSE;
+
+ if (init_yet)
+ {
+ /* OK */
+ }
+ else
+ {
+ p_memset(blocks, '\0', sizeof(blocks));
+
+ atexit(atexit_dump_mem);
+
+ init_yet = TRUE;
+ }
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * atexit_dump_mem()
+ *
+ * DESCRIPTION
+ * atexit() callback function which dumps memory allocated info.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void atexit_dump_mem(void)
+{
+ vf_stdlib_dump_alloc_info();
+}
+
+#endif /*defined(VFORMAT_MEM_DEBUG)*/
+
+
+#endif /*defined(VFORMAT_EXCLUDE_MALLOC)*/
+
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_malloc_stdlib.h b/src/vf_malloc_stdlib.h
new file mode 100644
index 0000000..d765256
--- /dev/null
+++ b/src/vf_malloc_stdlib.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_malloc.h $
+ $Revision: 1.1 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Externs for the malloc() based memory allocator.
+
+MODIFICATION HISTORY
+ * $Log: vf_malloc_stdlib.h,v $
+ * Revision 1.1 2002/10/26 15:57:11 tilda
+ * Initial Version
+ *
+ *
+ *******************************************************************************/
+
+#ifndef _VF_MALLOC_STDLIB_H_
+#define _VF_MALLOC_STDLIB_H_
+
+#ifndef NORCSID
+static const char vf_malloc_stdlib_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_malloc_stdlib.h,v 1.1 2002/10/26 15:57:11 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * _vf_stdlib_malloc(), _vf_stdlib_realloc(), _vf_stdlib_free()
+ *
+ * DESCRIPTION
+ * Memory allocation functions provided in terms of C runtime library
+ * malloc() etc. If VFORMAT_MEM_DEBUG is defined the line & file are
+ * passed through for ebugging purposes.
+ *
+ * RETURNS
+ * (various)
+ *----------------------------------------------------------------------------*/
+
+#if defined(VFORMAT_MEM_DEBUG)
+
+extern void *_vf_stdlib_malloc(uint32_t s, const char *file, int line);
+extern void *_vf_stdlib_realloc(void *p, uint32_t ns, const char *file, int line);
+extern void _vf_stdlib_free(void *p, const char *file, int line);
+
+#else
+
+extern void *_vf_stdlib_malloc(uint32_t s);
+extern void *_vf_stdlib_realloc(void *p, uint32_t ns);
+extern void _vf_stdlib_free(void *p);
+
+#endif
+
+/*=============================================================================*
+ FIN
+ *============================================================================*/
+
+#endif /*_VF_MALLOC_STDLIB_H_*/
diff --git a/src/vf_modified.c b/src/vf_modified.c
new file mode 100644
index 0000000..427698a
--- /dev/null
+++ b/src/vf_modified.c
@@ -0,0 +1,159 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_modified.c $
+ $Revision: 1.4 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Memory allocation system for vformat parser / editor.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_modified.c,v $
+ * Revision 1.4 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.3 2002/10/29 07:19:20 tilda
+ * Tidy headers.
+ *
+ * Revision 1.2 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.1 2002/10/11 20:29:25 tilda
+ * Include vf_modified.c
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_modified_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_modified.c,v 1.4 2002/11/02 18:29:26 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_modified.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_is_modified()
+ *
+ * DESCRIPTION
+ * Return the status of the modified flag for the indicated object.
+ *
+ * RETURNS
+ * TRUE/FALSE
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_is_modified(
+ VF_OBJECT_T *p_object
+ )
+{
+ bool_t ret = FALSE;
+
+ if (p_object)
+ {
+ ret = ((VOBJECT_T *)p_object)->modified;
+ }
+
+ return ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * mark_property_modified()
+ *
+ * DESCRIPTION
+ * Mark indicated property and it's owning object as modified. If the
+ * recurse flag is st, then the owning object's parent object is also
+ * marked as modified recursively up to the top of the tree.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+void mark_property_modified(
+ VPROP_T *p_prop, /* The property */
+ bool_t recurse /* Recurse? */
+ )
+{
+ p_prop->modified = TRUE;
+ p_prop->p_parent->modified = TRUE;
+
+ if (recurse)
+ {
+ VOBJECT_T *p_parent = p_prop->p_parent->p_parent;
+
+ for (;p_parent;p_parent = p_parent->p_parent)
+ {
+ p_parent->modified = TRUE;
+ }
+ }
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+
+ /*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_modified.h b/src/vf_modified.h
new file mode 100644
index 0000000..f1616a4
--- /dev/null
+++ b/src/vf_modified.h
@@ -0,0 +1,84 @@
+/*******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_modified.h $
+ $Revision: 1.1 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Library internal access to the modification status.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_modified.h,v $
+ * Revision 1.1 2002/10/11 20:22:32 tilda
+ * Added / repaired vf_modified.h
+ *
+ *
+ * 2 9/05/02 3:49p Nm2
+ * Adjust memoruy allocation system for use in an embedded build.
+ *
+ * 1 7/08/02 7:24a Nm2
+ *
+ *******************************************************************************/
+
+#ifndef _VF_MODIFIED_H_
+#define _VF_MODIFIED_H_
+
+#ifndef NORCSID
+static const char vf_modified_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_modified.h,v 1.1 2002/10/11 20:22:32 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * mark_property_modified()
+ *
+ * DESCRIPTION
+ * Mark indicated property and it's owning object as modified. If the
+ * recurse flag is st, then the owning object's parent object is also
+ * marked as modified recursively up to the top of the tree.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+extern void mark_property_modified(
+ VPROP_T *p_prop, /* The property */
+ bool_t recurse /* Recurse? */
+ );
+
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_MODIFIED_H_*/
diff --git a/src/vf_parser.c b/src/vf_parser.c
new file mode 100644
index 0000000..bf7b789
--- /dev/null
+++ b/src/vf_parser.c
@@ -0,0 +1,1182 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_parser.c $
+ $Revision: 1.22 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Parser for text stream in vobject format.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_parser.c,v $
+ * Revision 1.22 2002/11/16 13:19:10 tilda
+ * IID639288 - Implement method for adding subobjects.
+ *
+ * Revision 1.21 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.20 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.19 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.18 2002/11/02 08:56:17 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.17 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.16 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.15 2002/10/08 21:25:28 tilda
+ * Assignment of parent property.
+ *
+ * Revision 1.14 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.13 2002/02/24 17:10:34 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.12 2001/12/13 06:45:35 tilda
+ * IID488021 - Various bugs with quoted printable format.
+ *
+ * Revision 1.11 2001/10/24 18:36:06 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.10 2001/10/24 05:32:19 tilda
+ * BASE64 bugfixes - first part
+ *
+ * Revision 1.9 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.8 2001/10/14 19:53:36 tilda
+ * Group handling. NO group searching functions.
+ *
+ * Revision 1.7 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.6 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.5 2001/10/13 14:49:30 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ * Revision 1.4 2001/10/12 16:20:03 tilda
+ * Correctly parse compound quoted printable properties.
+ *
+ * Revision 1.3 2001/10/10 20:53:56 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *****************************************************************************/
+
+#ifndef NORCSID
+static const char vf_parser_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_parser.c,v 1.22 2002/11/16 13:19:10 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *===========================================================================*/
+
+#include <common/types.h>
+
+/*============================================================================*
+ Interface Header Files
+ *===========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *===========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*============================================================================*
+ Public Data
+ *===========================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *===========================================================================*/
+
+/*
+ * Significant characters.
+ */
+#define PERIOD '.'
+#define COLON ':'
+#define SEMICOLON ';'
+#define LINEFEED '\n'
+#define CRETURN '\r'
+#define TAB '\t'
+#define BACKSLASH '\\'
+#define SPACE ' '
+#define EQUALS '='
+#define PERIOD '.'
+
+/*
+ * dec hex oct char
+ * 10 0x0A 012 LF NL, line feed, new line, \n
+ * 13 0x0D 015 CR carriage return, \r
+ *
+ * => <CR><LF> = 0x0D 0x0A
+ */
+
+/*
+ * States associated with propname:propvalue parsing.
+ */
+#define _VF_STATE_PROPNAME (1) /* reading name (including groupings) */
+#define _VF_STATE_PROPNAMEESCAPE (2) /* escaped semicolon in name */
+#define _VF_STATE_RFC822VALUE (3) /* basic */
+#define _VF_STATE_RFC822VALUEFOLD (4) /* waiting for line fold (simple fields) */
+#define _VF_STATE_QPIDLE (5) /* Non escaped position in QP */
+#define _VF_STATE_QPIDLENL (6) /* Non escaped position in QP */
+#define _VF_STATE_QPEQUALSC1 (7) /* After = in QP */
+#define _VF_STATE_QPEQUALSC2 (8) /* After =X in QP */
+#define _VF_STATE_BASE64 (9) /* Reading BASE64 */
+
+#define ISCRORNL(c) ((CRETURN == (c)) || (LINEFEED == (c)))
+
+/*============================================================================*
+ Private Data Types
+ *===========================================================================*/
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * Maintains state variables etc. for current VOBJECT_T parsing.
+ *----------------------------------------------------------------------------*/
+
+typedef struct
+{
+ int state; /* Main state variable */
+ char qpchar; /* Workspace for QuotedPrintable decoder */
+ char *p_b64buf; /* Workspace for BASE64 decoder */
+ VOBJECT_T **pp_root_object; /* Pointer to the root */
+ VOBJECT_T *p_object; /* Current position in tree */
+ VPROP_T prop; /* Current property, copied into tree on completion */
+}
+VPARSE_T;
+
+/*============================================================================*
+ Private Function Prototypes
+ *===========================================================================*/
+
+static bool_t append_value_to_object(
+ VPROP_T **pp_prop, /* Pointer to the new property */
+ VPARSE_T *p_parse /* The property we're naming */
+ );
+
+static bool_t handle_base64_chars(
+ VPARSE_T *p_parse, /* The property value we're adding to */
+ const char *p_chars, /* Pointer to characters to add */
+ int numchars /* Number of characters */
+ );
+
+static vf_encoding_t deduce_encoding(
+ VSTRARRAY_T *p_propname /* Property name */
+ );
+
+static uint8_t base64_to_char(
+ char c /* Character to convert */
+ );
+
+static bool_t is_hex_digit(
+ char *p_nibble, /* Output nibble value */
+ char c /* Character read from file */
+ );
+
+static bool_t handle_value_complete(
+ VPARSE_T *p_parse /* Current parse state info */
+ );
+
+static bool_t alloc_next_object(
+ VPARSE_T *p_parse, /* Current parse state info */
+ char *p_type /* Type of object */
+ );
+
+static bool_t alloc_sub_object(
+ VPARSE_T *p_parse, /* Current parse state info */
+ char *p_type /* Type of object */
+ );
+
+static bool_t alloc_object(
+ VOBJECT_T **pp_new, /* Pointer to output pointer */
+ VOBJECT_T *p_parent, /* Parent of new node */
+ char *p_type, /* Type of new node */
+ VPARSE_T *p_parse /* Current parse info */
+ );
+
+static bool_t append_group_name(
+ VPROP_T *p_prop /* Property we're updating */
+ );
+
+
+/*============================================================================*
+ Private Data
+ *===========================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *===========================================================================*/
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_init()
+ *
+ * DESCRIPTION
+ * Initialise a parsing instance.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_parse_init(
+ VF_PARSER_T **pp_parser, /* The parser */
+ VF_OBJECT_T **pp_object /* The object we're parsing into */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (pp_parser && pp_object)
+ {
+ VPARSE_T *p_parse = (VPARSE_T *)vf_malloc(sizeof(VPARSE_T));
+
+ if (p_parse)
+ {
+ p_memset(p_parse, '\0', sizeof(VPARSE_T));
+
+ p_parse->state = _VF_STATE_PROPNAME;
+ p_parse->p_object = NULL;
+ p_parse->pp_root_object = (VOBJECT_T **)pp_object;
+
+ *pp_parser = (VF_PARSER_T *)p_parse;
+
+ *pp_object = NULL;
+
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_text()
+ *
+ * DESCRIPTION
+ * Parse indicated text into the object associated with the VPARSE_T.
+ *
+ * RETURNS
+ * TRUE <=> allocation & syntax OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_parse_text(
+ VF_PARSER_T *p_parser, /* The parser */
+ char *p_chars, /* New characters to parse into object */
+ int numchars /* Number of new characters */
+ )
+{
+ int i;
+ bool_t ok;
+ VPARSE_T *p_parse = (VPARSE_T *)p_parser;
+
+ /*
+ * Check pointer.
+ */
+ if (!p_parse)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Push each character through the state machine.
+ */
+ for (i = 0, ok = TRUE;ok && (i < numchars);i++)
+ {
+ char c = p_chars[i];
+
+ switch (p_parse->state)
+ {
+ case _VF_STATE_RFC822VALUEFOLD:
+ {
+ if (ISCRORNL(c))
+ {
+ /* Ignore */
+ }
+ else
+ if (SPACE == c)
+ {
+ ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1);
+
+ p_parse->state = _VF_STATE_RFC822VALUE;
+ }
+ else
+ {
+ ok = handle_value_complete(p_parse);
+
+ p_parse->state = _VF_STATE_PROPNAME;
+ }
+ }
+ if (_VF_STATE_PROPNAME == p_parse->state)
+ {
+ /* Fall through */
+ }
+ else
+ {
+ break;
+ }
+
+ /* Fall through */
+
+
+ case _VF_STATE_PROPNAME:
+ {
+ if (COLON == c)
+ {
+ p_parse->prop.value.encoding = deduce_encoding(&p_parse->prop.name);
+
+ switch (p_parse->prop.value.encoding)
+ {
+ case VF_ENC_7BIT:
+ p_parse->state = _VF_STATE_RFC822VALUE;
+ break;
+
+ case VF_ENC_BASE64:
+ p_parse->state = _VF_STATE_BASE64;
+ break;
+
+ case VF_ENC_QUOTEDPRINTABLE:
+ p_parse->state = _VF_STATE_QPIDLE;
+ break;
+
+ default:
+ ok = FALSE;
+ break;
+ }
+ }
+ else
+ if (BACKSLASH == c)
+ {
+ p_parse->state = _VF_STATE_PROPNAMEESCAPE;
+ }
+ else
+ if (ISCRORNL(c))
+ {
+ /* ignore */
+
+ free_string_array_contents(&p_parse->prop.name);
+ }
+ else
+ if (SEMICOLON == c)
+ {
+ ok = add_string_to_array(&p_parse->prop.name, "");
+ }
+ else
+ if (PERIOD == c)
+ {
+ ok = append_group_name(&p_parse->prop);
+ }
+ else
+ {
+ ok = append_to_curr_string(&(p_parse->prop.name), NULL, &c, 1);
+ }
+ }
+ break;
+
+ case _VF_STATE_PROPNAMEESCAPE:
+ {
+ if (SEMICOLON == c)
+ {
+ ok = append_to_curr_string(&(p_parse->prop.name), NULL, &c, 1);
+ }
+ else
+ {
+ ok = FALSE;
+ }
+ }
+ break;
+
+ case _VF_STATE_RFC822VALUE:
+ {
+ if (p_parse->prop.value.v.s.pp_strings)
+ {
+ /* Already allocated */
+ }
+ else
+ {
+ ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL);
+ }
+
+ if (ISCRORNL(c))
+ {
+ p_parse->state = _VF_STATE_RFC822VALUEFOLD;
+ }
+ else
+ if (SEMICOLON == c)
+ {
+ ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL);
+ }
+ else
+ {
+ ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1);
+ }
+ }
+ break;
+
+ case _VF_STATE_QPIDLENL:
+ {
+ if (ISCRORNL(c))
+ {
+ break;
+ }
+ else
+ {
+ p_parse->state = _VF_STATE_QPIDLE;
+ }
+ }
+
+ case _VF_STATE_QPIDLE:
+ {
+ if (p_parse->prop.value.v.s.pp_strings)
+ {
+ /* Already allocated */
+ }
+ else
+ {
+ ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL);
+ }
+
+ if (EQUALS == c)
+ {
+ p_parse->qpchar = 0x00;
+ p_parse->state = _VF_STATE_QPEQUALSC1;
+ }
+ else
+ if (SEMICOLON == c)
+ {
+ ok = add_string_to_array(&(p_parse->prop.value.v.s), NULL);
+ }
+ else
+ if (ISCRORNL(c))
+ {
+ ok = handle_value_complete(p_parse);
+ }
+ else
+ {
+ ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &c, 1);
+ }
+ }
+ break;
+
+ case _VF_STATE_QPEQUALSC1:
+ {
+ uint8_t nibble;
+
+ if (ISCRORNL(c))
+ {
+ p_parse->state = _VF_STATE_QPIDLENL;
+ }
+ else
+ if (is_hex_digit(&nibble, c))
+ {
+ (p_parse->qpchar) <<= 4;
+ (p_parse->qpchar) |= nibble;
+
+ p_parse->state = _VF_STATE_QPEQUALSC2;
+ }
+ else
+ {
+ ok = FALSE;
+ }
+ }
+ break;
+
+ case _VF_STATE_QPEQUALSC2:
+ {
+ uint8_t nibble;
+
+ if (is_hex_digit(&nibble, c))
+ {
+ (p_parse->qpchar) <<= 4;
+ (p_parse->qpchar) |= nibble;
+
+ ok = append_to_curr_string(&(p_parse->prop.value.v.s), NULL, &(p_parse->qpchar), 1);
+
+ p_parse->state = _VF_STATE_QPIDLE;
+ }
+ else
+ {
+ ok = FALSE;
+ }
+ }
+ break;
+
+ case _VF_STATE_BASE64:
+ {
+ /*
+ * The cr/nl stuff associated with line ends & termination of BASE64 encoding
+ * seems to be particularly problematic. Searching and reading vCards from the
+ * internet shows that all sorts of wierd things are out there in use! In the
+ * interests of interoperability we look for the next value as an indication of
+ * the end of the object. We build up each line and if it's still in BASE64
+ * format append the decoded data. Otherwise we use the parser recursively to
+ * decode the buffered text, which is probably something like "NEXT-VALUE:"
+ */
+
+ if (ISCRORNL(c))
+ {
+ if (p_parse->p_b64buf)
+ {
+ ok = handle_base64_chars(p_parse, p_parse->p_b64buf, p_strlen(p_parse->p_b64buf));
+
+ vf_free(p_parse->p_b64buf);
+ p_parse->p_b64buf = NULL;
+ }
+ }
+ else
+ {
+ ok = append_to_pointer(&(p_parse->p_b64buf), NULL, &c, 1);
+
+ if ((COLON == c) || (SEMICOLON == c))
+ {
+ ok = handle_value_complete(p_parse);
+
+ ok = vf_parse_text(p_parser, p_parse->p_b64buf, p_strlen(p_parse->p_b64buf));
+
+ vf_free(p_parse->p_b64buf);
+ p_parse->p_b64buf = NULL;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ /* no need to panic */
+ }
+ else
+ {
+ vf_delete_object((VF_OBJECT_T *)*(p_parse->pp_root_object), TRUE);
+ *(p_parse->pp_root_object) = NULL;
+ p_parse->p_object = NULL;
+
+ if (p_parse->p_b64buf)
+ {
+ vf_free(p_parse->p_b64buf);
+ p_parse->p_b64buf = NULL;
+ }
+
+ delete_prop_contents((VF_PROP_T *)&p_parse->prop, TRUE);
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_end()
+ *
+ * DESCRIPTION
+ * Ensure parse completion.
+ *
+ * RETURNS
+ * TRUE <=> allocation & syntax OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_parse_end(
+ VF_PARSER_T *p_parser /* The parser */
+ )
+{
+ bool_t ret = FALSE;
+ VPARSE_T *p_parse = (VPARSE_T *)p_parser;
+
+ /*
+ * Check pointer.
+ */
+ if (p_parse)
+ {
+ ret = handle_value_complete(p_parse);
+
+ vf_free(p_parse);
+ }
+
+ return ret;
+}
+
+
+
+
+/*============================================================================*
+ Private Functions
+ *===========================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_group_name()
+ *
+ * DESCRIPTION
+ * After reading a ".", we transfer the segment of name we've read (which
+ * must be the first string <G>) into the group name. Keep the group name
+ * in one string of "." tokens for simplicity, so we may end up with a
+ * group called "X-PHONE-BOOK.ENTRY.1" etc.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t append_group_name(
+ VPROP_T *p_prop
+ )
+{
+ bool_t ok = TRUE;
+
+ if (p_prop->p_group)
+ {
+ ok &= append_to_pointer(&p_prop->p_group, NULL, ".", 1);
+ }
+
+ if (ok)
+ {
+ const char *p_string = p_prop->name.pp_strings[0];
+
+ ok &= append_to_pointer(&p_prop->p_group, NULL, p_string, p_strlen(p_string));
+
+ if (ok)
+ {
+ vf_free(p_prop->name.pp_strings[0]);
+ p_prop->name.pp_strings[0] = NULL;
+ }
+ }
+
+ return ok;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * handle_value_complete()
+ *
+ * DESCRIPTION
+ * Called when a complete value is parsed.
+ *
+ * RETURNS
+ * (none).
+ *---------------------------------------------------------------------------*/
+
+bool_t handle_value_complete(
+ VPARSE_T *p_parse /* Current parse state info */
+ )
+{
+ bool_t ret = TRUE;
+ VOBJECT_T *p_object;
+
+ /*
+ * If we've got no object open we ignore values until we read a BEGIN at which point
+ * we create a vformat object and start to parse properties into it. If we subsequently
+ * read a BEGIN we add a property & parse the next vobject into that. Each time we read
+ * an END we pop the pp_object pointer back up to the owner of the object we're parsing
+ * into. There should be an easier way of doing this <G> ...
+ */
+
+ p_object = p_parse->p_object;
+
+ if (p_object)
+ {
+ if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_BEGIN, TRUE))
+ {
+ char *p_type;
+
+ p_type = p_parse->prop.value.v.s.pp_strings[0];
+ p_parse->prop.value.v.s.pp_strings[0] = NULL;
+
+ delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE);
+
+ p_parse->prop.value.encoding = VF_ENC_VOBJECT;
+
+ ret = add_string_to_array(&(p_parse->prop.name), p_type) &&
+ alloc_sub_object(p_parse, p_type);
+ }
+ else
+ if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_END, TRUE))
+ {
+ delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE);
+
+ p_parse->p_object = p_parse->p_object->p_parent;
+ }
+ else
+ {
+ ret = append_value_to_object(NULL, p_parse);
+ }
+ }
+ else
+ {
+ if (string_array_contains_string(&p_parse->prop.name, NULL, 0, VFP_BEGIN, TRUE))
+ {
+ char *p_type;
+
+ p_type = p_parse->prop.value.v.s.pp_strings[0];
+ p_parse->prop.value.v.s.pp_strings[0] = NULL;
+
+ ret = alloc_next_object(p_parse, p_type);
+ }
+
+ delete_prop_contents((VF_PROP_T *)(&(p_parse->prop)), TRUE);
+ }
+
+ p_parse->state = _VF_STATE_PROPNAME;
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * alloc_next_object()
+ *
+ * DESCRIPTION
+ * Allocate the "next" object, ie. annother vformat tagged to the p_next
+ * pointer to the current one.
+ *
+ * RETURNS
+ * TRUE iff memory allocated OK, FALSE else OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t alloc_next_object(
+ VPARSE_T *p_parse, /* Current parse state info */
+ char *p_type /* Type of object */
+ )
+{
+ bool_t ok = TRUE;
+ VOBJECT_T *p_parent = p_parse->p_object;
+ VOBJECT_T *p_new = NULL;
+
+ ok = alloc_object(&p_new, p_parent ? p_parent->p_parent : NULL, p_type, p_parse);
+
+ if (ok)
+ {
+ if (*p_parse->pp_root_object)
+ {
+ /* root object already set */
+
+ if (p_new->p_parent)
+ {
+ /* Owned by property */
+ }
+ else
+ {
+ /* Need to tag to end of top list */
+
+ VOBJECT_T **pp_tmp = p_parse->pp_root_object;
+
+ while (*pp_tmp)
+ {
+ pp_tmp = &((*pp_tmp)->p_next);
+ }
+
+ *pp_tmp = p_new;
+ }
+ }
+ else
+ {
+ *p_parse->pp_root_object = p_new;
+ }
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * alloc_sub_object()
+ *
+ * DESCRIPTION
+ * Allocate "sub" object, ie. annother vformat tagged to the p_object
+ * pointer of a VPROP_T allocated to contain it.
+ *
+ * RETURNS
+ * TRUE iff memory allocated OK, FALSE else OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t alloc_sub_object(
+ VPARSE_T *p_parse, /* Current parse state info */
+ char *p_type /* Type of object */
+ )
+{
+ bool_t ok = FALSE;
+ VOBJECT_T *p_parent = p_parse->p_object;
+
+ if (p_parent)
+ {
+ VPROP_T *p_tmp;
+
+ ok = append_value_to_object(&p_tmp, p_parse);
+
+ if (ok && p_tmp)
+ {
+ ok = alloc_object(&p_tmp->value.v.o.p_object, p_parent, p_type, p_parse);
+ }
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * alloc_object()
+ *
+ * DESCRIPTION
+ * Allocate & initialise a new VOBJECT_T. The new element od made the
+ * current parse target (ie. new properties will be added to it).
+ *
+ * RETURNS
+ * TRUE <=> allocation went OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t alloc_object(
+ VOBJECT_T **pp_new, /* Pointer to output pointer */
+ VOBJECT_T *p_parent, /* Parent of new node */
+ char *p_type, /* Type of new node */
+ VPARSE_T *p_parse /* Current parse info */
+ )
+{
+ bool_t ok = TRUE;
+ VOBJECT_T *p_new;
+
+ p_new = (VOBJECT_T *)vf_malloc(sizeof(VOBJECT_T));
+
+ if (p_new)
+ {
+ p_memset(p_new, '\0', sizeof(VOBJECT_T));
+
+ p_new->p_parent = p_parent;
+ p_new->p_type = p_type;
+
+ p_parse->p_object = p_new;
+
+ *pp_new = p_new;
+ }
+ else
+ {
+ ok = FALSE;
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * handle_base64_chars()
+ *
+ * DESCRIPTION
+ * Handle BASE64 decoding.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t handle_base64_chars(
+ VPARSE_T *p_parse, /* The property value we're adding to */
+ const char *p_chars, /* Pointer to characters to add */
+ int numchars /* Number of characters */
+ )
+{
+ bool_t ok = TRUE;
+
+ /*
+ * Skip spaces.
+ */
+ while ((0 < numchars) && (SPACE == p_chars[0]))
+ {
+ numchars--;
+ p_chars++;
+ }
+
+ /*
+ * Convert groups of 4 characters to byte triplets & append the bytes
+ * to the binary data.
+ */
+ if (0 < numchars)
+ {
+ int i, j, len, num, left;
+ const char *p_quad;
+
+ len = numchars;
+ num = len / 4;
+ left = len % 4;
+
+ for (i = 0, p_quad = p_chars;(i < num);i++, p_quad += 4)
+ {
+ uint32_t b;
+ char bytes[3];
+ uint8_t bits;
+
+ for (j = 0, b = 0, bits = 0;(j < 4);j++)
+ {
+ b = (b << 6) | base64_to_char(p_quad[j]);
+
+ if (EQUALS != p_quad[j])
+ {
+ bits += 6;
+ }
+ }
+
+ for (j = 0;(j < 3);j++)
+ {
+ bytes[2 - j] = (unsigned char)(b & 0xFF);
+
+ b >>= 8;
+ }
+
+ ok = append_to_pointer(&(p_parse->prop.value.v.b.p_buffer), &(p_parse->prop.value.v.b.n_bufsize), bytes, bits / 8);
+ }
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_value_to_object()
+ *
+ * DESCRIPTION
+ * Append characters to the name half of a VOBJECT_T. The VOBJECT is
+ * allocated if not already present.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+bool_t append_value_to_object(
+ VPROP_T **pp_prop, /* Pointer to the new property */
+ VPARSE_T *p_parse /* The property we're naming */
+ )
+{
+ bool_t ok = FALSE;
+
+ VPROP_T **pp_tmp;
+ VPROP_T *p_prop;
+
+ pp_tmp = &(p_parse->p_object->p_props);
+
+ while (*pp_tmp)
+ {
+ pp_tmp = &((*pp_tmp)->p_next);
+ }
+
+ *pp_tmp = p_prop = (VPROP_T *)vf_malloc(sizeof(VPROP_T));
+
+ if (pp_prop)
+ {
+ *pp_prop = p_prop;
+ }
+
+ if (p_prop)
+ {
+ p_memset(p_prop, '\0', sizeof(VPROP_T));
+
+ *p_prop = p_parse->prop;
+
+ p_memset(&(p_parse->prop), '\0', sizeof(VPROP_T));
+
+ p_prop->p_parent = p_parse->p_object;
+
+ ok = TRUE;
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * deduce_encoding()
+ *
+ * DESCRIPTION
+ * Check property name for encoding tags. If none present, return the
+ * default encoding.
+ *
+ * RETURNS
+ * vf_encoding_t.
+ *---------------------------------------------------------------------------*/
+
+vf_encoding_t deduce_encoding(
+ VSTRARRAY_T *p_propname /* Property name */
+ )
+{
+ vf_encoding_t ret = VF_ENC_7BIT;
+
+ if (string_array_contains_string(p_propname, NULL, -1, VFP_QUOTEDPRINTABLE, FALSE))
+ {
+ ret = VF_ENC_QUOTEDPRINTABLE;
+ }
+ else
+ if (string_array_contains_string(p_propname, NULL, -1, VFP_BASE64, FALSE))
+ {
+ ret = VF_ENC_BASE64;
+ }
+ else
+ if (string_array_contains_string(p_propname, NULL, -1, VFP_8BIT, FALSE))
+ {
+ ret = VF_ENC_8BIT;
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * is_hex_digit()
+ *
+ * DESCRIPTION
+ *
+ *
+ * RETURNS
+ * TRUE <=> valid HEX digit read.
+ *---------------------------------------------------------------------------*/
+
+bool_t is_hex_digit(
+ char *p_nibble, /* Output nibble value */
+ char c /* Character read from file */
+ )
+{
+ bool_t ret = TRUE;
+
+ if (('A' <= c) && (c <= 'F'))
+ {
+ *p_nibble = c - 'A' + 10;
+ }
+ else
+ if (('a' <= c) && (c <= 'f'))
+ {
+ *p_nibble = c - 'a' + 10;
+ }
+ else
+ if (('0' <= c) && (c <= '9'))
+ {
+ *p_nibble = c - '0';
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * base64_to_char()
+ *
+ * DESCRIPTION
+ * Convert base 64 char to byte.
+ *
+ * RETURNS
+ * Number corresponding to char.
+ *---------------------------------------------------------------------------*/
+
+uint8_t base64_to_char(char c)
+{
+ if (('A' <= c) && (c <= 'Z'))
+ return c - 'A';
+
+ if (('a' <= c) && (c <= 'z'))
+ return c - 'a' + 26;
+
+ if (('0' <= c) && (c <= '9'))
+ return c - '0' + 52;
+
+ if ('+' == c)
+ return 62;
+
+ if ('/' == c)
+ return 63;
+
+ return 0x00;
+}
+
+
+/*============================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_reader.c b/src/vf_reader.c
new file mode 100644
index 0000000..667279f
--- /dev/null
+++ b/src/vf_reader.c
@@ -0,0 +1,277 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_reader.c $
+ $Revision: 1.18 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley.
+
+DESCRIPTION
+ Code for reading vformat files from disk. Delegates the real responsibility
+ to vf_parser for actually converting chunks of text into the memory data
+ structure.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_reader.c,v $
+ * Revision 1.18 2002/11/15 09:20:59 tilda
+ * IID638823 - Don't include unistd.h unless required.
+ *
+ * Revision 1.17 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.16 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.15 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.14 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.13 2001/12/13 06:45:35 tilda
+ * IID488021 - Various bugs with quoted printable format.
+ *
+ * Revision 1.12 2001/11/05 21:07:19 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.11 2001/10/24 18:36:06 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.10 2001/10/24 05:32:19 tilda
+ * BASE64 bugfixes - first part
+ *
+ * Revision 1.9 2001/10/16 05:50:53 tilda
+ * Debug support for lists of vobjects from single file (ie. a phonebook).
+ *
+ * Revision 1.8 2001/10/14 19:53:36 tilda
+ * Group handling. NO group searching functions.
+ *
+ * Revision 1.7 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.6 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.5 2001/10/13 14:49:30 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ * Revision 1.4 2001/10/12 16:20:02 tilda
+ * Correctly parse compound quoted printable properties.
+ *
+ * Revision 1.3 2001/10/10 20:53:55 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_reader_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_reader.c,v 1.18 2002/11/15 09:20:59 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *=============================================================================*/
+
+#include <common/types.h>
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#if defined(HAS_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#if defined(WIN) || defined(WIN32)
+#include <io.h>
+#endif
+
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include <vformat/vf_iface.h>
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_internals.h"
+#include "vf_malloc.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+
+#define PARSEBUFSIZE (1024)
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_read_file()
+ *
+ * DESCRIPTION
+ * Reads indicated VOBJECT_T file.
+ *
+ * RETURNS
+ * TRUE <=> read OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t vf_read_file(
+ VF_OBJECT_T **pp_object,
+ const char *p_name
+ )
+{
+ bool_t ret = FALSE;
+
+ if (pp_object)
+ {
+ FILE *fp;
+
+ fp = fopen(p_name, "rb");
+
+ if (fp)
+ {
+ char buffer[PARSEBUFSIZE];
+ int charsread;
+ VF_PARSER_T *p_parser;
+
+ if (vf_parse_init(&p_parser, pp_object))
+ {
+ do
+ {
+ charsread = read(fileno(fp), buffer, sizeof(buffer));
+
+ if (0 < charsread)
+ {
+ ret = vf_parse_text(p_parser, buffer, charsread);
+ }
+ }
+ while (ret && (0 < charsread))
+ ;
+
+ if (!vf_parse_end(p_parser))
+ {
+ ret = FALSE;
+ }
+ }
+
+ if (0 == fclose(fp))
+ {
+ /* OK */
+ }
+ else
+ {
+ ret = FALSE;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_property_from_file()
+ *
+ * DESCRIPTION
+ * Loads the indicated file into memory and sets the indicated property.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_set_property_from_file(
+ VF_PROP_T *p_prop, /* The property */
+ vf_encoding_t encoding, /* Encoding to use */
+ const char *p_filename /* Source filename */
+ )
+{
+ bool_t ret = FALSE;
+ struct stat buf;
+
+ if (0 == stat(p_filename, &buf))
+ {
+ uint8_t *p_data = vf_malloc(buf.st_size);
+
+ if (p_data)
+ {
+ FILE *fp = fopen(p_filename, "rb");
+
+ if (fp)
+ {
+ if ((int)buf.st_size == read(fileno(fp), p_data, buf.st_size))
+ {
+ ret = TRUE;
+ }
+
+ if (0 == fclose(fp))
+ {
+ /* */
+ }
+ else
+ {
+ ret = FALSE;
+ }
+
+ if (ret)
+ {
+ ret &= vf_set_prop_value(p_prop, p_data, buf.st_size, encoding, TRUE);
+ }
+ }
+
+ vf_free(p_data);
+ }
+ }
+
+ return ret;
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_search.c b/src/vf_search.c
new file mode 100644
index 0000000..71be484
--- /dev/null
+++ b/src/vf_search.c
@@ -0,0 +1,457 @@
+/****************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_access.c $
+ $Revision: 1.11 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Basic searching functions for the vformat library.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_search.c,v $
+ * Revision 1.11 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.10 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.9 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.8 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.7 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.6 2002/02/24 17:10:34 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.5 2001/11/18 21:46:59 tilda
+ * Remove redundant code.
+ *
+ * Revision 1.4 2001/11/16 22:34:50 tilda
+ * New vf_get_property() allows append as well as find,
+ *
+ * Revision 1.3 2001/11/05 21:07:19 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.2 2001/10/24 18:56:29 tilda
+ * Tidy headers after import. Fix include path in release build.
+ *
+ * Revision 1.1 2001/10/24 18:34:35 tilda
+ * Initial Version.
+ *
+ *****************************************************************************/
+
+#ifndef NORCSID
+static const char vf_search_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_search.c,v 1.11 2002/11/03 18:43:16 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <common/types.h>
+
+/*===========================================================================*
+ Interface Header Files
+ *===========================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*===========================================================================*
+ Local Header File
+ *===========================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*===========================================================================*
+ Public Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Defines
+ *===========================================================================*/
+
+/*
+ * Maximum supported search tags.
+ */
+#define MAXNUMTAGS (10)
+
+/*===========================================================================*
+ Private Data Types
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Private Function Prototypes
+ *===========================================================================*/
+
+
+/*===========================================================================*
+ Private Data
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ Public Function Implementations
+ *===========================================================================*/
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_property()
+ *
+ * DESCRIPTION
+ * Basic searching function locating elements of the VOBJECT by qualified
+ * name. The function is a varargs function (like sprintf) and the list
+ * of arguments must be NULL terminated (hence the appearance of the
+ * p_qualifier argument in the arglist). Valid calls might be:
+ *
+ * vf_get_property(&p_out, p_object, FALSE, NULL, "N", NULL);
+ * vf_get_property(&p_out, p_object, FALSE, NULL, "TEL", "WORK", NULL);
+ * vf_get_property(&p_out, p_object, FALSE, "ME", "TEL", "WORK", NULL);
+ * vf_get_property(&p_out, p_object, FALSE, "ME", "*", NULL);
+ *
+ * A pointer to the first property matching the search criteria is returned
+ * the pp_prop argument. The search actually locates all such matches and
+ * pointer to subsequent entries (if there are >1) may be found by calling
+ * the vf_get_next_property() function.
+ *
+ * Qualifying tags (ie. not the name) may occur in any order
+ *
+ * Note that the VF_PROP_T returned vi pp_prop is an opaque type and the
+ * various accessor functions must be used to get to the data.
+ *
+ * RETURNS
+ * TRUE iff found/added successfully. ptr to prop returned via pp_prop.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_property(
+ VF_PROP_T **pp_prop, /* Output pointer */
+ VF_OBJECT_T *p_object, /* Object to add to */
+ vf_get_t ops, /* Search flags */
+ const char *p_group, /* Group name if any */
+ const char *p_name, /* Name of tag */
+ const char *p_qualifier, /* First qualifier if any */
+ ... /* Subequent qualifiers */
+ )
+{
+ bool_t ret = FALSE;
+ va_list args;
+
+ va_start(args, p_qualifier);
+
+ ret = vf_get_property_ex(pp_prop, p_object, ops, p_group, p_name, p_qualifier, args);
+
+ va_end(args);
+
+ return ret;
+}
+
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_property_ex()
+ *
+ * DESCRIPTION
+ * The grunt behind vf_get_property(). Manages the search as described
+ * vf_get_property() but takes the list of arguments as a va_list.
+ *
+ * RETURNS
+ * TRUE iff found / appended OK.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_property_ex(
+ VF_PROP_T **pp_prop, /* Output pointer */
+ VF_OBJECT_T *p_object, /* Object to search */
+ vf_get_t ops, /* Search flags */
+ const char *p_group, /* Group name if any */
+ const char *p_name, /* Name of tag */
+ const char *p_qualifier, /* First qualifier if any */
+ va_list args /* Argument list */
+ )
+{
+ bool_t ret = FALSE;
+ char **pp_tags = NULL;
+
+ if (!p_name || !p_object)
+ return ret;
+
+ if (pp_prop)
+ {
+ *pp_prop = NULL;
+ }
+
+ pp_tags = (char **)vf_malloc(MAXNUMTAGS * sizeof(char *));
+
+ if (pp_tags)
+ {
+ VOBJECT_T *p_obj = (VOBJECT_T *)p_object;
+ VPROP_T *p_props = p_obj->p_props;
+ int i;
+
+ VPROP_T **pp_lastprop = &(p_obj->p_props);
+ VPROP_T **pp_next_srch = NULL;
+
+ p_memset(pp_tags, '\0', MAXNUMTAGS * sizeof(char *));
+
+ pp_tags[0] = (char *)p_name;
+
+ /*
+ * The name is the first tag. We insist on there being at least one qualifier in the
+ * argument list to make sure callers terminate the list. Subsequent arguments are
+ * optional, but will be ignored if the (first) qualifier is NULL.
+ */
+ if (p_qualifier)
+ {
+ pp_tags[1] = (char *)p_qualifier;
+
+ for (i = 2;i < MAXNUMTAGS;i++)
+ {
+ char *p_tag = va_arg(args, char *);
+
+ if (p_tag)
+ {
+ pp_tags[i] = p_tag;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ if (ops & VFGP_FIND)
+ {
+ /*
+ * Skip down the list or properties. I'm assuming that we only want to search the
+ * current object for properties not the current object AND any contained objects.
+ * Such a search sounds a bit application specific, ie. the caller would be looking
+ * for a particular structure of things. Each element that is found is stitched
+ * into the emerging list.
+ */
+ for (;NULL != p_props;p_props = p_props->p_next)
+ {
+ bool_t found = TRUE;
+
+ /*
+ * Check the name & qualifiers.
+ */
+ for (i = 0;found && (i < MAXNUMTAGS) && pp_tags[i];i++)
+ {
+ if (0 != p_strcmp(VFP_ANY, pp_tags[i]))
+ found &= string_array_contains_string(&p_props->name, NULL, -1, pp_tags[i], TRUE);
+ }
+ if (p_group && found)
+ {
+ found = FALSE;
+
+ if (p_props->p_group)
+ {
+ if (0 == p_stricmp(p_props->p_group, p_group))
+ {
+ found = TRUE;
+ }
+ }
+ else
+ {
+ /* Search group specified & property doesn't have a group => not required */
+ }
+ }
+
+ if (found)
+ {
+ if (pp_prop)
+ {
+ if (!*pp_prop)
+ {
+ pp_next_srch = &(p_props->p_next_srch);
+ p_props->p_next_srch = NULL;
+
+ *pp_prop = (VF_PROP_T *)p_props;
+ }
+ else
+ {
+ *pp_next_srch = p_props;
+
+ pp_next_srch = &(p_props->p_next_srch);
+ p_props->p_next_srch = NULL;
+ }
+ }
+
+ ret = TRUE;
+ }
+
+ if (p_props->p_next)
+ {
+ pp_lastprop = &(p_props->p_next);
+ }
+ }
+ }
+
+ if (!ret && (ops & VFGP_APPEND))
+ {
+ VPROP_T *p_new = (VPROP_T *)vf_malloc(sizeof(VPROP_T));
+
+ if (p_new)
+ {
+ ret = TRUE;
+
+ p_memset(p_new, '\0', sizeof(VPROP_T));
+
+ p_new->p_parent = p_obj;
+
+ for (i = 0;ret && (i < MAXNUMTAGS) && pp_tags[i];i++)
+ {
+ ret = add_string_to_array(&p_new->name, pp_tags[i]);
+ }
+
+ if (ret)
+ {
+ /* All OK */
+
+ p_new->value.encoding = VF_ENC_7BIT;
+ }
+ else
+ {
+ free_string_array_contents(&p_new->name);
+
+ vf_free(p_new);
+ p_new = NULL;
+ }
+ }
+
+ if (p_new)
+ {
+ if (pp_prop)
+ {
+ *pp_prop = (VF_PROP_T *)p_new;
+ }
+
+ p_new->p_next = *pp_lastprop;
+ *pp_lastprop = p_new;
+
+ ret = TRUE;
+ }
+ }
+
+ vf_free(pp_tags);
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_next_property()
+ *
+ * DESCRIPTION
+ * Find the next property given the current search critera.
+ *
+ * RETURNS
+ * TRUE iff found, FALSE else. *pp_prop points to the next property.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_next_property(
+ VF_PROP_T **pp_prop /* Output pointer */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (pp_prop)
+ {
+ VPROP_T **pp_vprop = (VPROP_T **)pp_prop;
+
+ if (*pp_vprop)
+ {
+ *pp_prop = (VF_PROP_T *)((*pp_vprop)->p_next_srch);
+
+ if (*pp_prop)
+ {
+ ret = TRUE;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_next_object()
+ *
+ * DESCRIPTION
+ * Find "next" vobject.
+ *
+ * RETURNS
+ * TRUE iff found next object.
+ *---------------------------------------------------------------------------*/
+
+bool_t vf_get_next_object(
+ VF_OBJECT_T **pp_object
+ )
+{
+ bool_t ret = FALSE;
+
+ if (pp_object)
+ {
+ if (*pp_object)
+ {
+ *pp_object = (VF_OBJECT_T *)(((VOBJECT_T *)(*pp_object))->p_next);
+
+ if (*pp_object)
+ {
+ ret = TRUE;
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+/*===========================================================================*
+ Private Function Implementations
+ *===========================================================================*/
+/* None */
+
+/*===========================================================================*
+ End Of File
+ *===========================================================================*/
diff --git a/src/vf_string_arrays.c b/src/vf_string_arrays.c
new file mode 100644
index 0000000..eee27f4
--- /dev/null
+++ b/src/vf_string_arrays.c
@@ -0,0 +1,435 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_access.c $
+ $Revision: 1.4 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Utility functions handling string arrays - the VSTRARRAY_T type.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_string_arrays.c,v $
+ * Revision 1.4 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.3 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.2 2002/10/29 07:19:20 tilda
+ * Tidy headers.
+ *
+ * Revision 1.1 2002/10/26 15:57:11 tilda
+ * Initial Version
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_string_arrays_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_string_arrays.c,v 1.4 2002/11/03 18:43:16 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *=============================================================================*/
+
+#include <common/types.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_malloc.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+#include "vf_string_arrays.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * string_array_contains_string()
+ *
+ * DESCRIPTION
+ * Checks the strings in the indicated array to see if it contains a
+ * particulr value. Can check a particular index or the whole array.
+ * Can perform an exact match or check wether one of the strings simply
+ * contains the value.
+ *
+ * RETURNS
+ * TRUE <=> includes indicated value, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t string_array_contains_string(
+ VSTRARRAY_T *p_strarray, /* String array */
+ char **pp_string_found, /* String found */
+ uint32_t index, /* Which entry, (-1) => any */
+ const char *p_string, /* The string we're looking for */
+ bool_t exact /* Exact or partial match */
+ )
+{
+ bool_t ret = FALSE;
+ uint32_t i;
+ uint32_t s, e;
+
+ if (index == (-1))
+ {
+ s = 0;
+ e = p_strarray->n_strings;
+ }
+ else
+ {
+ s = index;
+ e = index + 1;
+ }
+
+ for (i = s;!ret && (i < e);i++)
+ {
+ if ((i < p_strarray->n_strings) && p_strarray->pp_strings[i])
+ {
+ if (exact)
+ {
+ if (0 == p_stricmp(p_strarray->pp_strings[i], p_string))
+ ret = TRUE;
+ }
+ else
+ {
+ if (p_strstr(p_strarray->pp_strings[i], p_string))
+ ret = TRUE;
+ }
+ }
+
+ if (ret && pp_string_found)
+ {
+ *pp_string_found = p_strarray->pp_strings[i];
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * add_string_to_array()
+ *
+ * DESCRIPTION
+ * Append string to indicated array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t add_string_to_array(
+ VSTRARRAY_T *p_strarray, /* String array */
+ const char *p_string /* String to add */
+ )
+{
+ char **pp_new;
+ bool_t ret = FALSE;
+
+ pp_new = vf_realloc(p_strarray->pp_strings, sizeof(char *) * (1 + p_strarray->n_strings));
+
+ if (pp_new)
+ {
+ if (p_string)
+ {
+ uint32_t l;
+ char *p_strcopy;
+
+ l = p_strlen(p_string);
+
+ p_strcopy = vf_malloc(1 + l);
+
+ if (p_strcopy)
+ {
+ p_strcpy(p_strcopy, p_string);
+
+ pp_new[p_strarray->n_strings] = p_strcopy;
+
+ ret = TRUE;
+ }
+ else
+ {
+ vf_free(pp_new);
+ }
+ }
+ else
+ {
+ pp_new[p_strarray->n_strings] = NULL;
+
+ ret = TRUE;
+ }
+
+ if (ret)
+ {
+ p_strarray->n_strings += 1;
+ p_strarray->pp_strings = pp_new;
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * free_string_array_contents()
+ *
+ * DESCRIPTION
+ * Delete contents of a string array. The structure itself is not free()d.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void free_string_array_contents(
+ VSTRARRAY_T *p_strarray /* String array */
+ )
+{
+ if (p_strarray && p_strarray->pp_strings)
+ {
+ uint32_t i;
+
+ for (i = 0;i < p_strarray->n_strings;i++)
+ {
+ if (p_strarray->pp_strings[i])
+ {
+ vf_free(p_strarray->pp_strings[i]);
+ p_strarray->pp_strings[i] = NULL;
+ }
+ }
+
+ vf_free(p_strarray->pp_strings);
+ p_strarray->pp_strings = NULL;
+
+ p_strarray->n_strings = 0;
+ }
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_to_curr_string()
+ *
+ * DESCRIPTION
+ * Append characters to the current string in a string array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t append_to_curr_string(
+ VSTRARRAY_T *p_strarray, /* String array */
+ uint32_t *p_length, /* Pointer to length, NULL if zero terminated */
+ const char *p_chars, /* Characters to append */
+ uint32_t numchars /* Number of characters */
+ )
+{
+ bool_t ret = TRUE;
+
+ if (p_strarray && !p_strarray->pp_strings)
+ {
+ ret = add_string_to_array(p_strarray, "");
+ }
+
+ if (ret)
+ {
+ ret = append_to_pointer(&(p_strarray->pp_strings[p_strarray->n_strings - 1]), p_length, p_chars, numchars);
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_to_pointer()
+ *
+ * DESCRIPTION
+ * Append characters to indicated pointer. Handles both NULL terminated
+ * strings (for simple 7-bit values) and buffer/length pairs. Passing
+ * the p_length field indicates that we're building up binary data.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t append_to_pointer(
+ char **pp_string, /* String we're appending to */
+ uint32_t *p_length, /* Pointer to length, NULL if ZT */
+ const char *p_chars, /* Chars we're appending */
+ int numchars /* Number of chars we're appending */
+ )
+{
+ bool_t ok = FALSE;
+
+ if (pp_string)
+ {
+ int newlen, currlen;
+ char *p_new;
+
+ newlen = numchars;
+
+ if (*pp_string)
+ {
+ currlen = p_length ? *p_length : p_strlen(*pp_string);
+
+ newlen += currlen;
+ }
+ else
+ {
+ currlen = 0;
+ }
+
+ p_new = vf_realloc(*pp_string, newlen + (p_length ? 0 : 1));
+
+ if (p_new)
+ {
+ p_memcpy(p_new + currlen, p_chars, numchars);
+
+ if (p_length)
+ {
+ *p_length = newlen;
+ }
+ else
+ {
+ p_new[newlen] = '\0';
+ }
+
+ *pp_string = p_new;
+ ok = TRUE;
+ }
+ }
+
+ return ok;
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * set_string_array_entry()
+ *
+ * DESCRIPTION
+ * Set indicated entry in a string array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t set_string_array_entry(
+ VSTRARRAY_T *p_strarray, /* String array */
+ const char *p_string, /* String to insert */
+ uint32_t n_string /* Insertion point */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (n_string < p_strarray->n_strings)
+ {
+ if (p_strarray->pp_strings[n_string])
+ {
+ vf_free(p_strarray->pp_strings[n_string]);
+ p_strarray->pp_strings[n_string] = NULL;
+ }
+
+ if (p_string)
+ {
+ uint32_t len = p_strlen(p_string);
+
+ p_strarray->pp_strings[n_string] = vf_malloc(1 + len);
+
+ if (p_strarray->pp_strings[n_string])
+ {
+ p_strcpy(p_strarray->pp_strings[n_string], p_string);
+
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ /* NULL = "delete" */
+
+ ret = TRUE;
+ }
+ }
+
+ return ret;
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_string_arrays.h b/src/vf_string_arrays.h
new file mode 100644
index 0000000..252da03
--- /dev/null
+++ b/src/vf_string_arrays.h
@@ -0,0 +1,177 @@
+/*******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_internals.h $
+ $Revision: 1.2 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Utility functions handling string arrays - the VSTRARRAY_T type.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_string_arrays.h,v $
+ * Revision 1.2 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.1 2002/10/26 15:57:11 tilda
+ * Initial Version
+ *
+ *******************************************************************************/
+
+#ifndef _VF_STRING_ARRAYS_H_
+#define _VF_STRING_ARRAYS_H_
+
+#ifndef NORCSID
+static const char vf_string_arrays_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_string_arrays.h,v 1.2 2002/11/02 18:29:26 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * string_array_contains_string()
+ *
+ * DESCRIPTION
+ * Checks the strings in the indicated array to see if it contains a
+ * particulr value. Can check a particular index or the whole array.
+ * Can perform an exact match or check wether one of the strings simply
+ * contains the value.
+ *
+ * RETURNS
+ * TRUE <=> includes indicated value, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t string_array_contains_string(
+ VSTRARRAY_T *p_strarray, /* String array */
+ char **pp_string_found, /* String found */
+ uint32_t index, /* Which entry, (-1) => any */
+ const char *p_string, /* The string we're looking for */
+ bool_t exact /* Exact or partial match */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * add_string_to_array()
+ *
+ * DESCRIPTION
+ * Append string to indicated array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t add_string_to_array(
+ VSTRARRAY_T *p_strarray, /* String array */
+ const char *p_string /* String to add */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * free_string_array_contents()
+ *
+ * DESCRIPTION
+ * Delete contents of a string array. The structure itself is not free()d.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern void free_string_array_contents(
+ VSTRARRAY_T *p_strarray /* String array */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_to_curr_string()
+ *
+ * DESCRIPTION
+ * Append characters to the current string in a string array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t append_to_curr_string(
+ VSTRARRAY_T *p_strarray, /* String array */
+ uint32_t *p_length, /* Pointer to length, NULL if zero terminated */
+ const char *p_chars, /* Characters to append */
+ uint32_t numchars /* Number of characters */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * append_to_pointer()
+ *
+ * DESCRIPTION
+ * Append characters to indicated pointer. Handles both NULL terminated
+ * strings (for simple 7-bit values) and buffer/length pairs. Passing
+ * the p_length field indicates that we're building up binary data.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t append_to_pointer(
+ char **pp_string, /* String we're appending to */
+ uint32_t *p_length, /* Pointer to length, NULL if ZT */
+ const char *p_chars, /* Chars we're appending */
+ int numchars /* Number of chars we're appending */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * set_string_array_entry()
+ *
+ * DESCRIPTION
+ * Set indicated entry in a string array.
+ *
+ * RETURNS
+ * TRUE <=> allocation OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t set_string_array_entry(
+ VSTRARRAY_T *p_strarray, /* String array */
+ const char *p_string, /* String to insert */
+ uint32_t n_string /* Insertion point */
+ );
+
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_STRING_ARRAYS_H_*/
diff --git a/src/vf_strings.c b/src/vf_strings.c
new file mode 100644
index 0000000..204a188
--- /dev/null
+++ b/src/vf_strings.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.9 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ String handling functions. The library uses the p_ functions (where hopefully
+ the 'p' stands for 'portable') and they are provided here in terms of C runtime
+ functions or implemented explicitly.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_strings.c,v $
+ * Revision 1.9 2002/11/15 09:15:00 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.8 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.7 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.6 2002/10/08 21:11:36 tilda
+ * Remove common.h.
+ *
+ * Revision 1.5 2001/11/05 21:07:19 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.4 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.3 2001/10/13 16:22:08 tilda
+ * Introduce VBINDATA_T and VOBJDATA_T to tidy up internals.
+ *
+ * Revision 1.2 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.1 2001/10/13 14:50:33 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_strings_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_strings.c,v 1.9 2002/11/15 09:15:00 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *=============================================================================*/
+
+#include <common/types.h>
+
+#include <ctype.h>
+#include <string.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_internals.h"
+#include "vf_strings.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strlen()
+ *
+ * DESCRIPTION
+ * Find length of string.
+ *
+ * RETURNS
+ * Length of strings.
+ *----------------------------------------------------------------------------*/
+
+int p_strlen(
+ const char *p_string /* String to measure */
+ )
+{
+#if defined(HAVE_STRLEN)
+ return strlen(p_string);
+#else
+ int len = 0;
+
+ while (*p_string)
+ {
+ p_string++;
+ len++;
+ }
+
+ return len;
+#endif
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcpy()
+ *
+ * DESCRIPTION
+ * Copy string to buffer.
+ *
+ * RETURNS
+ * Pointer to buffer.
+ *----------------------------------------------------------------------------*/
+
+char *p_strcpy(
+ char *p_string1, /* Buffer to copy to */
+ const char *p_string2 /* String to copy */
+ )
+{
+#if defined(HAVE_STRCPY)
+ return strcpy(p_string1, p_string2);
+#else
+ char *p_return = p_string1;
+
+ while ((*p_string1++ = *p_string2++))
+ ;
+
+ return p_return;
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcmp()
+ *
+ * DESCRIPTION
+ * Case sensitive string comparison.
+ *
+ * RETURNS
+ * 0<=>strings match, !=0 else.
+ *----------------------------------------------------------------------------*/
+
+int p_strcmp(
+ const char *p_string1,
+ const char *p_string2
+ )
+{
+#if defined(HAVE_STRCMP)
+ return strcmp(p_string1, p_string2);
+#else
+ while (*p_string1 && (*p_string1 == *p_string2))
+ {
+ p_string1++;
+ p_string2++;
+ }
+
+ return (*(unsigned char *)p_string1) - (*(unsigned char *)p_string2);
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcat()
+ *
+ * DESCRIPTION
+ * Append one string to another.
+ *
+ * RETURNS
+ * Pointer to resulting string.
+ *----------------------------------------------------------------------------*/
+
+char *p_strcat(
+ char *p_string1, /* String to append to */
+ const char *p_string2 /* String to append */
+ )
+{
+#if defined(HAVE_STRCAT)
+ return strcat(p_string1, p_string2);
+#else
+ char *p_return = p_string1;
+
+ while (*p_string1)
+ p_string1++;
+
+ while ((*p_string1++ = *p_string2++))
+ ;
+
+ return p_return;
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strstr()
+ *
+ * DESCRIPTION
+ * Case sensitive string searching function.
+ *
+ * RETURNS
+ * Pointer to position "looked for" has been located or NULL if !found.
+ *----------------------------------------------------------------------------*/
+
+char *p_strstr(
+ const char *p_searched, /* Buffer searched */
+ const char *p_lookedfor /* String we're looking for */
+ )
+{
+#if defined(HAVE_STRSTR)
+ return strstr(p_searched, p_lookedfor);
+#else
+ if (*p_searched == 0)
+ {
+ if (*p_lookedfor)
+ {
+ return (char *)NULL;
+ }
+
+ return (char *)p_searched;
+ }
+
+ while (*p_searched)
+ {
+ uint32_t i;
+
+ for (i = 0;;i++)
+ {
+ if (p_lookedfor[i] == 0)
+ {
+ return (char *)p_searched;
+ }
+
+ if (p_lookedfor[i] != p_searched[i])
+ {
+ break;
+ }
+ }
+
+ p_searched++;
+ }
+
+ return (char *)NULL;
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_stricmp()
+ *
+ * DESCRIPTION
+ * Case insensitive string comparison function.
+ *
+ * RETURNS
+ * 0<=>strings match, !=0 else.
+ *----------------------------------------------------------------------------*/
+
+int p_stricmp(
+ const char *p_string1, /* First string */
+ const char *p_string2 /* Second string */
+ )
+{
+#if defined(HAVE_STRCASECMP)
+ return strcasecmp(p_string1, p_string2);
+#elif defined(HAVE_STRICMP)
+ return stricmp(p_string1, p_string2);
+#else
+ while (*p_string1 && (tolower(*p_string1) == tolower(*p_string2)))
+ {
+ p_string1++;
+ p_string2++;
+ }
+
+ return tolower(*(unsigned char *)p_string1) - tolower(*(unsigned char *)p_string2);
+#endif
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_stristr()
+ *
+ * DESCRIPTION
+ * Case insensitive string searching function.
+ *
+ * RETURNS
+ * Pointer to position "looked for" has been located or NULL if !found.
+ *----------------------------------------------------------------------------*/
+
+char *p_stristr(
+ const char *p_searched, /* Buffer searched */
+ const char *p_lookedfor /* String we're looking for */
+ )
+{
+#if defined(HAVE_STRISTR)
+ return strstr(p_searched, p_lookedfor);
+#else
+ if (*p_searched == 0)
+ {
+ if (*p_lookedfor)
+ {
+ return (char *)NULL;
+ }
+
+ return (char *)p_searched;
+ }
+
+ while (*p_searched)
+ {
+ uint32_t i;
+
+ for (i = 0;;i++)
+ {
+ if (p_lookedfor[i] == 0)
+ {
+ return (char *)p_searched;
+ }
+
+ if (tolower(p_lookedfor[i]) != tolower(p_searched[i]))
+ {
+ break;
+ }
+ }
+
+ p_searched++;
+ }
+
+ return (char *)NULL;
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_memcpy()
+ *
+ * DESCRIPTION
+ * Copy characetrs between buffers. No checks on overlap.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void p_memcpy(
+ void *p_destination, /* Pointer to buffer */
+ const void *p_source, /* Source of copy */
+ uint32_t length /* Number of characters to copy */
+ )
+{
+#if defined(HAVE_MEMCPY)
+ memcpy(p_destination, p_source, length);
+#else
+ uint8_t *p_dst = (uint8_t *)p_destination;
+ uint8_t *p_src = (uint8_t *)p_source;
+
+ while (length--)
+ {
+ *p_dst++ = *p_src++;
+ }
+#endif
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_memset()
+ *
+ * DESCRIPTION
+ * Fill buffer with indicated character.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void p_memset(
+ void *p_destination, /* Pointer to buffer */
+ uint8_t v, /* Character to fill with */
+ uint32_t length /* Length of buffer to set */
+ )
+{
+#if defined(HAVE_MEMSET)
+ memset(p_destination, v, length);
+#else
+ uint8_t *p_dst = (uint8_t *)p_destination;
+
+ while (length--)
+ *p_dst++ = v;
+#endif
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/src/vf_strings.h b/src/vf_strings.h
new file mode 100644
index 0000000..29ccd78
--- /dev/null
+++ b/src/vf_strings.h
@@ -0,0 +1,230 @@
+/*******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.6 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ String handling functions. The library uses the p_ functions (where hopefully
+ the 'p' stands for 'portable') and they are provided here in terms of C runtime
+ functions or implemented explicitly.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_strings.h,v $
+ * Revision 1.6 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.5 2002/10/08 21:27:20 tilda
+ * Correct #endif directive.
+ *
+ * Revision 1.4 2001/11/05 21:07:19 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.3 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.2 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.1 2001/10/13 14:50:33 tilda
+ * Add string array code to unify handling of names / values.
+ *
+ *******************************************************************************/
+
+#ifndef _VF_STRINGS_H_
+#define _VF_STRINGS_H_
+
+#ifndef NORCSID
+static const char vf_strings_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_strings.h,v 1.6 2002/10/26 16:09:23 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Defines
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Types
+ *============================================================================*/
+/* None */
+
+/*=============================================================================*
+ Public Functions
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strlen()
+ *
+ * DESCRIPTION
+ * Find length of string.
+ *
+ * RETURNS
+ * Length of strings.
+ *----------------------------------------------------------------------------*/
+
+extern int p_strlen(
+ const char *p_string /* String to measure */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcpy()
+ *
+ * DESCRIPTION
+ * Copy string to buffer.
+ *
+ * RETURNS
+ * Pointer to buffer.
+ *----------------------------------------------------------------------------*/
+
+extern char *p_strcpy(
+ char *p_string1, /* Buffer to copy to */
+ const char *p_string2 /* String to copy */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcmp()
+ *
+ * DESCRIPTION
+ * Case sensitive string comparison.
+ *
+ * RETURNS
+ * 0<=>strings match, !=0 else.
+ *----------------------------------------------------------------------------*/
+
+extern int p_strcmp(
+ const char *p_string1,
+ const char *p_string2
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strcat()
+ *
+ * DESCRIPTION
+ * Append one string to another.
+ *
+ * RETURNS
+ * Pointer to resulting string.
+ *----------------------------------------------------------------------------*/
+
+extern char *p_strcat(
+ char *p_string1, /* String to append to */
+ const char *p_string2 /* String to append */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_strstr()
+ *
+ * DESCRIPTION
+ * Case sensitive string searching function.
+ *
+ * RETURNS
+ * Pointer to position "looked for" has been located or NULL if !found.
+ *----------------------------------------------------------------------------*/
+
+extern char *p_strstr(
+ const char *p_searched, /* Buffer searched */
+ const char *p_lookedfor /* String we're looking for */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_stricmp()
+ *
+ * DESCRIPTION
+ * Case insensitive string comparison function.
+ *
+ * RETURNS
+ * 0<=>strings match, !=0 else.
+ *----------------------------------------------------------------------------*/
+
+extern int p_stricmp(
+ const char *p_string1, /* First string */
+ const char *p_string2 /* Second string */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_stristr()
+ *
+ * DESCRIPTION
+ * Case insensitive string searching function.
+ *
+ * RETURNS
+ * Pointer to position "looked for" has been located or NULL if !found.
+ *----------------------------------------------------------------------------*/
+
+extern char *p_stristr(
+ const char *p_searched, /* Buffer searched */
+ const char *p_lookedfor /* String we're looking for */
+ );
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_memcpy()
+ *
+ * DESCRIPTION
+ * Copy characetrs between buffers. No checks on overlap.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern void p_memcpy(
+ void *p_destination, /* Pointer to buffer */
+ const void *p_source, /* Source of copy */
+ uint32_t length /* Number of characters to copy */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * p_memset()
+ *
+ * DESCRIPTION
+ * Fill buffer with indicated character.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern void p_memset(
+ void *p_destination, /* Pointer to buffer */
+ uint8_t v, /* Character to fill with */
+ uint32_t length /* Length of buffer to set */
+ );
+
+
+/*=============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_STRINGS_H_*/
diff --git a/src/vf_writer.c b/src/vf_writer.c
new file mode 100644
index 0000000..ef3298a
--- /dev/null
+++ b/src/vf_writer.c
@@ -0,0 +1,616 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.12 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley.
+
+DESCRIPTION
+ Code for writing vformat files. This is temporary as it is not based
+ around a state machine for converting the object to a character stream.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_writer.c,v $
+ * Revision 1.12 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.11 2002/11/02 08:56:17 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.10 2002/10/26 16:09:23 tilda
+ * IID629125 - Ensure string functions used are portable.
+ *
+ * Revision 1.9 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.8 2002/10/08 21:11:35 tilda
+ * Remove common.h.
+ *
+ * Revision 1.7 2002/02/24 17:10:34 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.6 2001/12/13 06:45:35 tilda
+ * IID488021 - Various bugs with quoted printable format.
+ *
+ * Revision 1.5 2001/11/18 21:45:10 tilda
+ * Add newline after BASE64 encodings
+ *
+ * Revision 1.4 2001/11/14 22:36:55 tilda
+ * Add parameter to vf_find_prop_qual_index()
+ *
+ * Revision 1.3 2001/11/06 22:51:05 tilda
+ * Supporting access functions for image selection / deletion.
+ *
+ * Revision 1.2 2001/10/24 18:56:29 tilda
+ * Tidy headers after import. Fix include path in release build.
+ *
+ * Revision 1.1 2001/10/24 18:34:35 tilda
+ * Initial Version.
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_writer_c_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/src/vf_writer.c,v 1.12 2002/11/03 18:43:16 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ ANSI C & System-wide Header Files
+ *=============================================================================*/
+
+#include <common/types.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include <vformat/vf_iface.h>
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "vf_config.h"
+#include "vf_internals.h"
+#include "vf_malloc.h"
+#include "vf_strings.h"
+
+/*============================================================================*
+ Public Data
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+
+#define QPMAXPERLINE (76)
+#define BASE64PERLINE (64)
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+
+static bool_t write_name_fields(
+ FILE *fp,
+ uint32_t *p_charsonline,
+ VPROP_T *p_prop
+ );
+
+static void write_base64_chars(
+ FILE *fp, /* File we're writing */
+ uint8_t *s, /* Pointer to buffer */
+ uint32_t len /* buffer length */
+ );
+
+static bool_t write_quoted_printable(
+ FILE *fp, /* File we're writing */
+ uint8_t *s, /* Pointer to buffer */
+ uint32_t *p_charsonline /* Num on line so far */
+ );
+
+static char char_to_base64(
+ uint8_t b /* Byte to convert */
+ );
+
+static bool_t qp_needs_quoting(
+ uint8_t c /* Char to test */
+ );
+
+static bool_t write_vobject_to_file(
+ FILE *fp,
+ VOBJECT_T *p_object,
+ bool_t write_all
+ );
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+
+static const char szEndOfLine[3] = { 0x0D, 0x0A, 0x00 };
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_write_file()
+ *
+ * DESCRIPTION
+ * Write indicated vobject to file.
+ *
+ * RETURNS
+ * TRUE <=> written OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t vf_write_file(
+ const char *p_name, /* Outpt filename */
+ VF_OBJECT_T *p_object, /* The object to write */
+ bool_t write_all /* Should write p_next as well? */
+ )
+{
+ FILE *fp;
+ bool_t ret = FALSE;
+
+ fp = fopen(p_name, "wb");
+
+ if (fp)
+ {
+ ret = write_vobject_to_file(fp, (VOBJECT_T *)p_object, write_all);
+
+ if (0 == fclose(fp))
+ {
+ /* as is */
+ }
+ else
+ {
+ ret = FALSE;
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_vobject_to_file()
+ *
+ * DESCRIPTION
+ * Write each field of the indicated vformat object to the indicated FILE*
+ * invoking write_vobject_to_file() recursively if a field is found which
+ * contains a vformat object.
+ *
+ * RETURNS
+ * TRUE <=> file acces OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t write_vobject_to_file(
+ FILE *fp,
+ VOBJECT_T *p_object,
+ bool_t write_all
+ )
+{
+ bool_t ret = TRUE;
+
+ VOBJECT_T *p_obj = (VOBJECT_T *)p_object;
+ VPROP_T *p_props = p_obj->p_props;
+
+ fprintf(fp, "%s:%s", VFP_BEGIN, p_obj->p_type);
+
+ fprintf(fp, szEndOfLine);
+
+ for (;NULL != p_props;p_props = p_props->p_next)
+ {
+ uint32_t charsonline;
+
+ switch (p_props->value.encoding)
+ {
+ default:
+ case VF_ENC_7BIT:
+ {
+ ret = write_name_fields(fp, &charsonline, p_props);
+
+ if (ret)
+ {
+ uint32_t n;
+
+ for (n = 0;ret && (n < p_props->value.v.s.n_strings);n++)
+ {
+ if (n)
+ fprintf(fp, ";");
+
+ if (p_props->value.v.s.pp_strings[n])
+ {
+ fprintf(fp, "%s", p_props->value.v.s.pp_strings[n]);
+ }
+ }
+ }
+ }
+ break;
+
+ case VF_ENC_BASE64:
+ {
+ ret = write_name_fields(fp, &charsonline, p_props);
+
+ if (ret)
+ {
+ write_base64_chars(fp, p_props->value.v.b.p_buffer, p_props->value.v.b.n_bufsize);
+ }
+ }
+ break;
+
+ case VF_ENC_QUOTEDPRINTABLE:
+ {
+ ret = write_name_fields(fp, &charsonline, p_props);
+
+ if (ret)
+ {
+ uint32_t n;
+
+ for (n = 0;ret && (n < p_props->value.v.s.n_strings);n++)
+ {
+ if (n)
+ fprintf(fp, ";");
+
+ if (p_props->value.v.s.pp_strings[n])
+ {
+ ret = write_quoted_printable(fp, p_props->value.v.s.pp_strings[n], &charsonline);
+ }
+ }
+ }
+ }
+ break;
+
+ case VF_ENC_VOBJECT:
+ {
+ write_vobject_to_file(fp, p_props->value.v.o.p_object, TRUE);
+ }
+ break;
+ }
+
+ if (VF_ENC_VOBJECT != p_props->value.encoding)
+ fprintf(fp, szEndOfLine);
+ }
+
+ fprintf(fp, "%s:%s", VFP_END, p_obj->p_type);
+
+ fprintf(fp, szEndOfLine);
+
+ if (ret && p_obj->p_next && write_all)
+ {
+ ret = write_vobject_to_file(fp, p_obj->p_next, TRUE);
+ }
+
+ p_obj->modified = !ret;
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_base64_chars()
+ *
+ * DESCRIPTION
+ * Write the indicated binary data stream out to FILE* using BASE64
+ * encoding.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void write_base64_chars(
+ FILE *fp, /* File we're writing */
+ uint8_t *p_buffer, /* Pointer to buffer */
+ uint32_t n_chars /* buffer length */
+ )
+{
+ uint32_t posn;
+ char quad[5];
+ uint8_t b;
+
+ quad[4] = 0;
+
+ for (posn = 0;posn < n_chars;)
+ {
+ int i;
+ uint32_t triplet = 0;
+ uint8_t bits = 0;
+
+ /* Form triplet from data if available */
+
+ for (i = 0;i < 3;i++, posn++)
+ {
+ triplet = triplet << 8;
+
+ if (posn < n_chars)
+ {
+ triplet |= *(p_buffer + posn);
+
+ bits += 8;
+ }
+ }
+
+ /* Convert the triplet to text */
+
+ for (i = 0;i < 4;i++)
+ {
+ b = (uint8_t)((0xFC0000 & triplet) >> 18);
+
+ triplet = triplet << 6;
+
+ quad[i] = (i <= (bits/6)) ? char_to_base64(b) : '=';
+ }
+
+ /* Output the text prefixed by newlines if necessary */
+
+ if (((posn - 3) % (BASE64PERLINE / 4)) == 0)
+ {
+ fprintf(fp, szEndOfLine);
+ fprintf(fp, " ");
+ }
+
+ fprintf(fp, "%s", quad);
+ }
+
+ fprintf(fp, szEndOfLine);
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_quoted_printable()
+ *
+ * DESCRIPTION
+ * Write the indicated field back to the file in quoted printable format.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static bool_t write_quoted_printable(
+ FILE *fp, /* File we're writing */
+ uint8_t *s, /* Pointer to buffer */
+ uint32_t *p_charsonline /* Num on line so far */
+ )
+{
+ uint32_t i;
+ uint32_t charsonline = *p_charsonline;
+
+ for (i = 0;s;i++)
+ {
+ uint8_t c = s[i];
+
+ if ('\0' == c)
+ {
+ break;
+ }
+ else
+ {
+ if (3 + charsonline > QPMAXPERLINE)
+ {
+ fprintf(fp, "=");
+ fprintf(fp, szEndOfLine);
+ charsonline = 0;
+ }
+
+ if (qp_needs_quoting(c))
+ {
+ fprintf(fp, "=%02X", c);
+ charsonline += 3;
+
+ if (0x0D == c)
+ {
+ fprintf(fp, "=");
+ fprintf(fp, szEndOfLine);
+ charsonline = 0;
+ }
+ }
+ else
+ {
+ fprintf(fp, "%c", c);
+ charsonline += 1;
+ }
+ }
+ }
+
+ *p_charsonline = charsonline;
+
+ return TRUE;
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * char_to_base64()
+ *
+ * DESCRIPTION
+ * Converts byte to BASE64.
+ *
+ * RETURNS
+ * Character encoded.
+ *----------------------------------------------------------------------------*/
+
+static char char_to_base64(
+ uint8_t b /* Byte to convert */
+ )
+{
+ char ret;
+
+ if (b < 26)
+ {
+ ret = (char)b + 'A';
+ }
+ else
+ if (b < 52)
+ {
+ ret = (char)(b - 26) + 'a';
+ }
+ else
+ if (b < 62)
+ {
+ ret = (char)(b - 52) + '0';
+ }
+ else
+ if (b == 62)
+ {
+ ret = '+';
+ }
+ else
+ {
+ ret = '/';
+ }
+
+ return ret;
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * qp_needs_quoting()
+ *
+ * DESCRIPTION
+ * Works out of 'c' needs quoting in quoted printable format.
+ *
+ * RETURNS
+ * TRUE <=> need to quote.
+ *----------------------------------------------------------------------------*/
+
+static bool_t qp_needs_quoting(
+ uint8_t c /* Char to test */
+ )
+{
+ /* TBD - look in the RFC?! */
+
+ bool_t needs_quoting = FALSE;
+
+ switch (c)
+ {
+ case ' ':
+ case ',':
+ case '-':
+ case '.':
+ case '!':
+ case '?':
+ case '\'':
+ return FALSE;
+
+ default:
+ if (isalnum(c))
+ needs_quoting = FALSE;
+ else
+ needs_quoting = TRUE;
+ break;
+ }
+
+ return needs_quoting;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_name_fields()
+ *
+ * DESCRIPTION
+ * Write name fields to file.
+ *
+ * RETURNS
+ * TRUE <=> OK so far.
+ *----------------------------------------------------------------------------*/
+
+bool_t write_name_fields(
+ FILE *fp,
+ uint32_t *p_charsonline,
+ VPROP_T *p_prop
+ )
+{
+ VSTRARRAY_T *p_strarray = &(p_prop->name);
+ bool_t ret = FALSE;
+
+ *p_charsonline = 0;
+
+ if (p_prop->p_group)
+ {
+ *p_charsonline += fprintf(fp, "%s.", p_prop->p_group);
+ }
+
+ if (p_strarray->pp_strings)
+ {
+ uint32_t i;
+
+ for (i = 0;i < p_strarray->n_strings;i++)
+ {
+ char *p_name_field = p_strarray->pp_strings[i];
+
+ if (p_name_field && (0 < p_strlen(p_name_field)))
+ {
+ if (0 < i)
+ {
+ fprintf(fp, ";");
+ *p_charsonline += 1;
+ }
+
+ *p_charsonline += fprintf(fp, "%s", p_name_field);
+ }
+ }
+
+ fprintf(fp, ":");
+ *p_charsonline += 1;
+
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+
+/*============================================================================*
+ End Of File
+ *============================================================================*/
diff --git a/stamp-h.in b/stamp-h.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/stamp-h.in
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..883a1a7
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,7 @@
+bin_PROGRAMS = vformat
+
+vformat_SOURCE = testsuppt.c vformat.c
+vformat_LDADD = ../src/.libs/libvformat.a testsuppt.o
+
+EXTRA_DIST = testsuppt.c testsuppt.h tests/access/*.vcf tests/adhoc/*.vc* tests/spec/*.vcf tests/utf-8/*.vcf
+TESTS = vformat \ No newline at end of file
diff --git a/test/tests/access/access_1.vcf b/test/tests/access/access_1.vcf
new file mode 100644
index 0000000..ecb8636
--- /dev/null
+++ b/test/tests/access/access_1.vcf
@@ -0,0 +1,17 @@
+BEGIN:VCARD
+N:frfrfr;frfrfr
+TEL;HOME;PREF:123456789
+FN:Fr. Frfrfr (fr the frfrfr)
+TEL;WORK;PREF:ABCDEFGHI
+ORG:fr;fr;fr;fr
+TEL;CELLULAR;PREF:JKLMNOP
+SOUND;WAVE;BASE64:
+ UklGRhAsAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YesrAACAg4eC
+ eXR4e3uAhoiIiYmKjIiDfnx5eX6CgoKEhYWDenV5fH6BhISGiIiDfHZ2eXt/hIiK
+ jY2IhH12d3Vyc3uDiIiFf3l7fn18eXl+houFf319fnyAgHl5eoCIiISChIeAfnt2
+TEL;WORK:XXYYZZ!!
+SOUND;WAVE;BASE64:
+ UklGRhAsAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YesrAACAg4eC
+ eXR4e3uAhoiIiYmKjIiDfnx5eX6CgoKEhYWDenV5fH6BhISGiIiDfHZ2eXt/hIiK
+ jY2IhH12d3Vyc3uDiIiFf3l7fn18eXl+houFf319fnyAgHl5eoCIiISChIeAfnt2
+END:VCARD
diff --git a/test/tests/adhoc/group_1.vcf b/test/tests/adhoc/group_1.vcf
new file mode 100644
index 0000000..c0ab6ef
--- /dev/null
+++ b/test/tests/adhoc/group_1.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+N:aaa;bbb;ccc
+A.N:ddd;eee;fff
+B.N:ggg;hhh;iii
+C.N:jjj;kkk;lll
+END:VCARD
diff --git a/test/tests/adhoc/group_2.vcf b/test/tests/adhoc/group_2.vcf
new file mode 100644
index 0000000..bd5dad8
--- /dev/null
+++ b/test/tests/adhoc/group_2.vcf
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+N:aaa;bbb;ccc
+X-1-FILLER:1;2;3;4;5;6;7;8
+A.N:ddd;eee;fff
+X-2-FILLER:1;2;3;4;5;6;7;8
+B.N:ggg;hhh;iii
+X-3-FILLER:1;2;3;4;5;6;7;8
+C.N:jjj;kkk;lll
+END:VCARD
diff --git a/test/tests/adhoc/group_3.vcf b/test/tests/adhoc/group_3.vcf
new file mode 100644
index 0000000..7f278ad
--- /dev/null
+++ b/test/tests/adhoc/group_3.vcf
@@ -0,0 +1,13 @@
+BEGIN:VCARD
+N:aaa;bbb;ccc
+FN:111;222;333
+X-1-FILLER:1;2;3;4;5;6;7;8
+A.N:ddd;eee;fff
+A.FN:111ddd;222eee;222fff
+X-2-FILLER:1;2;3;4;5;6;7;8
+B.N:ggg;hhh;iii
+B.FN:111ggg;222hhh;333iii
+X-3-FILLER:1;2;3;4;5;6;7;8
+C.N:jjj;kkk;lll
+C.FN:111jjj;222kkk;333lll
+END:VCARD
diff --git a/test/tests/adhoc/group_4.vcf b/test/tests/adhoc/group_4.vcf
new file mode 100644
index 0000000..23f9f06
--- /dev/null
+++ b/test/tests/adhoc/group_4.vcf
@@ -0,0 +1,16 @@
+BEGIN:VCARD
+N:aaa;bbb;ccc
+FN:111;222;333
+END:VCARD
+BEGIN:VCARD
+A.N:ddd;eee;fff
+A.FN:111ddd;222eee;222fff
+END:VCARD
+BEGIN:VCARD
+B.N:ggg;hhh;iii
+B.FN:111ggg;222hhh;333iii
+END:VCARD
+BEGIN:VCARD
+C.N:jjj;kkk;lll
+C.FN:111jjj;222kkk;333lll
+END:VCARD
diff --git a/test/tests/adhoc/group_5.vcf b/test/tests/adhoc/group_5.vcf
new file mode 100644
index 0000000..460777b
--- /dev/null
+++ b/test/tests/adhoc/group_5.vcf
@@ -0,0 +1,16 @@
+BEGIN:VCARD
+N:aaa;bbb;ccc
+FN:111;222;333
+BEGIN:VCARD
+A.N:ddd;eee;fff
+A.FN:111ddd;222eee;222fff
+BEGIN:VCARD
+B.N:ggg;hhh;iii
+B.FN:111ggg;222hhh;333iii
+BEGIN:VCARD
+C.N:jjj;kkk;lll
+C.FN:111jjj;222kkk;333lll
+END:VCARD
+END:VCARD
+END:VCARD
+END:VCARD
diff --git a/test/tests/adhoc/group_6.vcf b/test/tests/adhoc/group_6.vcf
new file mode 100644
index 0000000..4e5bffe
--- /dev/null
+++ b/test/tests/adhoc/group_6.vcf
@@ -0,0 +1,23 @@
+BEGIN:VCARD
+X-DUMMY-1:123
+X-DUMMY-2:456
+X-DUMMY-3:789
+ALPHA.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+ABC.X-DUMMY-1:123
+ABC.X-DUMMY-2:456
+ABC.X-DUMMY-3:789
+ALPHA.ABC.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+DEF.X-DUMMY-1:123
+DEF.X-DUMMY-2:456
+DEF.X-DUMMY-3:789
+ALPHA.DEF.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+END:VCARD
diff --git a/test/tests/adhoc/group_7.vcf b/test/tests/adhoc/group_7.vcf
new file mode 100644
index 0000000..9dcb356
--- /dev/null
+++ b/test/tests/adhoc/group_7.vcf
@@ -0,0 +1,46 @@
+BEGIN:VCARD
+X-DUMMY-1:123
+DEF.X-DUMMY-1:123
+ALPHA.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+ABC.X-DUMMY-1:123
+DEF.X-DUMMY-2:456
+X-DUMMY-2:456
+ABC.X-DUMMY-2:456
+ALPHA.ABC.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+DEF.X-DUMMY-3:789
+X-DUMMY-3:789
+ABC.X-DUMMY-3:789
+ALPHA.DEF.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+BEGIN:VCARD
+PPP.X-DUMMY-1:123
+PPP.DEF.X-DUMMY-1:123
+PPP.ALPHA.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+PPP.ABC.X-DUMMY-1:123
+PPP.DEF.X-DUMMY-2:456
+PPP.X-DUMMY-2:456
+PPP.ABC.X-DUMMY-2:456
+PPP.ALPHA.ABC.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+PPP.DEF.X-DUMMY-3:789
+PPP.X-DUMMY-3:789
+PPP.ABC.X-DUMMY-3:789
+PPP.ALPHA.DEF.LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHt=
+END:VCARD
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_1.vcf b/test/tests/adhoc/mail_list_1.vcf
new file mode 100644
index 0000000..b211638
--- /dev/null
+++ b/test/tests/adhoc/mail_list_1.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+TEL;CAR:
+TEL;HOME;VOICE:123
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_2.vcf b/test/tests/adhoc/mail_list_2.vcf
new file mode 100644
index 0000000..eacbd72
--- /dev/null
+++ b/test/tests/adhoc/mail_list_2.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+ADR;WORK;ENCODING=QUOTED-PRINTABLE:;;HSBC Building=0A=0D=
+30 Metcalfe Street, 3rd Floor;Ottawa;ON;K1P 5L4;Canada
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_3.vcf b/test/tests/adhoc/mail_list_3.vcf
new file mode 100644
index 0000000..5012c8b
--- /dev/null
+++ b/test/tests/adhoc/mail_list_3.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N;ENCODING=QUOTED-PRINTABLE;CHARSET=ISO-8859-1:Familyame=E4;Surname
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_4.vcf b/test/tests/adhoc/mail_list_4.vcf
new file mode 100644
index 0000000..dea6393
--- /dev/null
+++ b/test/tests/adhoc/mail_list_4.vcf
@@ -0,0 +1,13 @@
+BEGIN:VCARD
+VERSION:2.1
+BEGIN:VCARD
+UID:1
+N:Jerry Ramond
+TEL:1-221-222-1123
+END:VCARD
+BEGIN:VCARD
+UID:2
+N:Lacy Ramond
+TEL:1-212-222-1223
+END:VCARD
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_5.vcf b/test/tests/adhoc/mail_list_5.vcf
new file mode 100644
index 0000000..19ed460
--- /dev/null
+++ b/test/tests/adhoc/mail_list_5.vcf
@@ -0,0 +1,19 @@
+BEGIN:VCARD
+VERSION:2.1
+X-DL;Design Work Group:List Item 1;List Item 2;List Item 3
+BEGIN:VCARD
+UID:List Item 1
+N:John Smith
+TEL:+1-213-555-1111
+END:VCARD
+BEGIN:VCARD
+UID:List Item 2
+N:I. M. Big
+TEL:+1-213-555-9999
+END:VCARD
+BEGIN:VCARD
+UID:List Item 3
+N:Jane Doe
+TEL:+1-213-555-5555
+END:VCARD
+END:VCARD
diff --git a/test/tests/adhoc/mail_list_6.vcf b/test/tests/adhoc/mail_list_6.vcf
new file mode 100644
index 0000000..987350d
--- /dev/null
+++ b/test/tests/adhoc/mail_list_6.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N;ENCODING=QUOTED-PRINTABLE:Last;First;Middle
+N:Last;First;Middle
+END:VCARD
diff --git a/test/tests/adhoc/multiple_objs_1.vcf b/test/tests/adhoc/multiple_objs_1.vcf
new file mode 100644
index 0000000..f6d69ef
--- /dev/null
+++ b/test/tests/adhoc/multiple_objs_1.vcf
@@ -0,0 +1,21 @@
+BEGIN:VCARD
+STUF;QUOTED-PRINTABLE:Come And Get It!
+END:VCARD
+
+BEGIN:VCARD
+MORE-STUF;QUOTED-PRINTABLE:Come And Get It!
+END:VCARD
+
+BEGIN:VCARD
+YET-MORE-STUF;QUOTED-PRINTABLE:Come And Get It!
+END:VCARD
+
+BEGIN:VCARD
+AND-YET-SOME-MORE-STUF;QUOTED-PRINTABLE:Come And Get It!
+
+BEGIN:VCARD
+YET-MORE-STUF;QUOTED-PRINTABLE:Come And Get It!
+END:VCARD
+
+END:VCARD
+
diff --git a/test/tests/adhoc/straight_1.vcf b/test/tests/adhoc/straight_1.vcf
new file mode 100644
index 0000000..d4413f3
--- /dev/null
+++ b/test/tests/adhoc/straight_1.vcf
@@ -0,0 +1,2 @@
+BEGIN:VCARD
+END:VCARD
diff --git a/test/tests/adhoc/straight_2.vcf b/test/tests/adhoc/straight_2.vcf
new file mode 100644
index 0000000..50ac599
--- /dev/null
+++ b/test/tests/adhoc/straight_2.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:aaaa
+END:VCARD
diff --git a/test/tests/adhoc/straight_3.vcf b/test/tests/adhoc/straight_3.vcf
new file mode 100644
index 0000000..bed344f
--- /dev/null
+++ b/test/tests/adhoc/straight_3.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:aaaa;bbbb
+END:VCARD
diff --git a/test/tests/adhoc/straight_4.vcf b/test/tests/adhoc/straight_4.vcf
new file mode 100644
index 0000000..ce8b613
--- /dev/null
+++ b/test/tests/adhoc/straight_4.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:aaaa;bbbb;cccc
+END:VCARD
diff --git a/test/tests/adhoc/straight_5.vcf b/test/tests/adhoc/straight_5.vcf
new file mode 100644
index 0000000..b45a355
--- /dev/null
+++ b/test/tests/adhoc/straight_5.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:;bbbb;cccc
+END:VCARD
diff --git a/test/tests/adhoc/straight_6.vcf b/test/tests/adhoc/straight_6.vcf
new file mode 100644
index 0000000..84438f3
--- /dev/null
+++ b/test/tests/adhoc/straight_6.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:;;cccc
+END:VCARD
diff --git a/test/tests/adhoc/straight_7.vcf b/test/tests/adhoc/straight_7.vcf
new file mode 100644
index 0000000..2907949
--- /dev/null
+++ b/test/tests/adhoc/straight_7.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+N:;bbbb;
+END:VCARD
diff --git a/test/tests/adhoc/straight_8.vcf b/test/tests/adhoc/straight_8.vcf
new file mode 100644
index 0000000..165f956
--- /dev/null
+++ b/test/tests/adhoc/straight_8.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+FN:12. 345678 987654321
+N:;bbbb;
+END:VCARD
diff --git a/test/tests/adhoc/straight_9.vcf b/test/tests/adhoc/straight_9.vcf
new file mode 100644
index 0000000..d16729d
--- /dev/null
+++ b/test/tests/adhoc/straight_9.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N:;bbbb;
+FN:12. 345678 987654321
+END:VCARD
diff --git a/test/tests/adhoc/straight_A.vcf b/test/tests/adhoc/straight_A.vcf
new file mode 100644
index 0000000..2f6a4f5
--- /dev/null
+++ b/test/tests/adhoc/straight_A.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+X-DUMMY-1:123
+X-DUMMY-2:456
+X-DUMMY-3:789
+N:;bbbb;
+FN:12. 345678 987654321
+END:VCARD
diff --git a/test/tests/adhoc/straight_B.vcf b/test/tests/adhoc/straight_B.vcf
new file mode 100644
index 0000000..49f79a3
--- /dev/null
+++ b/test/tests/adhoc/straight_B.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N;qqq:;bbbb;
+FN:12. 345678 987654321
+END:VCARD
diff --git a/test/tests/adhoc/straight_C.vcf b/test/tests/adhoc/straight_C.vcf
new file mode 100644
index 0000000..51ae8ff
--- /dev/null
+++ b/test/tests/adhoc/straight_C.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N;qqq;rrr;sss:;bbbb;
+FN:12. 345678 987654321
+END:VCARD
diff --git a/test/tests/adhoc/straight_D.vcf b/test/tests/adhoc/straight_D.vcf
new file mode 100644
index 0000000..ae90513
--- /dev/null
+++ b/test/tests/adhoc/straight_D.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N;qqq;rrr;sss:aaa;bbbb;ccc
+FN:12. 345678 987654321
+END:VCARD
diff --git a/test/tests/adhoc/straight_E.vcf b/test/tests/adhoc/straight_E.vcf
new file mode 100644
index 0000000..71e53c9
--- /dev/null
+++ b/test/tests/adhoc/straight_E.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+FN:12. 345678 987654321
+N;qqq;rrr;sss:;;ccc
+END:VCARD
diff --git a/test/tests/adhoc/straight_F.vcf b/test/tests/adhoc/straight_F.vcf
new file mode 100644
index 0000000..530ff82
--- /dev/null
+++ b/test/tests/adhoc/straight_F.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD
+FN:12. 345678 987654321
+X;Y;Z:123123123
+N;qqq;rrr;sss:;;ccc
+END:VCARD
diff --git a/test/tests/adhoc/straight_G.vcf b/test/tests/adhoc/straight_G.vcf
new file mode 100644
index 0000000..1cc3d18
--- /dev/null
+++ b/test/tests/adhoc/straight_G.vcf
@@ -0,0 +1,8 @@
+BEGIN:VCARD
+A:
+B:
+C;D:
+E:;
+F;G:;
+H;I;J:;K;L;M
+END:VCARD
diff --git a/test/tests/adhoc/straight_H.vcf b/test/tests/adhoc/straight_H.vcf
new file mode 100644
index 0000000..d507d3f
--- /dev/null
+++ b/test/tests/adhoc/straight_H.vcf
@@ -0,0 +1,11 @@
+BEGIN:VCARD
+A:
+B:
+C;D:
+E:;
+F;G:;
+H;I;J:;K;L;M
+N;;:
+O;;;:;;P
+Q;;;:;;R;;;S
+END:VCARD
diff --git a/test/tests/adhoc/straight_I.vcf b/test/tests/adhoc/straight_I.vcf
new file mode 100644
index 0000000..298e613
--- /dev/null
+++ b/test/tests/adhoc/straight_I.vcf
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+A;QUOTED-PRINTABLE:
+B;QUOTED-PRINTABLE:
+C;QUOTED-PRINTABLE;D:
+E;;;QUOTED-PRINTABLE:;
+F;;;;;QUOTED-PRINTABLE;;;G:;
+H;I;J;QUOTED-PRINTABLE:;K;L;M
+N;QUOTED-PRINTABLE;;:
+O;QUOTED-PRINTABLE;;;:;;P
+Q;QUOTED-PRINTABLE;;;:;;R;;;S
+T;QUOTED-PRINTABLE:;;UUU;VVV=12=12=12
+END:VCARD
diff --git a/test/tests/adhoc/straight_qp_1.vcf b/test/tests/adhoc/straight_qp_1.vcf
new file mode 100644
index 0000000..04fac0a
--- /dev/null
+++ b/test/tests/adhoc/straight_qp_1.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ORG;QUOTED-PRINTABLE:ah-ah-ah-ah-ah-ah-ah-ah
+END:VCARD
diff --git a/test/tests/adhoc/straight_qp_2.vcf b/test/tests/adhoc/straight_qp_2.vcf
new file mode 100644
index 0000000..dcdbe3c
--- /dev/null
+++ b/test/tests/adhoc/straight_qp_2.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ORG;QUOTED-PRINTABLE:ah-ah-ah-ah-ah-ah-ah-ah-=41=48
+END:VCARD
diff --git a/test/tests/adhoc/straight_qp_3.vcf b/test/tests/adhoc/straight_qp_3.vcf
new file mode 100644
index 0000000..4b858ff
--- /dev/null
+++ b/test/tests/adhoc/straight_qp_3.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD
+ORG;QUOTED-PRINTABLE:ah-ah-ah-ah-ah-ah-ah-ah-=41=48=
+-ah-ah-ah-ah-ah-ah-ah-ah-=41=48=0D=0A=
+-ah-ah-ah-ah-ah-ah-ah-ah-=41=48
+END:VCARD
diff --git a/test/tests/adhoc/straight_qp_4.vcf b/test/tests/adhoc/straight_qp_4.vcf
new file mode 100644
index 0000000..4b858ff
--- /dev/null
+++ b/test/tests/adhoc/straight_qp_4.vcf
@@ -0,0 +1,5 @@
+BEGIN:VCARD
+ORG;QUOTED-PRINTABLE:ah-ah-ah-ah-ah-ah-ah-ah-=41=48=
+-ah-ah-ah-ah-ah-ah-ah-ah-=41=48=0D=0A=
+-ah-ah-ah-ah-ah-ah-ah-ah-=41=48
+END:VCARD
diff --git a/test/tests/adhoc/vcal_1.vcs b/test/tests/adhoc/vcal_1.vcs
new file mode 100644
index 0000000..aba139a
--- /dev/null
+++ b/test/tests/adhoc/vcal_1.vcs
@@ -0,0 +1,20 @@
+BEGIN:VCALENDAR
+VERSION:1.0
+
+BEGIN:VEVENT
+CATEGORIES:MEETING
+STATUS:NEEDS ACTION
+DTSTART:19960401T073000Z
+DTEND:19960401T083000Z
+SUMMARY:Steve's Proposal Review
+DESCRIPTION:Steve and John to review newest proposal material
+CLASS:PRIVATE
+END:VEVENT
+
+BEGIN:VTODO
+SUMMARY:John to pay for lunch
+DUE:19960401T083000Z
+STATUS:NEEDS ACTION
+END:VTODO
+
+END:VCALENDAR
diff --git a/test/tests/spec/2_1_1-begin-1.vcf b/test/tests/spec/2_1_1-begin-1.vcf
new file mode 100644
index 0000000..36123a5
--- /dev/null
+++ b/test/tests/spec/2_1_1-begin-1.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+X-HERE-IT-IS:fred
+END:VCARD
diff --git a/test/tests/spec/2_1_1-begin-2.vcf b/test/tests/spec/2_1_1-begin-2.vcf
new file mode 100644
index 0000000..497bd3d
--- /dev/null
+++ b/test/tests/spec/2_1_1-begin-2.vcf
@@ -0,0 +1,23 @@
+yv vuyg duvy gvuysdfgvdvgosdf gvouyvg uyv ouvgsd ovuydgs vudov dvuyg
+vdovd vuhdpvduh vpdhv pdiv
+sd vdosv dsvuh dvuh vdvpdu ivhd
+sdvoidusvodsvdvdovd
+
+BEGIN:VCARD
+X-HERE-IT-IS:fred
+END:VCARD
+
+vdvdpfkvo
+vkof
+dfk
+dfkvfd
+vokdf
+vdfkvdf
+ovkdf
+vokdf
+vodk
+ko
+
+BEGIN:VCARD
+X-HERE-IT-IS:bloggs
+END:VCARD
diff --git a/test/tests/spec/2_1_2-property.vcf b/test/tests/spec/2_1_2-property.vcf
new file mode 100644
index 0000000..934b2b9
--- /dev/null
+++ b/test/tests/spec/2_1_2-property.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+TEL;HOME:+1-919-555-1234
+NOTE;ENCODING=QUOTED-PRINTABLE:Don't remember to order Girl=
+ Scout cookies from Stacey today!
+NOTE;QUOTED-PRINTABLE:Don't remember to order Girl=
+ Scout cookies from Stacey today!
+END:VCARD
diff --git a/test/tests/spec/2_1_3-delimiters.vcf b/test/tests/spec/2_1_3-delimiters.vcf
new file mode 100644
index 0000000..cacec9e
--- /dev/null
+++ b/test/tests/spec/2_1_3-delimiters.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+NOTE_1:This is a very long description that exists on a long line.
+NOTE_2:This is a very long description
+ that exists on a long line.
+NOTE_2:This is a very long description
+ that exists on a long line.
+END:VCARD
diff --git a/test/tests/spec/2_1_4_1-grouping-nested.vcf b/test/tests/spec/2_1_4_1-grouping-nested.vcf
new file mode 100644
index 0000000..15d0aae
--- /dev/null
+++ b/test/tests/spec/2_1_4_1-grouping-nested.vcf
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+N:abc;def;ghi
+BEGIN:VCARD
+N:jkl;mno;pqr
+BEGIN:VCARD
+N:stu;vwx;yz
+END:VCARD
+END:VCARD
+END:VCARD
diff --git a/test/tests/spec/2_1_4_1-grouping-sequential.vcf b/test/tests/spec/2_1_4_1-grouping-sequential.vcf
new file mode 100644
index 0000000..72bfb23
--- /dev/null
+++ b/test/tests/spec/2_1_4_1-grouping-sequential.vcf
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+N:abc;def;ghi
+END:VCARD
+BEGIN:VCARD
+N:jkl;mno;pqr
+END:VCARD
+BEGIN:VCARD
+N:stu;vwx;yz
+END:VCARD
diff --git a/test/tests/spec/2_1_4_2-property-grouping.vcf b/test/tests/spec/2_1_4_2-property-grouping.vcf
new file mode 100644
index 0000000..7abd856
--- /dev/null
+++ b/test/tests/spec/2_1_4_2-property-grouping.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+A.TEL;HOME:+1-213-555-1234
+A.NOTE:This is my vacation home.
+END:VCARD
diff --git a/test/tests/spec/2_1_6-charset.vcf b/test/tests/spec/2_1_6-charset.vcf
new file mode 100644
index 0000000..4be0ecf
--- /dev/null
+++ b/test/tests/spec/2_1_6-charset.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ADR;CHARSET=ISO-8859-8:...
+END:VCARD
diff --git a/test/tests/spec/2_1_7-language.vcf b/test/tests/spec/2_1_7-language.vcf
new file mode 100644
index 0000000..d561fb2
--- /dev/null
+++ b/test/tests/spec/2_1_7-language.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ADR;LANGUAGE=fr-CA:...
+END:VCARD
diff --git a/test/tests/spec/2_1_8-valuelocation.vcf b/test/tests/spec/2_1_8-valuelocation.vcf
new file mode 100644
index 0000000..1ca41b6
--- /dev/null
+++ b/test/tests/spec/2_1_8-valuelocation.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+PHOTO;VALUE=URL;TYPE=GIF:http://www.abc.com/dir_photos/my_photo.gif
+SOUND;VALUE=CONTENT-ID:<jsmith.part3.960817T083000.xyzMail@host1.com>
+END:VCARD
diff --git a/test/tests/spec/2_2_1-fn.vcf b/test/tests/spec/2_2_1-fn.vcf
new file mode 100644
index 0000000..fa6df57
--- /dev/null
+++ b/test/tests/spec/2_2_1-fn.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+FN:Mr. John Q. Public, Esq.
+END:VCARD
diff --git a/test/tests/spec/2_2_2-name.vcf b/test/tests/spec/2_2_2-name.vcf
new file mode 100644
index 0000000..deb7774
--- /dev/null
+++ b/test/tests/spec/2_2_2-name.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+N:Public;John;Quinlan;Mr.;Esq.
+N:Veni, Vidi, Vici;The Restaurant.
+END:VCARD
diff --git a/test/tests/spec/2_2_3-photo.vcf b/test/tests/spec/2_2_3-photo.vcf
new file mode 100644
index 0000000..cb77196
--- /dev/null
+++ b/test/tests/spec/2_2_3-photo.vcf
@@ -0,0 +1,7 @@
+BEGIN:VCARD
+PHOTO;VALUE=URL:file:///jqpublic.gif
+PHOTO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHtz
+END:VCARD
diff --git a/test/tests/spec/2_2_4-birthdate.vcf b/test/tests/spec/2_2_4-birthdate.vcf
new file mode 100644
index 0000000..996a303
--- /dev/null
+++ b/test/tests/spec/2_2_4-birthdate.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+BDAY:19950415
+BDAY:1995-04-15
+END:VCARD
diff --git a/test/tests/spec/2_3_1-address.vcf b/test/tests/spec/2_3_1-address.vcf
new file mode 100644
index 0000000..c7fb5f0
--- /dev/null
+++ b/test/tests/spec/2_3_1-address.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ADR;DOM;WORK;HOME;POSTAL:P.O. Box 101;;;Any Town;CA;91921-1234;
+END:VCARD
diff --git a/test/tests/spec/2_3_2-label.vcf b/test/tests/spec/2_3_2-label.vcf
new file mode 100644
index 0000000..0c5330d
--- /dev/null
+++ b/test/tests/spec/2_3_2-label.vcf
@@ -0,0 +1,12 @@
+BEGIN:VCARD
+LABEL;DOM;POSTAL;ENCODING=QUOTED-PRINTABLE:P. O. Box 456=0D=0A=
+123 Main Street=0D=0A=
+Any Town, CA 91921-1234
+LABEL;INTL;PARCEL,ENCODING=QUOTED-PRINTABLE:Suite 101=0D=0A=
+123 Main Street=0D=0A=
+Any Town, CA 91921-1234=0D=0A=
+U.S.A.
+LABEL;DOM;HOME,ENCODING=QUOTED-PRINTABLE:Suite 101=0D=0A=
+123 Main Street=0D=0A=
+Any Town, CA 91921-1234
+END:VCARD
diff --git a/test/tests/spec/2_4_1-tel.vcf b/test/tests/spec/2_4_1-tel.vcf
new file mode 100644
index 0000000..ef68044
--- /dev/null
+++ b/test/tests/spec/2_4_1-tel.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+TEL;WORK;HOME;VOICE;FAX:+1-800-555-1234
+END:VCARD
diff --git a/test/tests/spec/2_4_2-email.vcf b/test/tests/spec/2_4_2-email.vcf
new file mode 100644
index 0000000..020e419
--- /dev/null
+++ b/test/tests/spec/2_4_2-email.vcf
@@ -0,0 +1,16 @@
+BEGIN:VCARD
+EMAIL;INTERNET:john.public@abc.com
+EMAIL;TYPE=INTERNET:john.public@abc.com
+EMAIL;TYPE=AppleLink:john.public@abc.com
+EMAIL;TYPE=ATTMail:john.public@abc.com
+EMAIL;TYPE=CIS:john.public@abc.com
+EMAIL;TYPE=eWorld:john.public@abc.com
+EMAIL;TYPE=INTERNET:john.public@abc.com
+EMAIL;TYPE=IBMMail:john.public@abc.com
+EMAIL;TYPE=MCIMail:john.public@abc.com
+EMAIL;TYPE=POWERSHARE:john.public@abc.com
+EMAIL;TYPE=PRODIGY:john.public@abc.com
+EMAIL;TYPE=TLX:john.public@abc.com
+EMAIL;TYPE=X400:john.public@abc.com
+END:VCARD
+
diff --git a/test/tests/spec/2_4_3-mailer.vcf b/test/tests/spec/2_4_3-mailer.vcf
new file mode 100644
index 0000000..bdec58f
--- /dev/null
+++ b/test/tests/spec/2_4_3-mailer.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+MAILER:ccMail 2.2
+END:VCARD
diff --git a/test/tests/spec/2_4_5-tz.vcf b/test/tests/spec/2_4_5-tz.vcf
new file mode 100644
index 0000000..6ceb500
--- /dev/null
+++ b/test/tests/spec/2_4_5-tz.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+TZ:-0500
+TZ:-08:00
+END:VCARD
diff --git a/test/tests/spec/2_4_6-geo.vcf b/test/tests/spec/2_4_6-geo.vcf
new file mode 100644
index 0000000..8fdcde9
--- /dev/null
+++ b/test/tests/spec/2_4_6-geo.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+GEO:37.24,-17.87
+END:VCARD
diff --git a/test/tests/spec/2_5_1-title.vcf b/test/tests/spec/2_5_1-title.vcf
new file mode 100644
index 0000000..12a6d70
--- /dev/null
+++ b/test/tests/spec/2_5_1-title.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+TITLE:V.P., Research and Development
+END:VCARD
diff --git a/test/tests/spec/2_5_2-role.vcf b/test/tests/spec/2_5_2-role.vcf
new file mode 100644
index 0000000..9aeb431
--- /dev/null
+++ b/test/tests/spec/2_5_2-role.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ROLE:Executive
+END:VCARD
diff --git a/test/tests/spec/2_5_3-logo.vcf b/test/tests/spec/2_5_3-logo.vcf
new file mode 100644
index 0000000..d740429
--- /dev/null
+++ b/test/tests/spec/2_5_3-logo.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+LOGO;ENCODING=BASE64;TYPE=GIF:
+ R0lGODdhfgA4AOYAAAAAAK+vr62trVIxa6WlpZ+fnzEpCEpzlAha/0Kc74+PjyGM
+ SuecKRhrtX9/fzExORBSjCEYCGtra2NjYyF7nDGE50JrhAg51qWtOTl7vee1MWu1
+ 50o5e3PO/3sxcwAx/4R7GBgQOcDAwFoAQt61hJyMGHuUSpRKIf8A/wAY54yMjHtz
+END:VCARD
diff --git a/test/tests/spec/2_5_4-agent.vcf b/test/tests/spec/2_5_4-agent.vcf
new file mode 100644
index 0000000..af79284
--- /dev/null
+++ b/test/tests/spec/2_5_4-agent.vcf
@@ -0,0 +1,9 @@
+BEGIN:VCARD
+AGENT:
+BEGIN:VCARD
+VERSION:2.1
+N:Friday;Fred
+TEL;WORK;VOICE:+1-213-555-1234
+TEL;WORK;FAX:+1-213-555-5678
+END:VCARD
+END:VCARD
diff --git a/test/tests/spec/2_5_5-org.vcf b/test/tests/spec/2_5_5-org.vcf
new file mode 100644
index 0000000..49ed921
--- /dev/null
+++ b/test/tests/spec/2_5_5-org.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+ORG:ABC, Inc.;North American Division;Marketing
+END:VCARD
diff --git a/test/tests/spec/2_6_1-comment.vcf b/test/tests/spec/2_6_1-comment.vcf
new file mode 100644
index 0000000..0573597
--- /dev/null
+++ b/test/tests/spec/2_6_1-comment.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+NOTE;ENCODING=QUOTED-PRINTABLE:This facsimile machine if operational=
+ 0830 to 1715 hours=0D=0A=
+Monday through Friday. Call +1-213-555-1234 if you have problems=0D=0A=
+with access to the machine.
+END:VCARD
diff --git a/test/tests/spec/2_6_2-revision.vcf b/test/tests/spec/2_6_2-revision.vcf
new file mode 100644
index 0000000..f61aff7
--- /dev/null
+++ b/test/tests/spec/2_6_2-revision.vcf
@@ -0,0 +1,4 @@
+BEGIN:VCARD
+REV:19951031T222710
+REV:1995-10-31T22:27:10Z
+END:VCARD
diff --git a/test/tests/spec/2_6_3-sound.vcf b/test/tests/spec/2_6_3-sound.vcf
new file mode 100644
index 0000000..fd4cffe
--- /dev/null
+++ b/test/tests/spec/2_6_3-sound.vcf
@@ -0,0 +1,8 @@
+BEGIN:VCARD
+SOUND:JON Q PUBLIK
+SOUND;VALUE=URL:file///multimed/audio/jqpublic.wav
+SOUND;WAVE;BASE64:
+ UklGRhAsAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YesrAACAg4eC
+ eXR4e3uAhoiIiYmKjIiDfnx5eX6CgoKEhYWDenV5fH6BhISGiIiDfHZ2eXt/hIiK
+ jY2IhH12d3Vyc3uDiIiFf3l7fn18eXl+houFf319fnyAgHl5eoCIiISChIeAfnt2
+END:VCARD
diff --git a/test/tests/spec/2_6_4-url.vcf b/test/tests/spec/2_6_4-url.vcf
new file mode 100644
index 0000000..6b0e080
--- /dev/null
+++ b/test/tests/spec/2_6_4-url.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+URL:http://abc.com/pub/directory/northam/jpublic.ecd
+END:VCARD
diff --git a/test/tests/spec/2_6_5-uid.vcf b/test/tests/spec/2_6_5-uid.vcf
new file mode 100644
index 0000000..ae32da3
--- /dev/null
+++ b/test/tests/spec/2_6_5-uid.vcf
@@ -0,0 +1,3 @@
+BEGIN:VCARD
+UID:19950401-080045-40000F192713-0052
+END:VCARD
diff --git a/test/tests/utf-8/S15cx8.vcf b/test/tests/utf-8/S15cx8.vcf
new file mode 100644
index 0000000..b4b796f
--- /dev/null
+++ b/test/tests/utf-8/S15cx8.vcf
@@ -0,0 +1,352 @@
+BEGIN:VCARD
+LOGO;GIF;BASE64;INLINE:
+ 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
+ LNOjPNE8LbMpPT0c3dOyHNTpKNRGHccJAAA7
+
+SOUND;URL:http://www.sounds.com
+LABEL;DOM;QUOTED-PRINTABLE:=C3=91=C3=AC=C2=A2=C3=91=C3=AC=C2=A2=C3=91=C3=AC=
+=C2=A2
+SOUND:
+VERSION:2.1
+X-ESI-CATEGORIES:Keine Gruppe
+NAME;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:Anon;H=C3=A4p
+ADR;CHARSET=UTF-8:;;£;¥;;;
+ORG;CHARSET=UTF-8:Näbert€€;
+X-VFORMAT-POSNS:ORG@0x0;LABEL@0x-503;FN@14200x-503;LOGO@250x-6853
+FN:
+N:;;
+TITLE:
+LABEL;QUOTED-PRINTABLE:=C3=91=C3=AC=C2=A2=C3=91=C3=AC=C2=A2=C3=91=C3=AC=C2=
+=A2
+END:VCARD
diff --git a/test/tests/utf-8/S15cxu.vcf b/test/tests/utf-8/S15cxu.vcf
new file mode 100644
index 0000000..a80c39e
--- /dev/null
+++ b/test/tests/utf-8/S15cxu.vcf
@@ -0,0 +1,6 @@
+BEGIN:VCARD
+VERSION:2.1
+X-ESI-CATEGORIES:Keine Gruppe
+N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:B=C3=BCro
+TEL;HOME:+12345678
+END:VCARD
diff --git a/test/testsuppt.c b/test/testsuppt.c
new file mode 100644
index 0000000..1a678d5
--- /dev/null
+++ b/test/testsuppt.c
@@ -0,0 +1,409 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile: vf_access.c $
+ $Revision: 1.7 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ See accompanying header file.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ $Log: testsuppt.c,v $
+ Revision 1.7 2002/11/15 09:20:58 tilda
+ IID638823 - Don't include unistd.h unless required.
+
+ Revision 1.6 2002/11/15 09:14:59 tilda
+ IID638823 - Various portability issues.
+
+ Revision 1.5 2002/11/14 20:14:24 tilda
+ Minot tidy ups to WIN32 versions.
+
+ Revision 1.4 2002/11/11 17:23:07 monos
+ run testing harness on linux systems
+
+ Revision 1.3 2001/10/24 18:40:25 tilda
+ FindClose() not CloseHandle(). Nit.
+
+ Revision 1.2 2001/10/14 19:53:36 tilda
+ Group handling. NO group searching functions.
+
+ Revision 1.1 2001/10/12 19:02:15 tilda
+ Moved generic test functions to new file
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char vf_access_c_vss_id[] = "$Header: /cvsroot/vformat/build/vformat/testsuppt.c,v 1.7 2002/11/15 09:20:58 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <stdlib.h>
+#if defined(HAS_UNISTD_H)
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+
+#if defined(WIN) || defined(WIN32)
+#include <io.h>
+#endif
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "testsuppt.h"
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+
+static int ts_nextfile;
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * find_first_file()
+ *
+ * DESCRIPTION
+ * Locate (initialise search for) first file of indicated pattern in
+ * directory. See also find_next_file().
+ *
+ * RETURNS
+ * TRUE <=> first file found, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t find_first_file(
+ char *p_name, /* Name of file found (output) */
+ file_enum_t *p_enum, /* Pointer to enumerator */
+ const char *p_dirname, /* Directory we're searching in */
+ const char *p_pattern /* Pattern we're searching for */
+ )
+{
+ bool_t ret = FALSE;
+ char pattern[_MAX_PATH];
+
+ sprintf(pattern, "%s//%s", p_dirname, p_pattern);
+
+ if (p_enum)
+ {
+ memset(p_enum, '\0', sizeof(*p_enum));
+
+#if defined(WIN) || defined(WIN32)
+
+ p_enum->h = INVALID_HANDLE_VALUE;
+
+ if (INVALID_HANDLE_VALUE == (p_enum->h = FindFirstFile(pattern, &p_enum->fd)))
+ {
+ /* No files */
+ }
+ else
+ {
+ p_enum->p_dirname = strdup(p_dirname);
+
+ if (p_enum->p_dirname)
+ {
+ sprintf(p_name, "%s//%s", p_enum->p_dirname, p_enum->fd.cFileName);
+
+ ret = TRUE;
+ }
+ else
+ {
+ close_file_find(p_enum);
+ }
+ }
+#else
+ if (0 == glob(pattern, GLOB_ERR, NULL, &p_enum->h))
+ {
+ /* Return first found pathname and increment counter */
+ sprintf(p_name, "%s", p_enum->h.gl_pathv[0]);
+ ts_nextfile = 1;
+
+ ret = TRUE;
+ }
+ else
+ {
+ /* Failed to open directory or to find files */
+ }
+#endif
+ }
+
+ return ret;
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * find_next_file()
+ *
+ * DESCRIPTION
+ * Locate (initialise search for) first file of indicated pattern in
+ * directory. See also find_first_file().
+ *
+ * RETURNS
+ * TRUE <=> next file found, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t find_next_file(
+ char *p_name, /* Name of file found (output) */
+ file_enum_t *p_enum /* Pointer to enumerator */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (p_enum)
+ {
+#if defined(WIN) || defined(WIN32)
+ if (INVALID_HANDLE_VALUE == p_enum->h)
+ {
+ /* No files */
+ }
+ else
+ {
+ if (FindNextFile(p_enum->h, &p_enum->fd))
+ {
+ sprintf(p_name, "%s//%s", p_enum->p_dirname, p_enum->fd.cFileName);
+
+ ret = TRUE;
+ }
+ }
+#else
+ if (ts_nextfile < p_enum->h.gl_pathc)
+ {
+ sprintf(p_name, "%s", p_enum->h.gl_pathv[ts_nextfile++]);
+ ret = TRUE;
+ }
+#endif
+ }
+
+ return ret;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * close_file_find()
+ *
+ * DESCRIPTION
+ * Close the file search. Free memory, close handles etc. The enumerator
+ * is ready for another call to find_first_file().
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void close_file_find(
+ file_enum_t *p_enum /* Pointer to enumerator */
+ )
+{
+ if (p_enum)
+ {
+#if defined(WIN) || defined(WIN32)
+ if (INVALID_HANDLE_VALUE == p_enum->h)
+ {
+ /* Not an open handle */
+ }
+ else
+ {
+ FindClose(p_enum->h);
+ p_enum->h = INVALID_HANDLE_VALUE;
+ }
+
+ if (p_enum->p_dirname)
+ {
+ free(p_enum->p_dirname);
+ p_enum->p_dirname = NULL;
+ }
+#else
+ globfree(&p_enum->h);
+#endif
+ }
+}
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * filecomp()
+ *
+ * DESCRIPTION
+ * Compare files.
+ *
+ * RETURNS
+ * 0 <=> fies are th same, != 0 else.
+ *----------------------------------------------------------------------------*/
+
+int filecomp(
+ const char *p_file1, /* Name of first file */
+ const char *p_file2 /* Name of second file */
+ )
+{
+ int ret = (-1);
+ file_image_t f1, f2;
+
+ if (get_file_image(&f1, p_file1))
+ {
+ if (get_file_image(&f2, p_file2))
+ {
+ if (f1.size == f2.size)
+ {
+ ret = memcmp(f1.p_data, f2.p_data, f1.size);
+ }
+ else
+ {
+ printf(" Sizes difference :\n %s (%lu bytes) Vs.\n %s (%lu bytes)\n",
+ p_file1, (unsigned long)f1.size, p_file2, (unsigned long)f2.size);
+ }
+
+ free_file_image(&f2);
+ }
+
+ free_file_image(&f1);
+ }
+
+ return ret;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * get_file_image()
+ *
+ * DESCRIPTION
+ * Load file into memory.
+ *
+ * RETURNS
+ * TRUE <=> file i/o successful, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+bool_t get_file_image(
+ file_image_t *p, /* Info on file (output) */
+ const char *p_name /* Name of file */
+ )
+{
+ bool_t ret = FALSE;
+
+ if (p)
+ {
+ struct stat buf;
+
+ memset(p, '\0', sizeof(*p));
+
+ if (0 == stat(p_name, &buf))
+ {
+ p->size = buf.st_size;
+ p->p_data = malloc(p->size);
+
+ if (p->p_data)
+ {
+ FILE *fp;
+
+ fp = fopen(p_name, "rb");
+
+ if (fp)
+ {
+ if (p->size == (size_t)read(fileno(fp), p->p_data, p->size))
+ {
+ ret = TRUE;
+ }
+
+ fclose(fp);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * free_file_image()
+ *
+ * DESCRIPTION
+ * Free up resources allocated to a file image.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void free_file_image(
+ file_image_t *p /* Info on file (output) */
+ )
+{
+ if (p)
+ {
+ if (p->p_data)
+ {
+ free(p->p_data);
+ p->p_data = NULL;
+ }
+
+ p->size = 0l;
+ }
+}
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ FIN
+ *============================================================================*/
diff --git a/test/testsuppt.h b/test/testsuppt.h
new file mode 100644
index 0000000..142a676
--- /dev/null
+++ b/test/testsuppt.h
@@ -0,0 +1,211 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.3 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Platform dependant functions supporting vformat library test harness.
+
+ A typical usage for the file find functions is as follows:
+
+ if (find_first_file(...))
+ {
+ do
+ {
+ something_worthwhile();
+ }
+ while (find_next_file(...))
+ ;
+
+ close_file_find(...);
+ }
+
+ The only reason this exists is 'cos I like to keep the core test harness
+ code platform independant.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ $Log: testsuppt.h,v $
+ Revision 1.3 2002/11/14 20:14:25 tilda
+ Minot tidy ups to WIN32 versions.
+
+ Revision 1.2 2002/11/11 17:23:08 monos
+ run testing harness on linux systems
+
+ Revision 1.1 2001/10/12 19:02:15 tilda
+ Moved generic test functions to new file
+ *
+ *******************************************************************************/
+
+#ifndef NORCSID
+static const char testsuppt_h_vss_id[] = "$Header: /cvsroot/vformat/build/vformat/testsuppt.h,v 1.3 2002/11/14 20:14:25 tilda Exp $";
+#endif
+
+/*=============================================================================*
+ Public Includes
+ *=============================================================================*/
+
+#if defined(WIN) || defined(WIN32)
+#include <Windows.h>
+#else
+#include <glob.h>
+#endif
+
+/*============================================================================*
+ Public Defines
+ *============================================================================*/
+
+#ifndef _MAX_PATH
+#define _MAX_PATH (256)
+#endif
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+
+typedef struct
+{
+#if defined(WIN) || defined(WIN32)
+ WIN32_FIND_DATA fd;
+ HANDLE h;
+ char *p_dirname;
+#else
+ glob_t h;
+#endif
+}
+file_enum_t;
+
+typedef struct
+{
+ size_t size;
+ char *p_data;
+}
+file_image_t;
+
+/*============================================================================*
+ Public Functions
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * find_first_file()
+ *
+ * DESCRIPTION
+ * Locate (initialise search for) first file of indicated pattern in
+ * directory. If find_first_file() returns TRUE, users should call
+ * do whatever they wer going to do with the file that's located and
+ * then continue their search using find_next_file().
+ *
+ * RETURNS
+ * TRUE <=> first file found, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t find_first_file(
+ char *p_name, /* Name of file found (output) */
+ file_enum_t *p_enum, /* Pointer to enumerator */
+ const char *p_dirname, /* Directory we're searching in */
+ const char *p_pattern /* Pattern we're searching for */
+ );
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * find_next_file()
+ *
+ * DESCRIPTION
+ * Continues a search initialised by find_first_file(). Users should
+ * call find_next_file() until it returns FALSE, then close_file_find().
+ *
+ * RETURNS
+ * TRUE <=> next file found, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t find_next_file(
+ char *p_name, /* Name of file found (output) */
+ file_enum_t *p_enum /* Pointer to enumerator */
+ );
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * close_file_find()
+ *
+ * DESCRIPTION
+ * Close the file search. Free memory, close handles etc. The enumerator
+ * is ready for another call to find_first_file(). User should always
+ * call close_file_find() if find_first_file() returns TRUE or resources
+ * may be leaked.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern void close_file_find(
+ file_enum_t *p_enum /* Pointer to enumerator */
+ );
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * filecomp()
+ *
+ * DESCRIPTION
+ * Compare files.
+ *
+ * RETURNS
+ * 0 <=> contents of files is the same, != 0 else.
+ *----------------------------------------------------------------------------*/
+
+extern int filecomp(
+ const char *p_file1, /* Name of first file */
+ const char *p_file2 /* Name of second file */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * get_file_image()
+ *
+ * DESCRIPTION
+ * Load file into memory.
+ *
+ * RETURNS
+ * TRUE <=> file i/o successful, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern bool_t get_file_image(
+ file_image_t *p, /* Info on file (output) */
+ const char *p_name /* Name of file */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * free_file_image()
+ *
+ * DESCRIPTION
+ * Free up resources allocated to a file image.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern void free_file_image(
+ file_image_t *p /* Info on file (output) */
+ );
diff --git a/test/vformat.c b/test/vformat.c
new file mode 100644
index 0000000..b4a753d
--- /dev/null
+++ b/test/vformat.c
@@ -0,0 +1,858 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ This software is distributed under the GNU Lesser General Public Licence.
+ Please read and understand the comments at the top of vf_iface.h before use!
+
+FILE
+ $Workfile$
+ $Revision: 1.18 $
+ $Author: tilda $
+
+ORIGINAL AUTHOR
+ Nick Marley
+
+DESCRIPTION
+ Platform independant test harness for the vformat library functions. This
+ code runs various tests on the library, results are written to stdout.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vformat.c,v $
+ * Revision 1.18 2002/11/16 13:33:18 tilda
+ * IID639288 - Implement method for adding subobjects.
+ *
+ * Revision 1.17 2002/11/15 09:14:59 tilda
+ * IID638823 - Various portability issues.
+ *
+ * Revision 1.16 2002/11/14 20:14:25 tilda
+ * Minot tidy ups to WIN32 versions.
+ *
+ * Revision 1.15 2002/11/11 17:23:08 monos
+ * run testing harness on linux systems
+ *
+ * Revision 1.14 2002/11/03 18:56:45 tilda
+ * Add test functions for VCAL encoding functions.
+ *
+ * Revision 1.13 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.12 2002/11/02 09:03:45 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.11 2001/11/18 22:05:57 tilda
+ * Correct args for vf_get_property().
+ *
+ * Revision 1.10 2001/10/24 20:20:27 tilda
+ * uit printing when we're done.
+ *
+ * Revision 1.9 2001/10/24 18:40:40 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.8 2001/10/24 05:33:59 tilda
+ * Test harness / file list mods
+ *
+ * Revision 1.7 2001/10/16 05:50:53 tilda
+ * Debug support for lists of vobjects from single file (ie. a phonebook).
+ *
+ * Revision 1.6 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.5 2001/10/14 19:53:36 tilda
+ * Group handling. NO group searching functions.
+ *
+ * Revision 1.4 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.3 2001/10/12 19:02:15 tilda
+ * Moved generic test functions to new file
+ *
+ ******************************************************************************/
+
+#ifndef NORCSID
+static const char vformat_c_vss_id[] = "$Header: /cvsroot/vformat/build/vformat/vformat.c,v 1.18 2002/11/16 13:33:18 tilda Exp $";
+#endif
+
+/*============================================================================*
+ ANSI C & System-wide Header Files
+ *============================================================================*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*============================================================================*
+ Interface Header Files
+ *============================================================================*/
+
+#include "vformat/vf_iface.h"
+
+/*============================================================================*
+ Local Header File
+ *============================================================================*/
+
+#include "testsuppt.h"
+
+/*============================================================================*
+ Private Defines
+ *============================================================================*/
+
+#define LINELENGTH (76)
+
+#define MAXBASE64ENC (1000)
+
+/*============================================================================*
+ Private Data Types
+ *============================================================================*/
+/* None */
+
+/*============================================================================*
+ Private Function Prototypes
+ *============================================================================*/
+
+static void read_cards_from_dir(const char *dirname, const char *p_pattern);
+static void test_read_vcard(const char *filename);
+static bool_t read_show_status(VF_OBJECT_T **pp_object, const char *p_name);
+static bool_t write_show_status(const char *p_name, VF_OBJECT_T *p_object);
+static void update_results(bool_t pass, bool_t warning);
+static void do_title_line(const char *filename);
+static void print_search_results(VF_PROP_T *p_tmp);
+static void check_extract_fields(const char *filename, const char *p_array[3]);
+static void check_extract_groups(const char *filename, const char *p_group);
+static void check_base64_enc(bool_t rdata);
+static bool_t encode_decode_check(const char *p_data, uint32_t length);
+static void check_vcal_functions(void);
+static void get_random_date(VF_ISO8601_PERIOD_T *p_period);
+static void get_out_file(char *, const char *, const char *);
+
+/*============================================================================*
+ Private Data
+ *============================================================================*/
+
+static int tot_tests = 0;
+static int tot_errors = 0;
+static int tot_warnings = 0;
+
+static const char *pp_tel_fields[3] =
+{
+ VFP_TELEPHONE,
+ VFP_WORK,
+ VFP_PREFERRED
+};
+
+
+/*============================================================================*
+ Public Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * main()
+ *
+ * DESCRIPTION
+ * Entry point.
+ *
+ * RETURNS
+ * Hopefully.
+ *----------------------------------------------------------------------------*/
+
+int main(int argc, char **argv)
+{
+ /*
+ * simple reading / writing tests.
+ */
+ read_cards_from_dir("tests//spec", "*.vcf");
+ read_cards_from_dir("tests//adhoc", "*.vcf");
+ read_cards_from_dir("tests//utf-8", "*.vcf");
+
+ /*
+ * list access functions.
+ */
+ check_extract_fields("tests//access//access_1.vcf", pp_tel_fields);
+ check_extract_groups("tests//adhoc//group_7.vcf", "ALPHA");
+
+ /*
+ * data format tests.
+ */
+ check_base64_enc(TRUE);
+
+ /*
+ * VCAL access functions
+ */
+ check_vcal_functions();
+
+ /* split_phonebook("C:\\Windows\\Desktop\\Whole Phonebook.vcf", "C:\\Temp"); */
+
+
+ /* for automatic testing */
+ if (tot_errors) exit (1);
+ exit (0);
+}
+
+
+
+/*============================================================================*
+ Private Function Implementations
+ *============================================================================*/
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * main()
+ *
+ * DESCRIPTION
+ * Entry point.
+ *
+ * RETURNS
+ * Hopefully.
+ *----------------------------------------------------------------------------*/
+
+void read_cards_from_dir(
+ const char *p_dirname,
+ const char *p_pattern
+ )
+{
+ file_enum_t f;
+ char filename[_MAX_PATH];
+
+ if (find_first_file(filename, &f, p_dirname, p_pattern))
+ {
+ do
+ {
+ test_read_vcard(filename);
+ }
+ while (find_next_file(filename, &f))
+ ;
+
+ close_file_find(&f);
+ }
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * test_read_vcard()
+ *
+ * DESCRIPTION
+ * Attempt to read the indicated card. If the read succeeds, then write
+ * the card out to a new file. Compare the original file with the new
+ * files - they will be the same if the file was in exactly the format
+ * produced by this library (line lengths & ends may differ of course as
+ * well as choice of characters escaped in quoted printable format).
+ *
+ * We then read in "our" version of the test file and write it out. This
+ * time, the output should be the same as the input. Well - for the
+ * purposes of this test I consider it an error if they differ!
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void test_read_vcard(
+ const char *filename
+ )
+{
+ VF_OBJECT_T *p_object = NULL;
+ bool_t warning = FALSE, pass = FALSE;
+
+ do_title_line(filename);
+
+ if (read_show_status(&p_object, filename))
+ {
+ VF_OBJECT_T *p_object_1 = NULL;
+ char outfile_1[_MAX_PATH];
+ char outfile_2[_MAX_PATH];
+
+ get_out_file(outfile_1, ".out-1", filename);
+ get_out_file(outfile_2, ".out-2", filename);
+
+ write_show_status("vobject.vcf", p_object);
+
+ write_show_status(outfile_1, p_object);
+
+ if (0 == filecomp(outfile_1, filename))
+ {
+ printf(" OK - no differences after 1st read/write\n");
+ }
+ else
+ {
+ printf(" Warning - differences after 1st read/write\n");
+
+ warning = TRUE;
+ }
+
+ if (read_show_status(&p_object_1, outfile_1))
+ {
+ write_show_status(outfile_2, p_object_1);
+ }
+
+ if (0 == filecomp(outfile_2, outfile_1))
+ {
+ printf(" OK - no differences after 2nd read/write\n");
+
+ pass = TRUE;
+ }
+ else
+ {
+ printf(" Error - differences after 2nd read/write\n");
+ }
+
+ vf_delete_object(p_object, TRUE);
+ vf_delete_object(p_object_1, TRUE);
+ }
+
+ update_results(pass, warning);
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * do_title_line()
+ *
+ * DESCRIPTION
+ * Print a title line.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void do_title_line(const char *filename)
+{
+ char title[LINELENGTH];
+
+ memset(title, '-', sizeof(title));
+ title[sizeof(title) - 1] = '\0';
+ memcpy(title + 2, filename, strlen(filename));
+ printf("\n%s\n", title);
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * read_show_status()
+ *
+ * DESCRIPTION
+ * Wrapper on vf_read_file() which displays status after the read.
+ *
+ * RETURNS
+ * Same as wrapped vf_read_file().
+ *----------------------------------------------------------------------------*/
+
+static bool_t read_show_status(
+ VF_OBJECT_T **pp_object,
+ const char *p_name
+ )
+{
+ bool_t ret;
+
+ ret = vf_read_file(pp_object, p_name);
+
+ if (ret)
+ {
+ printf("Successfully read file '%s'\n", p_name);
+ }
+ else
+ {
+ printf("Failed to read file '%s'\n", p_name);
+ }
+
+ return ret;
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_show_status()
+ *
+ * DESCRIPTION
+ * Wrapper on vf_write_file() which displays status after the read.
+ *
+ * RETURNS
+ * Same as wrapped vf_read_file().
+ *----------------------------------------------------------------------------*/
+
+static bool_t write_show_status(
+ const char *p_name,
+ VF_OBJECT_T *p_object
+ )
+{
+ bool_t ret;
+
+ ret = vf_write_file(p_name, p_object, TRUE);
+
+ if (ret)
+ {
+ printf("Successfully wrote file '%s'\n", p_name);
+ }
+ else
+ {
+ printf("Failed to wrote file '%s'\n", p_name);
+ }
+
+ return ret;
+}
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * write_show_status()
+ *
+ * DESCRIPTION
+ * Wrapper on vf_write_file() which displays status after the read.
+ *
+ * RETURNS
+ * Same as wrapped vf_read_file().
+ *----------------------------------------------------------------------------*/
+
+static void update_results(
+ bool_t pass,
+ bool_t warning
+ )
+{
+ char buffer[80];
+
+ tot_tests += 1;
+
+ if (pass)
+ {
+ /* OK */
+ }
+ else
+ {
+ tot_errors += 1;
+ }
+
+ if (warning)
+ {
+ tot_warnings += 1;
+ }
+
+ sprintf(buffer, "[%d tests, %d errors, %d warnings]",
+ tot_tests, tot_errors, tot_warnings);
+
+ printf("%*s\n", LINELENGTH-1, buffer);
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * check_extract_fields()
+ *
+ * DESCRIPTION
+ * Exract fields.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void check_extract_fields(
+ const char *filename,
+ const char *p_array[3]
+ )
+{
+ VF_OBJECT_T *p_object = NULL;
+ bool_t warning = FALSE, pass = FALSE;
+
+ do_title_line(filename);
+
+ if (read_show_status(&p_object, filename))
+ {
+ VF_PROP_T *p_tmp;
+
+ printf(" Looking for {%s}...\n", p_array[0]);
+ if (vf_get_property(&p_tmp, p_object, VFGP_FIND, NULL, p_array[0], NULL))
+ {
+ print_search_results(p_tmp);
+ }
+
+ printf(" Looking for {%s, %s}...\n", p_array[0], p_array[1]);
+ if (vf_get_property(&p_tmp, p_object, VFGP_FIND, NULL, p_array[0], p_array[1], NULL))
+ {
+ print_search_results(p_tmp);
+ }
+
+ printf(" Looking for {%s, %s}...\n", p_array[0], p_array[2]);
+ if (vf_get_property(&p_tmp, p_object, VFGP_FIND, NULL, p_array[0], p_array[2], NULL))
+ {
+ print_search_results(p_tmp);
+ }
+
+ printf(" Looking for {%s, %s, %s}...\n", p_array[0], p_array[1], p_array[2]);
+ if (vf_get_property(&p_tmp, p_object, VFGP_FIND, NULL, p_array[0], p_array[1], p_array[2], NULL))
+ {
+ print_search_results(p_tmp);
+ }
+
+ vf_delete_object(p_object, TRUE);
+
+ pass = TRUE;
+ }
+
+ update_results(pass, warning);
+}
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * extract_groups()
+ *
+ * DESCRIPTION
+ *
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void check_extract_groups(
+ const char *filename,
+ const char *p_group
+ )
+{
+ VF_OBJECT_T *p_object = NULL;
+ bool_t warning = FALSE, pass = FALSE;
+
+ do_title_line(filename);
+
+ if (read_show_status(&p_object, filename))
+ {
+ VF_PROP_T *p_tmp;
+
+ if (vf_get_property(&p_tmp, p_object, VFGP_FIND, p_group, "LOGO", NULL))
+ {
+ print_search_results(p_tmp);
+ }
+
+ vf_delete_object(p_object, TRUE);
+
+ pass = TRUE;
+ }
+
+ update_results(pass, warning);
+}
+
+
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * print_search_results()
+ *
+ * DESCRIPTION
+ * List the values in each of the current search results.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void print_search_results(
+ VF_PROP_T *p_tmp /* Pointer to current property */
+ )
+{
+ do
+ {
+ void *ptr;
+ uint32_t size;
+ vf_encoding_t enc;
+
+ if (vf_get_prop_value(p_tmp, &ptr, &size, &enc))
+ {
+ switch (enc)
+ {
+ case VF_ENC_BASE64:
+ {
+ printf(" prop = \"%s\"\n", vf_get_prop_name_string(p_tmp, 0));
+ }
+ break;
+
+ case VF_ENC_7BIT:
+ case VF_ENC_QUOTEDPRINTABLE:
+ {
+ uint16_t i;
+
+ for (i = 0;;i++)
+ {
+ const char *p_value = vf_get_prop_value_string(p_tmp, i);
+
+ if (p_value)
+ {
+ printf(" field[%d] = \"%s\"\n", i, p_value);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ while (vf_get_next_property(&p_tmp))
+ ;
+}
+
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * check_base64_enc()
+ *
+ * DESCRIPTION
+ * Check BASE64 encoding.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void check_base64_enc(bool_t rdata)
+{
+ char buffer[MAXBASE64ENC+1];
+ int i, s;
+ bool_t pass;
+
+ do_title_line("BASE64 encoding");
+
+ for (s = 1, pass = TRUE;pass && (s < sizeof(buffer));s++)
+ {
+ for (i = 0;i < s;i++)
+ {
+ buffer[i] = (rdata ? rand() : (i + 1)) % 256;
+ }
+
+ pass &= encode_decode_check(buffer, s);
+
+ if (pass)
+ {
+ printf("encode_decode_check() : OK @ %d bytes\r", s);
+ }
+ }
+
+ printf("\n");
+
+ update_results(pass, 0);
+}
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * encode_decode_check()
+ *
+ * DESCRIPTION
+ * Encode & decode chunk of data. Check data consistency.
+ *
+ * RETURNS
+ * TRUE iff encoded / decoded successfully.
+ *----------------------------------------------------------------------------*/
+
+static bool_t encode_decode_check(
+ const char *p_data, /* Pointer to data */
+ uint32_t length /* Length */
+ )
+{
+ VF_OBJECT_T *p_object;
+ const char *testfile = "bindata.vcf";
+ const char *testprop = "X-BINARY-DATA";
+
+ bool_t pass = FALSE;
+
+ p_object = vf_create_object("TEST", NULL);
+
+ if (p_object)
+ {
+ VF_PROP_T *p_prop;
+
+ if (vf_get_property(&p_prop, p_object, VFGP_GET, NULL, testprop, NULL))
+ {
+ vf_set_prop_value_base64(p_prop, p_data, length, TRUE);
+ }
+
+ vf_write_file(testfile, p_object, TRUE);
+
+ vf_delete_object(p_object, TRUE);
+ }
+
+ if (vf_read_file(&p_object, testfile))
+ {
+ VF_PROP_T *p_prop;
+
+ if (vf_get_property(&p_prop, p_object, VFGP_FIND, NULL, testprop, NULL))
+ {
+ const char *p_new_data;
+ uint32_t new_length;
+
+ p_new_data = vf_get_prop_value_base64(p_prop, &new_length);
+
+ if (p_new_data)
+ {
+ if (length == new_length)
+ {
+ if (0 == memcmp(p_data, p_new_data, length))
+ {
+ pass = TRUE;
+ }
+ else
+ {
+ printf("encode_decode_check() : data NOT OK\n");
+ }
+ }
+ else
+ {
+ printf("encode_decode_check() : Length error\n");
+ }
+ }
+ else
+ {
+ printf("encode_decode_check() : No data\n");
+ }
+ }
+
+ vf_delete_object(p_object, TRUE);
+ }
+
+ return pass;
+}
+
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * check_vcal_functions()
+ *
+ * DESCRIPTION
+ * Check the date encoding functions. This is a non systematic random
+ * test ehich generates random values, encodes them, decodes them and
+ * compares the result with the initial value.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+static void check_vcal_functions(void)
+{
+ VF_ISO8601_PERIOD_T test_in, test_out;
+ int i;
+ bool_t pass;
+
+ do_title_line("VCAL encoding functions");
+
+ for (i = 0, pass = TRUE;pass && (i < 1000);i++)
+ {
+ char sz[256];
+
+ get_random_date(&test_in);
+
+ vf_period_time_to_string(sz, &test_in);
+ vf_period_string_to_time(&test_out, sz);
+
+ if (memcmp(&test_in, &test_out, sizeof(VF_ISO8601_PERIOD_T)))
+ {
+ pass = FALSE;
+ }
+ else
+ {
+ printf("check_vcal_functions() : %s \r", sz);
+ }
+ }
+
+ printf("\n");
+
+ update_results(pass, 0);
+}
+
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * get_random_date()
+ *
+ * DESCRIPTION
+ * Initialise a random VF_ISO8601_PERIOD_T value.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void get_random_date(VF_ISO8601_PERIOD_T *p_period)
+{
+ p_period->days = rand() % 100;
+ p_period->hours = rand() % 24;
+ p_period->minutes = rand() % 60;
+ p_period->months = rand() % 12;
+ p_period->seconds = rand() % 60;
+ p_period->weeks = rand() % 9;
+ p_period->years = rand() % 20;
+}
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * get_out_file()
+ *
+ * DESCRIPTION
+ * Obtain the name of a test output file from a teset input file. The
+ * outout filename is the input name with the subscript replaced.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+void get_out_file(
+ char *p_outfile, /* Buffer to receive filename */
+ const char *p_subscript, /* New subscript */
+ const char *p_infile /* Name of source file we're mimicing */
+ )
+{
+ char *p_found_subscript;
+
+ strcpy(p_outfile, p_infile);
+
+ if (NULL == (p_found_subscript = strstr(p_outfile, ".")))
+ {
+ printf("get_out_file() : invalid name (%s) in test files\n", p_outfile);
+ }
+ else
+ {
+ strcpy(p_found_subscript, p_subscript);
+ }
+}
+
diff --git a/vf_iface.h b/vf_iface.h
new file mode 100644
index 0000000..6627bf5
--- /dev/null
+++ b/vf_iface.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+
+ (C) Mathias Palm, 2002 -
+
+ THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+ * This file is only an auxiliary for the linux distribution
+ */
+
+#ifndef _VF_IFACE_H_
+#include "iface/vf_iface.h"
+#endif
diff --git a/vformat/Makefile.am b/vformat/Makefile.am
new file mode 100644
index 0000000..325ccb3
--- /dev/null
+++ b/vformat/Makefile.am
@@ -0,0 +1,2 @@
+include_HEADERS = vf_iface.h
+
diff --git a/vformat/vf_iface.h b/vformat/vf_iface.h
new file mode 100644
index 0000000..8dc1b62
--- /dev/null
+++ b/vformat/vf_iface.h
@@ -0,0 +1,1269 @@
+/******************************************************************************
+
+ (C) Nick Marley, 2001 -
+
+ THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
+ INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
+ RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
+ THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
+ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+FILE
+ $Workfile: vf_iface.h $
+ $Revision: 1.30 $
+ $Author: monos $
+
+ORIGINAL AUTHOR
+ Tilda@users.sourceforge.net <Nick Marley>
+
+DESCRIPTION
+ Main include file for the vFormat object library.
+
+REFERENCES
+ (none)
+
+MODIFICATION HISTORY
+ * $Log: vf_iface.h,v $
+ * Revision 1.30 2002/12/07 17:25:44 monos
+ * *** empty log message ***
+ *
+ * Revision 1.29 2002/11/24 14:26:22 tilda
+ * IID484686 - More vcard work.
+ *
+ * Revision 1.28 2002/11/17 10:01:02 tilda
+ * IID484686 - Yet more vCalendar stuff.
+ *
+ * Revision 1.27 2002/11/16 13:19:10 tilda
+ * IID639288 - Implement method for adding subobjects.
+ *
+ * Revision 1.26 2002/11/03 18:43:16 tilda
+ * IID619851 - Update and check headers and function prototypes.
+ *
+ * Revision 1.25 2002/11/02 18:29:26 tilda
+ * IID485157 - UI does character conversion based on CHARSET property.
+ *
+ * Revision 1.24 2002/11/02 08:56:17 tilda
+ * Start of internationalisation changes.
+ *
+ * Revision 1.23 2002/10/08 21:45:07 tilda
+ * IID620473 - reduce c-runtime dependencies.
+ *
+ * Revision 1.22 2002/10/08 21:15:56 tilda
+ * IID619851 - Update comments.
+ *
+ * Revision 1.21 2002/02/24 17:10:35 tilda
+ * Add API for "is modified" functionality.
+ *
+ * Revision 1.20 2002/02/16 19:14:36 tilda
+ * Various mods improving the command line options.
+ *
+ * Revision 1.19 2002/01/12 15:55:32 tilda
+ * Add pragmas for linking.
+ *
+ * Revision 1.18 2002/01/06 16:18:48 tilda
+ * Add dialog box for events / todos.
+ *
+ * Revision 1.17 2001/12/28 17:23:50 tilda
+ * Minor mods to VTODO etc. defines.
+ *
+ * Revision 1.16 2001/11/16 22:34:49 tilda
+ * New vf_get_property() allows append as well as find,
+ *
+ * Revision 1.15 2001/11/15 08:55:15 tilda
+ * Minor reorganisation & add comments where missing.
+ *
+ * Revision 1.14 2001/11/14 22:36:56 tilda
+ * Add parameter to vf_find_prop_qual_index()
+ *
+ * Revision 1.13 2001/11/14 16:04:16 tilda
+ * Add VFP_ names.
+ *
+ * Revision 1.12 2001/11/12 20:24:54 tilda
+ * Add properties.
+ *
+ * Revision 1.11 2001/11/06 22:51:05 tilda
+ * Supporting access functions for image selection / deletion.
+ *
+ * Revision 1.10 2001/11/05 21:08:02 tilda
+ * Various changes for initial version of vfedit.
+ *
+ * Revision 1.9 2001/10/24 18:36:45 tilda
+ * BASE64 bugfixes. Split reader/writer code. Start create/modify work.
+ *
+ * Revision 1.8 2001/10/24 05:33:16 tilda
+ * Start work on object create/modify API.
+ *
+ * Revision 1.7 2001/10/16 05:50:53 tilda
+ * Debug support for lists of vobjects from single file (ie. a phonebook).
+ *
+ * Revision 1.6 2001/10/14 20:42:37 tilda
+ * Addition of group searching.
+ *
+ * Revision 1.5 2001/10/14 16:40:35 tilda
+ * Initial testing of access functions.
+ *
+ * Revision 1.4 2001/10/13 14:58:56 tilda
+ * Tidy up version headers, add vf_strings.h where needed.
+ *
+ * Revision 1.3 2001/10/10 20:54:34 tilda
+ * Various minor tidy ups.
+ *
+ * Revision 1.2 2001/10/09 22:01:59 tilda
+ * Remove older version control comments.
+ *
+ *****************************************************************************/
+
+#ifndef _VF_IFACE_H_
+#define _VF_IFACE_H_
+
+#ifndef NORCSID
+static const char vf_iface_h_vss_id[] = "$Header: /cvsroot/vformat/src/vformat/vf_iface.h,v 1.30 2002/12/07 17:25:44 monos Exp $";
+#endif
+
+/*============================================================================*
+ Public Includes
+ *============================================================================*/
+
+#include <common/types.h>
+
+#include <stdarg.h>
+
+/* c2man (for producing man pages) can't handle some lines in time.h */
+
+#ifndef __C2MAN__
+#include <time.h>
+#else
+#define time_t long int
+#endif
+
+/*============================================================================*
+ Public defines
+ *============================================================================*/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * Default .DLL build using the symbols maintained by MSDEV.
+ */
+#if defined(WIN) || defined(WIN32)
+ #if defined(_USRDLL)
+ #ifndef VFORMATDECLSPEC
+ #ifdef VFORMATL_EXPORTS
+ #define VFORMATDECLSPEC __declspec(dllexport)
+ #else
+ #define VFORMATDECLSPEC __declspec(dllimport)
+ #endif
+ #endif
+ #endif
+#endif
+
+#if defined(WIN) || defined(WIN32)
+ #if !defined(VFORMAT_BUILD)
+ #if defined(_DEBUG)
+ #pragma comment(lib, "VFORMATLD.lib")
+ #else
+ #pragma comment(lib, "VFORMATL.lib")
+ #endif
+ #endif
+#endif
+
+
+/*
+ * Remove VFORMATDECLSPEC if not defined.
+ */
+#ifndef VFORMATDECLSPEC
+ #define VFORMATDECLSPEC
+#endif
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * Definitions of the standard properties.
+ *----------------------------------------------------------------------------*/
+
+#define VFP_AALARM "AALARM"
+#define VFP_ADDITIONALNAMES "ADDN"
+#define VFP_ADR "ADR"
+#define VFP_AGENT "AGENT"
+#define VFP_AIFF "AIFF"
+#define VFP_AOL "AOL"
+#define VFP_APPLELINK "APPLELINK"
+#define VFP_ATTACH "ATTACH"
+#define VFP_ATTENDEE "ATTENDEE"
+#define VFP_ORGANIZER "ORGANIZER"
+#define VFP_OWNER "OWNER"
+#define VFP_DELEGATE "DELEGATE"
+#define VFP_ACCEPTED "ACCEPTED"
+#define VFP_NEEDSACTION "NEEDS ACTION"
+#define VFP_SENT "SENT"
+#define VFP_TENTATIVE "TENTATIVE"
+#define VFP_CONFIRMED "CONFIRMED"
+#define VFP_DECLINED "DECLINED"
+#define VFP_COMPLETED "COMPLETED"
+#define VFP_DELEGATED "DELEGATED"
+#define VFP_CATERING "CATERING"
+#define VFP_COMPUTERPROJECTOR "COMPUTER PROJECTOR"
+#define VFP_EASEL "EASEL"
+#define VFP_OVERHEADPROJECTOR "OVERHEAD PROJECTOR"
+#define VFP_SPEAKERPHONE "SPEAKER PHONE"
+#define VFP_TABLE "TABLE"
+#define VFP_TV "TV"
+#define VFP_VCR "VCR"
+#define VFP_VIDEOPHONE "VIDEO PHONE"
+#define VFP_VEHICLE "VEHICLE"
+#define VFP_ATTMAIL "ATTMAIL"
+#define VFP_AUDIOCONTENT "AUDIOCONTENT"
+#define VFP_AVI "AVI"
+#define VFP_BBS "BBS"
+#define VFP_BIRTHDATE "BDAY"
+#define VFP_BMP "BMP"
+#define VFP_BODY "BODY"
+#define VFP_BUSINESSROLE "ROLE"
+#define VFP_CAPTION "CAP"
+#define VFP_CAR "CAR"
+#define VFP_CATEGORIES "CATEGORIES"
+#define VFP_CELLULAR "CELL"
+#define VFP_CGM "CGM"
+#define VFP_CHARSET "CHARSET"
+#define VFP_CID "CID"
+#define VFP_CIS "CIS"
+#define VFP_CITY "L"
+#define VFP_CLASS "CLASS"
+#define VFP_COMMENT "NOTE"
+#define VFP_COMPLETED "COMPLETED"
+#define VFP_CONTENTID "CONTENT-ID"
+#define VFP_COUNTRYNAME "C"
+#define VFP_DALARM "DALARM"
+#define VFP_DATASIZE "DATASIZE"
+#define VFP_DAYLIGHT "DAYLIGHT"
+#define VFP_DCREATED "DCREATED"
+#define VFP_DELIVERYLABEL "LABEL"
+#define VFP_DESCRIPTION "DESCRIPTION"
+#define VFP_DIB "DIB"
+#define VFP_DISPLAYSTRING "DISPLAYSTRING"
+#define VFP_DOMESTIC "DOM"
+#define VFP_DTEND "DTEND"
+#define VFP_DTSTART "DTSTART"
+#define VFP_DUE "DUE"
+#define VFP_EMAILADDRESS "EMAIL"
+#define VFP_ENCODING "ENCODING"
+#define VFP_EWORLD "EWORLD"
+#define VFP_EXNUM "EXNUM"
+#define VFP_EXPDATE "EXDATE"
+#define VFP_EXPECT "EXPECT"
+#define VFP_EXTADDRESS "EXT ADD"
+#define VFP_FAMILYNAME "F"
+#define VFP_FAX "FAX"
+#define VFP_FULLNAME "FN"
+#define VFP_GEO "GEO"
+#define VFP_GEOLOCATION "GEO"
+#define VFP_GIF "GIF"
+#define VFP_GIVENNAME "G"
+#define VFP_GROUPING "GROUPING"
+#define VFP_HOME "HOME"
+#define VFP_IBMMAIL "IBMMAIL"
+#define VFP_INLINE "INLINE"
+#define VFP_INTERNATIONAL "INTL"
+#define VFP_INTERNET "INTERNET"
+#define VFP_ISDN "ISDN"
+#define VFP_JPEG "JPEG"
+#define VFP_LANGUAGE "LANG"
+#define VFP_LASTMODIFIED "LAST-MODIFIED"
+#define VFP_LASTREVISED "REV"
+#define VFP_LOCATION "LOCATION"
+#define VFP_LOGO "LOGO"
+#define VFP_MAILER "MAILER"
+#define VFP_MALARM "MALARM"
+#define VFP_MCIMAIL "MCIMAIL"
+#define VFP_MESSAGE "MSG"
+#define VFP_MET "MET"
+#define VFP_MODEM "MODEM"
+#define VFP_MPEG2 "MPEG2"
+#define VFP_MPEG "MPEG"
+#define VFP_MSN "MSN"
+#define VFP_NAMEPREFIXES "NPRE"
+#define VFP_NAME "N"
+#define VFP_NAMESUFFIXES "NSUF"
+#define VFP_NOTE "NOTE"
+#define VFP_ORGNAME "ORGNAME"
+#define VFP_ORG "ORG"
+#define VFP_ORGUNIT2 "OUN2"
+#define VFP_ORGUNIT3 "OUN3"
+#define VFP_ORGUNIT4 "OUN4"
+#define VFP_ORGUNIT "OUN"
+#define VFP_PAGER "PAGER"
+#define VFP_PALARM "PALARM"
+#define VFP_PARCEL "PARCEL"
+#define VFP_PART "PART"
+#define VFP_PCM "PCM"
+#define VFP_PDF "PDF"
+#define VFP_PGP "PGP"
+#define VFP_PHOTO "PHOTO"
+#define VFP_PROPTYPE "TYPE"
+#define VFP_PICT "PICT"
+#define VFP_PMB "PMB"
+#define VFP_POSTALBOX "BOX"
+#define VFP_POSTALCODE "PC"
+#define VFP_POSTAL "POSTAL"
+#define VFP_POWERSHARE "POWERSHARE"
+#define VFP_PREFERRED "PREF"
+#define VFP_PRIORITY "PRIORITY"
+#define VFP_PROCEDURENAME "PROCEDURENAME"
+#define VFP_PRODID "PRODID"
+#define VFP_PRODIGY "PRODIGY"
+#define VFP_SOUND "SOUND"
+#define VFP_PS "PS"
+#define VFP_PUBLICKEY "KEY"
+#define VFP_QP "QP"
+#define VFP_QUICKTIME "QTIME"
+#define VFP_RDATE "RDATE"
+#define VFP_REGION "R"
+#define VFP_RELATEDTO "RELATED-TO"
+#define VFP_REPEATCOUNT "REPEATCOUNT"
+#define VFP_RESOURCES "RESOURCES"
+#define VFP_RNUM "RNUM"
+#define VFP_ROLE "ROLE"
+#define VFP_RRULE "RRULE"
+#define VFP_RSVP "RSVP"
+#define VFP_RUNTIME "RUNTIME"
+#define VFP_SEQUENCE "SEQUENCE"
+#define VFP_SNOOZETIME "SNOOZETIME"
+#define VFP_START "START"
+#define VFP_STATUS "STATUS"
+#define VFP_STREETADDRESS "STREET"
+#define VFP_SUBTYPE "SUBTYPE"
+#define VFP_SUMMARY "SUMMARY"
+#define VFP_TELEPHONE "TEL"
+#define VFP_TIFF "TIFF"
+#define VFP_TIMEZONE "TZ"
+#define VFP_TITLE "TITLE"
+#define VFP_TLX "TLX"
+#define VFP_TRANSP "TRANSP"
+#define VFP_UNIQUESTRING "UID"
+#define VFP_URL "URL"
+#define VFP_URLVALUE "URLVAL"
+#define VFP_VALUE "VALUE"
+#define VFP_VERSION "VERSION"
+#define VFP_VIDEO "VIDEO"
+#define VFP_VOICE "VOICE"
+#define VFP_WAVE "WAVE"
+#define VFP_WMF "WMF"
+#define VFP_WORK "WORK"
+#define VFP_X400 "X400"
+#define VFP_X509 "X509"
+#define VFP_XRULE "XRULE"
+
+#define VFP_UTF8 "UTF-8"
+
+#define VFP_PRONUNCIATION VFP_SOUND /* ??? */
+
+/*
+ * Property tokesn indicating encoding.
+ */
+#define VFP_7BIT "7BIT"
+#define VFP_8BIT "8BIT"
+#define VFP_BASE64 "BASE64"
+#define VFP_QUOTEDPRINTABLE "QUOTED-PRINTABLE"
+
+/*
+ * Names for the "begin" token.
+ */
+#define VF_NAME_VCALENDAR "VCALENDAR"
+#define VF_NAME_VCARD "VCARD"
+#define VF_NAME_VNOTE "VNOTE"
+#define VF_NAME_VEVENT "VEVENT"
+#define VF_NAME_VTODO "VTODO"
+
+
+/*
+ * Special token that matches any when searching.
+ */
+#define VFP_ANY "*"
+
+/*
+ * Indexes for compound name properties (the "N" property).
+ */
+#define VFP_NAME_FAMILY (0)
+#define VFP_NAME_GIVEN (1)
+#define VFP_NAME_MIDDLE (2)
+#define VFP_NAME_TITLE (3)
+
+/*
+ * Indexes for compound address properties (the "ADR" property).
+ */
+#define VFP_ADR_POBOX (0)
+#define VFP_ADR_EXTENDED (1)
+#define VFP_ADR_STREET (2)
+#define VFP_ADR_CITY (3)
+#define VFP_ADR_REGION (4)
+#define VFP_ADR_POSTCODE (5)
+#define VFP_ADR_COUNTRY (6)
+
+/*
+ * Indexes for compound organisation properties (the "ORG" property)
+ */
+#define VFP_ORG_NAME (0)
+#define VFP_ORG_DIVISION (1)
+
+/*
+ * Type declaring macro.
+ */
+#define VF_DECLARE_TYPE(x) typedef struct _vf_##x { uint8_t _; } x;
+
+/*============================================================================*
+ Public Types
+ *============================================================================*/
+
+/*
+ * Type representing "parser" - an object used to parse VOBJECTS.
+ */
+VF_DECLARE_TYPE(VF_PARSER_T)
+
+/*
+ * Type representing an "object" - objects are collections of properties.
+ */
+VF_DECLARE_TYPE(VF_OBJECT_T)
+
+/*
+ * Type representing a "property" - properties associate a name & a value.
+ */
+VF_DECLARE_TYPE(VF_PROP_T)
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * VF_ISO8601_PERIOD_T is used to encapsulate an ISO time 'period'.
+ *----------------------------------------------------------------------------*/
+
+typedef struct VF_ISO8601_PERIOD_T
+{
+ uint32_t years;
+ uint32_t months;
+ uint32_t weeks;
+ uint32_t days;
+ uint32_t hours;
+ uint32_t minutes;
+ uint32_t seconds;
+}
+VF_ISO8601_PERIOD_T;
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * vf_encoding_t enumerates the supported encodings (formats) of a
+ * vformat object property. Each "value" has a field of this type.
+ *----------------------------------------------------------------------------*/
+
+typedef uint8_t vf_encoding_t;
+
+#define VF_ENC_UNKNOWN ((vf_encoding_t)(0))
+#define VF_ENC_7BIT ((vf_encoding_t)(1))
+#define VF_ENC_8BIT ((vf_encoding_t)(2))
+#define VF_ENC_BASE64 ((vf_encoding_t)(3))
+#define VF_ENC_QUOTEDPRINTABLE ((vf_encoding_t)(4))
+#define VF_ENC_VOBJECT ((vf_encoding_t)(5))
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * vf_get_t controls the operation of vf_get_property() (qv). Controls
+ * how far the search algorithm is prepared to go in order to return a
+ * property ready for modification.
+ *----------------------------------------------------------------------------*/
+
+typedef uint16_t vf_get_t;
+
+#define VFGP_FIND ((vf_get_t)(0x0001)) /* Search for property */
+#define VFGP_APPEND ((vf_get_t)(0x0002)) /* Append property, no search */
+#define VFGP_GET ((vf_get_t)(0x0003)) /* Find & append if not present */
+
+
+/*----------------------------------------------------------------------------*
+ * PURPOSE
+ * vf_search_flags_t is used to describe how string matching is performed
+ * when searching for properties, qualifiers, values etc.
+ *----------------------------------------------------------------------------*/
+
+typedef uint32_t vf_search_flags_t;
+
+/*============================================================================*
+ Public Functions
+ *============================================================================*/
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_init()
+ *
+ * DESCRIPTION
+ * Allocate and initialise a parser. To parse a VCARD (or any vObject)
+ * a user allocates a parser, pushes data through it using vf_parse_text()
+ * and finally calls vf_parse_end():
+ *
+ * VF_PARSER_T *p_parser;
+ *
+ * if (vf_parse_init(&p_parser, pp_object))
+ * {
+ * do
+ * {
+ * char buffer[...];
+ * int numchars;
+ *
+ * numchars = get_chars_from_somewhere(buffer, ...);
+ *
+ * ret = vf_parse_text(p_parser, buffer, numchars);
+ * }
+ * while (ret && (0 < charsread))
+ * ;
+ *
+ * if (!vf_parse_end(p_parser))
+ * {
+ * ret = FALSE;
+ * }
+ * }
+ *
+ * A parser allocated by vf_parse_init(), must be deallocated by calling
+ * vf_parse_end() whether or not parsing succeeds. Also, parsing may not
+ * be complete (ie. values may be held buffered and not evaluated fully
+ * or assigned to a VF_OBJECT_T) untill the final call to vf_parse_end()
+ * => after a vf_parse_init() you _must_ vf_parse_end().
+ *
+ * RETURNS
+ * TRUE iff parser allocated successfully.
+ *----------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_parse_init(
+ VF_PARSER_T **pp_parser, /* Ptr to allocated parser */
+ VF_OBJECT_T **pp_object /* The object we're parsing into */
+ );
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_text()
+ *
+ * DESCRIPTION
+ * Parse indicated text into the object associated with the VPARSE_T.
+ *
+ * See notes for vf_parse_init().
+ *
+ * RETURNS
+ * TRUE <=> allocation & syntax OK, FALSE else.
+ *----------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_parse_text(
+ VF_PARSER_T *p_parse, /* The parser */
+ char *p_chars, /* New characters to parse into object */
+ int numchars /* Number of new characters */
+ );
+
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_parse_end()
+ *
+ * DESCRIPTION
+ * Ensure parse completion, release memory associated with the parser.
+ *
+ * See notes for vf_parse_init().
+ *
+ * RETURNS
+ * TRUE <=> parse complete with no error.
+ *----------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_parse_end(
+ VF_PARSER_T *p_parse /* The parser */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_read_file()
+ *
+ * DESCRIPTION
+ * Reads indicated VOBJECT_T file.
+ *
+ * RETURNS
+ * TRUE <=> read OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_read_file(
+ VF_OBJECT_T **pp_object, /* Pointer to output object */
+ const char *p_name /* Name of file to read */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_write_file()
+ *
+ * DESCRIPTION
+ * Write indicated vobject to file. For lists of objects (eg. read from
+ * a phonebook) the write_all parameter allows the caller to control if
+ * the library writes the entire list or just the head item.
+ *
+ * RETURNS
+ * TRUE <=> written OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_write_file(
+ const char *p_name, /* Outpt filename */
+ VF_OBJECT_T *p_object, /* The object to write */
+ bool_t write_all /* Should write p_next as well? */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_next_object()
+ *
+ * DESCRIPTION
+ * Find "next" vobject. Typically called after a call to vf_read_file()
+ * which may well read a list of objects from a file for example:
+ *
+ * if (vf_read_file(&p_object, p_filename))
+ * {
+ * do
+ * {
+ * ...
+ * }
+ * while (vf_get_next_object(&p_object))
+ * ;
+ * }
+ *
+ * The value of *pp_object is updated by the call if it returns TRUE.
+ *
+ * RETURNS
+ * TRUE iff found (ie. there is a "next" object).
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_next_object(
+ VF_OBJECT_T **pp_object /* Ptr to pointer to current object */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_create_object()
+ *
+ * DESCRIPTION
+ * Creates an empty vformat object.
+ *
+ * RETURNS
+ * Ptr to object if created else NULL.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC VF_OBJECT_T *vf_create_object(
+ const char *p_type, /* Type of object to create */
+ VF_OBJECT_T *p_parent /* Parent object if any */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_object_type()
+ *
+ * DESCRIPTION
+ * Return the type string identifying the indicated vformat object,
+ * the string after the 'BEGIN' mark so 'VCARD' or 'VNOTE' etc.
+ *
+ * RETURNS
+ * Ptr to string.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC const char *vf_get_object_type(
+ VF_OBJECT_T *p_object /* Object to locate type of */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_property()
+ *
+ * DESCRIPTION
+ * Basic searching function locating elements of the VOBJECT by qualified
+ * name. The function is a varargs function (like sprintf) and the list
+ * of arguments must be NULL terminated (hence the appearance of the
+ * p_qualifier argument in the arglist). Valid calls might be:
+ *
+ * vf_get_property(&p_out, p_object, VFGP_FIND, NULL, "N", NULL);
+ * - find and return "N" properties. If there are none, return FALSE.
+ *
+ * vf_get_property(&p_out, p_object, VFGP_FIND, NULL, "TEL", "WORK", NULL);
+ * - find and return "TEL" entries qualified by the "work" attribute
+ * (ie. work phone numbers). If there are none, return FALSE.
+ *
+ * vf_get_property(&p_out, p_object, VFGP_GET, NULL, "TEL", "WORK", NULL);
+ * - find and return work phone number. The entry is automatically
+ * added if not pre-existing.
+ *
+ * vf_get_property(&p_out, p_object, VFGP_GET, NULL, "TEL", "WORK", NULL);
+ * - find and return work phone numbers in the group identifier by the "ME"
+ * identifier. The entry is automatically added if not pre-existing.
+ *
+ * vf_get_property(&p_out, p_object, VFGP_FIND, "ME", "*", NULL);
+ * - effectively enumerates all entries in the "ME" group.
+ *
+ * A pointer to the first property matching the search criteria is returned
+ * via the pp_prop argument. The search actually locates all such matches
+ * and pointer to subsequent entries (if there are >1) may be found by
+ * calling the vf_get_next_property() function.
+ *
+ * The tags may occur in any order _except_ that the p_name must be first.
+ *
+ * Note that the VF_PROP_T returned by pp_prop is an opaque type and the
+ * functions vf_get_prop_xxxx() etc. must be used to locate real "values".
+ *
+ * Cached search results (the list enumerated by subsequent calls to the
+ * vf_get_next_property() function) are maintained through the use of a
+ * a single internal pointer therefore this method is not thread safe.
+ *
+ * RETURNS
+ * TRUE iff found/added successfully. Ptr to prop returned via pp_prop.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_property(
+ VF_PROP_T **pp_prop, /* Output pointer */
+ VF_OBJECT_T *p_object, /* Object to add to */
+ vf_get_t ops, /* Search flags */
+ const char *p_group, /* Group name if any */
+ const char *p_name, /* Name of tag */
+ const char *p_qualifier, /* First qualifier if any */
+ ... /* Subequent qualifiers */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_property_ex()
+ *
+ * DESCRIPTION
+ * The grunt behind vf_get_property(). Manages the search as described
+ * vf_get_property() but takes the list of arguments as a va_list.
+ * This function should be used when writing higher layer functions
+ * which take varargs (eg. DDX functions).
+ *
+ * RETURNS
+ * TRUE iff found/added successfully. ptr to prop returned via pp_prop.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_property_ex(
+ VF_PROP_T **pp_prop, /* Output pointer */
+ VF_OBJECT_T *p_object, /* Object to search */
+ vf_get_t ops, /* Search flags */
+ const char *p_group, /* Group name if any */
+ const char *p_name, /* Name of tag */
+ const char *p_qualifier, /* First qualifier if any */
+ va_list args /* Argument list */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_next_property()
+ *
+ * DESCRIPTION
+ * Find the next property given the current search critera. User
+ * calls vf_get_property() to locate first in a bunch of properties
+ * and can iterate over the rest by calling vf_get_next_property().
+ *
+ * RETURNS
+ * TRUE iff found, FALSE else. *pp_prop points to the nex property.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_next_property(
+ VF_PROP_T **pp_prop /* Output pointer */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value()
+ *
+ * DESCRIPTION
+ * Get hold of raw fields associated with the property. These are of
+ * various types:
+ *
+ * VF_ENC_VOBJECT
+ * - *pp_value = pointer to contained VF_OBJECT_T which can be
+ * passed back to any of the object manipulation functions.
+ *
+ * VF_ENC_7BIT, VF_ENC_QUOTEDPRINTABLE
+ * - *pp_value = ptr to array of char*, *p_size = number of elts.
+ *
+ * VF_ENC_8BIT, VF_BASE64
+ * - *pp_value = ptr to bytes, *p_size = number of bytes
+ *
+ * RETURNS
+ * TRUE <=> encoding is valid, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_prop_value(
+ VF_PROP_T *p_prop, /* The property */
+ void **pp_value, /* Pointer value */
+ uint32_t *p_size, /* Integer value */
+ vf_encoding_t *p_encoding /* Type of return values */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value()
+ *
+ * DESCRIPTION
+ * Set values associated with a property.
+ *
+ * Passing a value of encoding not the same as the current property
+ * encoding will cause the property contents to be freed prior to
+ * setting the indicated value.
+ *
+ * RETURNS
+ * TRUE <=> re-allocation success & encoding correct, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_value(
+ VF_PROP_T *p_prop, /* The property */
+ void *p_value, /* Pointer to the data */
+ uint32_t n_param, /* Data size or index */
+ vf_encoding_t encoding, /* Encoding in use */
+ bool_t copy /* Copy the data? */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_string()
+ *
+ * DESCRIPTION
+ * Obtain string pointer value from VF_PROP_T. For example a property
+ * may be defined as:
+ *
+ * THING;THIS=STUFF;WITH-QUALIFIERS:fred-fred-fred;gogogo;baabaabaa
+ *
+ * A call to vf_get_prop_value_string() specifying n_string=1 will
+ * return a pointer to the gogogo value.
+ *
+ * Return NULL if out of range request, ie. n_string=3 for N:0;1;2
+ *
+ * RETURNS
+ * Pointer to string value if value present, NULL if index too large.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC char *vf_get_prop_value_string(
+ VF_PROP_T *p_prop, /* Property to locate string from */
+ uint32_t n_string /* Index to string requred */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_name_string()
+ *
+ * DESCRIPTION
+ * Get n'th name string. For example a property may be defined as:
+ *
+ * THING;THIS=STUFF;WITH-QUALIFIERS:fred-fred-fred;gogogo;baabaabaa
+ *
+ * A call to vf_get_prop_name_string() specifying n_string=2 will
+ * return a pointer to the WITH-QUALIFIERS value.
+ *
+ * Return NULL if out of range request, ie. n_string=4 for X;A;B;C:foo
+ *
+ * RETURNS
+ * Pointer to string value if value present, NULL if index too large.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC char *vf_get_prop_name_string(
+ VF_PROP_T *p_prop, /* Property to locate string from */
+ uint32_t n_string /* Index to string requred */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_name_string()
+ *
+ * DESCRIPTION
+ * Set n'th name string.
+ *
+ * RETURNS
+ * TRUE iff allocation OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_name_string(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ uint32_t n_string, /* Index to string */
+ const char *p_string /* Pointer to string */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_name()
+ *
+ * DESCRIPTION
+ * Build the property name string in the indicated buffer.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC void vf_get_prop_name(
+ VF_PROP_T *p_prop, /* The property */
+ char *p_buffer, /* The buffer */
+ uint32_t bufsize /* Size of the buffer */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_object()
+ *
+ * DESCRIPTION
+ * Obtain object pointer value from VF_PROP_T.
+ *
+ * RETURNS
+ * Pointer to vobject value (or NULL if not found).
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC VF_OBJECT_T *vf_get_prop_value_object(
+ VF_PROP_T *p_prop /* Property to locate object from */
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_object()
+ *
+ * DESCRIPTION
+ * Set the value of the indicated property to be a VOBJECT.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_value_object(
+ VF_PROP_T *p_prop,
+ VF_OBJECT_T *p_object
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_string()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_value_string(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ uint32_t n_string, /* Index to string */
+ const char *p_string /* Pointer to string */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_base64()
+ *
+ * DESCRIPTION
+ * Set the value of a property.
+ *
+ * RETURNS
+ * TRUE <=> set successfully.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_value_base64(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ const uint8_t *p_data, /* Pointer to the binary data */
+ uint32_t length, /* Length of the binary data */
+ bool_t copy /* Copy or keep pointer */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_base64()
+ *
+ * DESCRIPTION
+ * Get a BASE64 property. Returns ptr, passes length via parameter.
+ *
+ * RETURNS
+ * Ptr to data.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC const uint8_t *vf_get_prop_value_base64(
+ VF_PROP_T *p_prop, /* Property we're setting a value in */
+ uint32_t *p_length /* Length of the binary data */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_property_from_file()
+ *
+ * DESCRIPTION
+ * Loads the indicated file into memory and sets the indicated property.
+ *
+ * RETURNS
+ * TRUE iff succeded, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_property_from_file(
+ VF_PROP_T *p_prop, /* The property */
+ vf_encoding_t encoding, /* Encoding to use */
+ const char *p_filename /* Source filename */
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_delete_object()
+ *
+ * DESCRIPTION
+ * Cleans up the memory used by the indicated vformat object.
+ *
+ * RETURNS
+ * (none)
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC void vf_delete_object(
+ VF_OBJECT_T *p_object, /* The object to delete */
+ bool_t all /* Delete all subsequent objects? */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_delete_prop()
+ *
+ * DESCRIPTION
+ * Deletes indicated property from the indicated object. Deletes prop
+ * contents if dc is set.
+ *
+ * RETURNS
+ * (none)
+ *----------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC void vf_delete_prop(
+ VF_OBJECT_T *p_object, /* The object we're deleting from */
+ VF_PROP_T *p_prop, /* The property we're removing */
+ bool_t dc /* Should property contents be deleted? */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_find_prop_qual_index()
+ *
+ * DESCRIPTION
+ * Locate property qualifier given either an array of possible values
+ * or a single token that is either present or absent. For example
+ * if we have a property:
+ *
+ * NAME;THIRD;TIME;LUCKY:VALUE1;VALUE2;VALUE3
+ *
+ * Then there are two possible searches.
+ *
+ * Firstly we can look for the property qualifier which can take values
+ * from the array { "FIRST", "SECOND", THIRD" } in which case the array
+ * is passed as pp_possible_values and the function returns with the
+ * values *p_found_value_index=2, p_qualifier_index=1
+ *
+ * Secondly we can look for the token with value "TIME" in which case
+ * p_token is set to "TIME" and the function returns *p_qualifier_index=2.
+ *
+ * RETURNS
+ * TRUE iff found, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_find_prop_qual_index(
+ VF_PROP_T *p_prop, /* The property we're querying */
+ uint32_t *p_qualifier_index, /* Ptr to output name index */
+ uint32_t *p_found_value_index, /* Ptr to output index in array */
+ const char **pp_possible_values, /* Array of possible values */
+ const char *p_token, /* Token searched for */
+ vf_search_flags_t match /* String comparison flags */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_is_modified()
+ *
+ * DESCRIPTION
+ * Fetch status of modified flag.
+ *
+ * RETURNS
+ * TRUE iff modified since list read/write.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_is_modified(
+ VF_OBJECT_T *p_object /* The object */
+ );
+
+
+/*----------------------------------------------------------------------------*
+ * NAME
+ * vf_find_charset()
+ *
+ * DESCRIPTION
+ * Locate the CHARSET property which indicates the character encoding
+ * in use - which indicates how the octet stream encoded in the VCARD
+ * is to be decoded into characters.
+ *
+ * RETURNS
+ * Pointer to character encoding name eg. "UTF-8".
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC const char *vf_find_charset(
+ VF_PROP_T *p_prop /* The property we're querying */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_date_string_to_time()
+ *
+ * DESCRIPTION
+ * Convert calendar string to absolute time. The basic formats are
+ * 19960401, 19960401T073000Z
+ *
+ * RETURNS
+ * TRUE <=> conversion OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_date_string_to_time(
+ uint32_t *p_time, /* Output time value */
+ const char *p_string /* Input string */
+ );
+
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_period_string_to_time()
+ *
+ * DESCRIPTION
+ * Convert period definition string to time value. The format is
+ * P[aaaY][bbbM][cccW][dddD]T[eeeH][fffM][gggS] where 'aaa' is a
+ * number of years, bbb months etc.
+ *
+ * RETURNS
+ * TRUE <=> conversion OK, FALSE else.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_period_string_to_time(
+ VF_ISO8601_PERIOD_T *p_period, /* Output time value */
+ const char *p_string /* Input string */
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_period_time_to_string()
+ *
+ * DESCRIPTION
+ * Convert a VF_ISO8601_PERIOD_T to a string.
+ *
+ * RETURNS
+ * Number of characters written.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC uint32_t vf_period_time_to_string(
+ char *p_string, /* Output string */
+ const VF_ISO8601_PERIOD_T *p_period /* Input period value */
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_set_prop_value_time()
+ *
+ * DESCRIPTION
+ * Set a time_t value into a VF property.
+ *
+ * RETURNS
+ * TRUE iff property added & set OK.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_set_prop_value_time(
+ VF_PROP_T *p_prop, /* The property */
+ uint32_t n_string, /* Which string we're encoding to */
+ const time_t t_value /* Time value */
+ );
+
+
+/*---------------------------------------------------------------------------*
+ * NAME
+ * vf_get_prop_value_time()
+ *
+ * DESCRIPTION
+ * Fetch a time_t value from a VF property.
+ *
+ * RETURNS
+ * TRUE iff foudn & converted OK.
+ *---------------------------------------------------------------------------*/
+
+extern VFORMATDECLSPEC bool_t vf_get_prop_value_time(
+ VF_PROP_T *p_prop, /* The property */
+ uint32_t n_string, /* Which string we're decoding */
+ time_t *p_t_value /* Pointer to output time value */
+ );
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*============================================================================*
+ End of file
+ *============================================================================*/
+
+#endif /*_VF_IFACE_H_*/