From: Michael Rasmussen Date: Mon, 30 Dec 2019 21:52:03 +0000 (+0100) Subject: Completed initialization X-Git-Url: http://git.datanom.net/vcard-parser.git/commitdiff_plain/0d68a95569264bb6b305c87c6dfc1c50ad536a79 Completed initialization Signed-off-by: Michael Rasmussen --- diff --git a/autogen.sh b/autogen.sh index 0c4b0ae..c9f6e38 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,8 +1,32 @@ #!/bin/sh -autoconf -automake --add-missing -libtoolize -autoreconf -f -./configure --enable-maintainer-mode +echo "Rebuilding build system......" +autoreconf --version 2>&1 > /dev/null 2>&1 + +if [ $? -eq 0 ]; then + AUTORECONF=autoreconf +else + AUTORECONF= +fi + +error() { + echo "Missing tool: $1" + echo "Cannot proceed until the missing tool is available" + exit 1 +} + +if [ ! -z ${AUTORECONF} ]; then + echo "Using autoreconf to rebuild build system" + autoreconf --force --install --symlink +else + echo "No autoreconf found. Using plain old tools to rebuild build system" + libtoolize --automake --force || error libtoolize + aclocal -I m4|| error aclocal + autoheader --force || error autoheader + automake --add-missing --force-missing --gnu || error automake + autoconf --force || error autoconf +fi +./configure --enable-maintainer-mode $* + +exit 0 diff --git a/configure.ac b/configure.ac index ead011d..9b9f85c 100644 --- a/configure.ac +++ b/configure.ac @@ -33,7 +33,7 @@ if test x$PKG_CONFIG = xno ; then AC_MSG_ERROR([*** pkg-config not found. See http://www.freedesktop.org/software/pkgconfig/]) fi -PKG_CHECK_MODULES(GLIB, [glib-2.0]) +PKG_CHECK_MODULES(GLIB, [[glib-2.0 >= 2.30 gmodule-2.0 >= 2.30 gobject-2.0 >= 2.30 gthread-2.0 >= 2.30]]) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) @@ -69,6 +69,8 @@ else fi AM_CONDITIONAL(BUILD_EXAMPLE, test x"$ac_enable_example" = "xyes") +AC_DEFINE_UNQUOTED(TEST_SRC_DIR, "$srcdir", [location of source code]) + AC_CONFIG_COMMANDS( [summary], [[echo "" diff --git a/example/Makefile.am b/example/Makefile.am index f742448..d6a6b11 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -9,11 +9,9 @@ AM_CPPFLAGS = \ bin_PROGRAMS = vcard-example vcard_example_SOURCES = \ - vcard-example - -vcard_example_LDFLAGS = \ - -L$(top_srcdir)/src/ + vcard-example.c vcard_example_LDADD = \ - $(GLIB_LIBS) \ - -lvCard + -L${top_srcdir}/src \ + -lvCard \ + $(GLIB_LIBS) diff --git a/example/vcard-example.c b/example/vcard-example.c index 254bca4..43e5b2d 100644 --- a/example/vcard-example.c +++ b/example/vcard-example.c @@ -1,5 +1,56 @@ -# include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include "vcard.h" + +int main(int argc, char *argv[]) { + GError* err = NULL; + gchar* buffer = NULL; + int args; + + if (argc > 1) { + for (args = 1; args < argc; args++) { + g_file_get_contents(argv[args], &buffer, NULL, &err); + + if (err) { + fprintf(stderr, "%s\n", err->message); + g_error_free(err); + return 1; + } + + GSList* list = VCard_new_from_text(buffer, VCARD_VERSION_DETECT, FALSE); + g_free(buffer); + buffer = NULL; + GSList* tmp = list; + while (tmp) { + VCard* vc = (VCard*) tmp->data; + gchar* state = VCard_get_state(vc); + if (g_strcmp0("OK", state) != 0) + fprintf(stderr, "%s\n", state); + g_free(state); + + g_print("Search property ADR in vCard\n"); + GSList* prop = VCard_get_property(vc, "ADR"); + for (GSList* iter = prop; iter; iter = g_slist_next(iter)) { + gchar* s = (gchar*) iter->data; + g_print("%s\n", s); + g_free(s); + } + g_slist_free(prop); + tmp = tmp->next; + } + VCard_print_list(list); + g_print("\n"); + VCard_list_free(list); + } + } else { + g_print("Mising file argument(s)\n"); + g_print("Usage: %s file [file ..]\n", argv[0]); + } -int main() { return 0; } diff --git a/src/Makefile.am b/src/Makefile.am index e4bf932..157805a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,19 +1,28 @@ AUTOMAKE_OPTIONS = gnu -AM_CPPFLAGS = \ +libvCard_la_CPPFLAGS = \ + -I$(top_builddir) \ + -I $(top_srcdir) \ + @GLIB_CFLAGS@ \ + $(AM_CPPFLAGS) + +libvCard_la_CFLAGS = \ @GLIB_CFLAGS@ \ - -I $(top_srcdir) + $(AM_CFLAGS) lib_LTLIBRARIES = libvCard.la libvCard_la_SOURCES = \ vcard.c \ - vcard-parser.h + vcard-parser.h \ + vcard-parser.c libvCard_la_LDFLAGS = \ -version-info @LIB_VERSION@ + include_HEADERS = \ - vcard.h + vcard.h \ + globals.h libvCard_la_LIBADD = \ @GLIB_LIBS@ diff --git a/src/vcard-parser.h b/src/vcard-parser.h index 9884abb..0eb4670 100644 --- a/src/vcard-parser.h +++ b/src/vcard-parser.h @@ -19,15 +19,18 @@ * MA 02110-1301, USA. */ -#ifndef __VCARD_H__ -#define __VCARD_H__ +#ifndef __VCARD_PARSER_H__ +#define __VCARD_PARSER_H__ #include G_BEGIN_DECLS +#include + typedef enum { // vCard 2.1 properties and up + // https://github.com/emacsmirror/addressbook/blob/master/vcard-21.txt N = 0, FN, PHOTO, @@ -50,11 +53,16 @@ typedef enum { VERSION, KEY, TZ, + SOURCE, + AGENT, // Removed in vCard 4.0 + PROFILE, // Removed in vCard 4.0 // vCard 3.0 properties + // https://tools.ietf.org/html/rfc2426 CATEGORIES, SORT_STRING, PRODID, NICKNAME, + NAME, // Removed in vCard 4.0 CLASS, // Removed in vCard 4.0 // rfc2739 properties FBURL, @@ -64,7 +72,7 @@ typedef enum { // rfc4770 properties IMPP, // vCard 4.0 properties - SOURCE, + // https://tools.ietf.org/html/rfc6350 XML, ANNIVERSARY, CLIENTPIDMAP, @@ -85,60 +93,26 @@ typedef enum { VCARD_PROPERTIES, } Property; -gchar* Proterties[VCARD_PROPERTIES+1] = { - "N", - "FN", - "PHOTO", - "BDAY", - "ADR", - "LABEL", - "TEL", - "EMAIL", - "MAILER", - "GEO", - "TITLE", - "ROLE", - "LOGO", - "ORG", - "NOTE", - "REV", - "SOUND", - "URL", - "UID", - "VERSION", - "KEY", - "TZ", - "CATEGORIES", - "SORT-STRING", - "PRODID", - "NICKNAME", - "CLASS", - "FBURL", - "CAPURI", - "CALURI", - "CALADRURI", - "IMPP", - "SOURCE", - "XML", - "ANNIVERSARY", - "CLIENTPIDMAP", - "LANG", - "GENDER", - "KIND", - "MEMBER", - "RELATED", - "BIRTHPLACE", - "DEATHPLACE", - "DEATHDATE", - "EXPERTISE", - "HOBBY", - "INTEREST", - "ORG-DIRECTORY", - NULL -}; +typedef enum { + VCARD_PARSER_OK, + VCARD_PARSER_VERSION_MISSING, + VCARD_PARSER_VERSION_MISMATCH, + VCARD_PARSER_ATTRIBUTE_VERSION_MISMATCH, + VCARD_PARSER_BAD_FORMAT, + VCARD_PARSER_ERROR, +} VCardParserResponse; -G_END_DECLS +typedef struct { + gchar* name; + gchar* value; +} VCardProperty; + +VCardVersion str_2_vcard_version(const gchar* version); +gchar* vcard_version_2_str(VCardVersion version); +Property vcard_max_property(VCardVersion version); +VCardParserResponse vcard_parse_text(const gchar* text, VCardVersion* version, GHashTable** vcard); +void destroy_hash_table(GHashTable* ht); -gboolean vcard_parse_text(); +G_END_DECLS #endif diff --git a/src/vcard.c b/src/vcard.c index 9a09cca..e9881f9 100644 --- a/src/vcard.c +++ b/src/vcard.c @@ -19,12 +19,247 @@ * MA 02110-1301, USA. */ -# include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif struct _VCard { - gchar *version; + VCardParserResponse state; + VCardVersion version; + GHashTable* vcard; }; -int main() { - return 0; +static char *replaceWord(const char *s, const char *oldW, const char *newW) { + char *result; + int i, cnt = 0; + int newWlen = strlen(newW); + int oldWlen = strlen(oldW); + + for (i = 0; s[i] != '\0'; i++) { + if (strstr(&s[i], oldW) == &s[i]) { + cnt++; + i += oldWlen - 1; + } + } + + result = (char *) malloc(i + cnt * (newWlen - oldWlen) + 1); + + i = 0; + while (*s) { + if (strstr(s, oldW) == s) { + strcpy(&result[i], newW); + i += newWlen; + s += oldWlen; + } + else + result[i++] = *s++; + } + + result[i] = '\0'; + return result; +} + +static void hash_table_cb(gpointer key, gpointer value, gpointer data) { + GSList* list = (GSList*) value; + gchar** str = (gchar**) data; + gchar* s = NULL; + + if (!list) return; + + while (list) { + VCardProperty* vp = (VCardProperty*) list->data; + gchar* s0 = replaceWord(vp->value, "\n", "\n "); + if (!*str) + s = g_strconcat(vp->name, ":", s0, NULL); + else { + s = g_strconcat(*str, "\n", vp->name, ":", s0, NULL); + g_free(*str); + } + g_free(s0); + *str = g_strdup(s); + g_free(s); + list = list->next; + } +} + +static gchar** make_chunks(const gchar* text) { + gchar** chunks = NULL; + gchar* v_text = g_strdup(text); + g_strstrip(v_text); + + gchar** tmp = g_strsplit(v_text, "END:VCARD", 0); + g_free(v_text); + guint lines = g_strv_length(tmp); + if (lines < 2) + return tmp; + + if (strlen(tmp[lines-1]) < 1) { + chunks = g_new0(gchar*, lines); + lines--; + } else + chunks = g_new0(gchar*, lines + 1); + + for(int i = 0; i < lines; i++) { + g_strchug(tmp[i]); + chunks[i] = g_strconcat(tmp[i], "END:VCARD", NULL); + } + g_strfreev(tmp); + + return chunks; +} + +void VCard_free(VCard* object) { + if (object == NULL) return; + + if (object->vcard) + destroy_hash_table(object->vcard); + g_free(object); +} + +void VCard_list_free(GSList* list) { + GSList* tmp = list; + + while(tmp) { + VCard* object = (VCard*) tmp->data; + VCard_free(object); + tmp = tmp->next; + } + + if(list) + g_slist_free(list); +} + +/* +VCard* VCard_new(VCardVersion version) { + VCard* vc = g_new0(VCard, 1); + vc->version = version; + + return vc; +} +*/ + +GSList* VCard_new_from_text(const gchar* text, VCardVersion version, gboolean skip_broken) { + GSList* list = NULL; + VCard* vc = NULL; + + if (!text || strlen(text) < 1) return NULL; + + gchar** chunks = make_chunks(text); + for (int i = 0; i < g_strv_length(chunks); i++) { + vc = g_new0(VCard, 1); + vc->version = version; + + VCardParserResponse r = vcard_parse_text(chunks[i], &vc->version, &vc->vcard); + if (r != VCARD_PARSER_OK && skip_broken) { + VCard_free(vc); + continue; + } + vc->state = r; + list = g_slist_prepend(list, vc); + } + g_strfreev(chunks); + + return list; +} + +GSList* VCard_new_from_file(FILE* file, VCardVersion version, gboolean skip_broken) { + GSList* list = NULL; + VCard* vc = g_new0(VCard, 1); + + vc->version = version; + list = g_slist_prepend(list, vc); + + return list; +} + +void VCard_print_list(GSList* list) { + VCard_print_list_fd(list, STDOUT_FILENO); +} + +void VCard_print_list_fd(GSList* list, int fd) { + GSList* tmp = list; + if (fd > 0) { + while(tmp) { + VCard* object = (VCard*) tmp->data; + VCard_print_fd(object, fd); + if (tmp->next) { + ssize_t len = strlen("\n"); + if (write(fd, "\n", len) < len) + g_warning(strerror(errno)); + } + tmp = tmp->next; + } + } +} + +void VCard_print(VCard* object){ + VCard_print_fd(object, STDOUT_FILENO); +} + +void VCard_print_fd(VCard* object, int fd) { + gchar *body = NULL, *s = NULL; + + if (object && object->vcard && fd > 0) { + gchar* version = vcard_version_2_str(object->version); + s = g_strdup_printf("BEGIN:VCARD\nVERSION:%s", version); + g_free(version); + g_hash_table_foreach(object->vcard, hash_table_cb, &s); + body = g_strdup_printf("%s\nEND:VCARD", s); + g_free(s); + ssize_t len = strlen(body); + if (write(fd, body, len) < len) + g_warning(strerror(errno)); + g_free(body); + } +} + +gchar* VCard_get_state(VCard* object) { + gchar* message = NULL; + + if (!object) return NULL; + + switch (object->state) { + case VCARD_PARSER_OK: + message = g_strdup("OK"); + break; + case VCARD_PARSER_VERSION_MISMATCH: + message = g_strdup("Version mismatch"); + break; + case VCARD_PARSER_ATTRIBUTE_VERSION_MISMATCH: + message = g_strdup("Attribute not supported in this version"); + break; + case VCARD_PARSER_BAD_FORMAT: + message = g_strdup("Bad input format"); + break; + case VCARD_PARSER_ERROR: + message = g_strdup("Unknown error"); + break; + default: + message = g_strdup("Unhandled error"); + break; + } + + return message; +} + +GSList* VCard_get_property(VCard* object, const gchar* property) { + GSList *values = NULL, *tmp; + GSList *iter; + VCardProperty* vp = NULL; + + if (object && object->vcard && property) { + tmp = g_hash_table_lookup(object->vcard, property); + for (iter = tmp; iter; iter = g_slist_next(iter)) { + vp = (VCardProperty*) iter->data; + values = g_slist_prepend(values, g_strdup_printf("%s:%s", vp->name, vp->value)); + } + } + + return values; } diff --git a/src/vcard.h b/src/vcard.h index 12bbd76..b523527 100644 --- a/src/vcard.h +++ b/src/vcard.h @@ -19,30 +19,28 @@ * MA 02110-1301, USA. */ -#ifndef __VCARD_PARSER_H__ -#define __VCARD_PARSER_H__ +#ifndef __VCARD_H__ +#define __VCARD_H__ #include G_BEGIN_DECLS #include -#include +#include -typedef enum { - DETECT, - VERSION_2_1, - VERSION_3_0, - VERSION_4_0, -} VCardVersion; +//VCard* VCard_new(VCardVersion version); +GSList* VCard_new_from_text(const gchar* text, VCardVersion version, gboolean skip_broken); +GSList* VCard_new_from_file(FILE* file, VCardVersion version, gboolean skip_broken); +void VCard_free(VCard* object); +void VCard_list_free(GSList* list); -typedef struct _VCard VCard; - -VCard* VCard_new(VCardVersion version); -VCard* VCard_new_from_text(const gchar* text, VCardVersion version); -VCard* VCard_new_from_file(FILE* file, VCardVersion version); +void VCard_print_list(GSList* list); +void VCard_print_list_fd(GSList* list, int fd); void VCard_print(VCard* object); void VCard_print_fd(VCard* object, int fd); +gchar* VCard_get_state(VCard* object); +GSList* VCard_get_property(VCard* object, const gchar* property); G_END_DECLS