diff options
Diffstat (limited to 'e-util/ename/e-address-western.c')
-rw-r--r-- | e-util/ename/e-address-western.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/e-util/ename/e-address-western.c b/e-util/ename/e-address-western.c new file mode 100644 index 0000000000..d4dcda995e --- /dev/null +++ b/e-util/ename/e-address-western.c @@ -0,0 +1,372 @@ +/* -------------------------------------------------- + + An address parser, yielding fields as per RFC 2426. + + Author: + Jesse Pavel (jpavel@helixcode.com) + + Copyright 2000, Helix Code, Inc. + -------------------------------------------------- +*/ + +#include <ctype.h> +#include <string.h> +#include <glib.h> + +#include <ename/e-address-western.h> + + +static gboolean +e_address_western_is_line_blank (gchar *line) +{ + gboolean blank = TRUE; + gint cntr; + + /* A blank line consists of whitespace only, or a NULL line. */ + for (cntr = 0; line[cntr] != '\0'; cntr++ ) { + if (!isspace(line[cntr])) { + blank = FALSE; + break; + } + } + + return blank; +} + + + +/* In the array of lines, `lines', we will erase the line at line_num, and + shift the remaining lines, up to line number num_lines, up one position. */ + +void +e_address_western_shift_line (gchar *lines[], gint line_num, gint num_lines) +{ + gint cntr; + + if (line_num >= (num_lines - 1)) { + /* It is the last line, so simply shift in a NULL. */ + lines[line_num] = NULL; + } + else { + for (cntr = line_num; cntr < num_lines; cntr++) + lines[cntr] = lines[cntr + 1]; + } +} + + +static void +e_address_western_remove_blank_lines (gchar *lines[], gint *linecntr) +{ + gint cntr; + + for (cntr = 0; cntr < *linecntr; cntr++) { + if (e_address_western_is_line_blank (lines[cntr])) { + /* Delete the blank line, and shift all subsequent lines up + one spot to fill its old spot. */ + e_address_western_shift_line (lines, cntr, *linecntr); + + /* Since we must check the newly shifted line, let's + not advance the counter on this next pass. */ + cntr--; + + /* There is now one less line, total. */ + *linecntr -= 1; + } + } +} + + +gboolean +e_address_western_is_po_box (gchar *line) +{ + gboolean retval; + + /* In which phase of processing are we? */ + enum State { FIRSTCHAR, SECONDCHAR, WHITESPACE } state; + + + /* If the first two letters of the line are `p' and `o', and these + are in turn followed by whitespace before another letter, then I + will deem the line a representation of a PO Box address. */ + + gint cntr; + + state = FIRSTCHAR; + for (cntr = 0; line[cntr] != '\0'; cntr++) { + if (state == FIRSTCHAR) { + if (isalnum(line[cntr])) { + if (tolower(line[cntr]) == 'p') + state = SECONDCHAR; + else { + retval = FALSE; + break; + } + } + } + else if (state == SECONDCHAR) { + if (isalnum (line[cntr])) { + if (tolower(line[cntr]) == 'o') + state = WHITESPACE; + else { + retval = FALSE; + break; + } + } + } + else if (state == WHITESPACE) { + if (isspace (line[cntr])) { + retval = TRUE; + break; + } + else if (isalnum (line[cntr])) { + retval = FALSE; + break; + } + } + } + + return retval; +} + +/* A line that contains a comma followed eventually by a number is + deemed to be the line in the form of <town, region postal-code>. */ + +gboolean +e_address_western_is_postal (gchar *line) +{ + gboolean retval; + int cntr; + + if (strchr (line, ',') == NULL) + retval = FALSE; /* No comma. */ + else { + int index; + + /* Ensure that the first character after the comma is + a letter. */ + index = strcspn (line, ","); + index++; + while (isspace(line[index])) + index++; + + if (!isalpha(line[index])) + return FALSE; /* FIXME: ugly control flow. */ + + cntr = strlen(line) - 1; + + /* Go to the character immediately following the last + whitespace character. */ + while (cntr >= 0 && isspace(line[cntr])) + cntr--; + + while (cntr >= 0 && !isspace(line[cntr])) + cntr--; + + if (cntr == 0) + retval = FALSE; + else { + if (isdigit (line[cntr+1])) + retval = TRUE; + else + retval = FALSE; + } + } + + return retval; +} + +gchar * +e_address_western_extract_po_box (gchar *line) +{ + return g_strdup (line); +} + +gchar * +e_address_western_extract_locality (gchar *line) +{ + gint index; + + /* Everything before the comma is the locality. */ + index = strcspn(line, ","); + + if (index == 0) + return NULL; + else + return g_strndup (line, index); +} + +gchar * +e_address_western_extract_region (gchar *line) +{ + gint start, end; + + start = strcspn (line, ","); + start++; + while (isspace(line[start])) + start++; + + end = start; + while (!isspace (line[end])) + end++; + + /* Between start and end lie the string. */ + return g_strndup ( (line+start), end-start); +} + +gchar * +e_address_western_extract_postal_code (gchar *line) +{ + int start, end; + + end = strlen (line) - 1; + while (isspace(line[end])) + end--; + + start = end; + end++; + + while (!isspace(line[start])) + start--; + start++; + + /* Between start and end lie the string. */ + return g_strndup ( (line+start), end-start); +} + +EAddressWestern * +e_address_western_parse (const gchar *in_address) +{ + gchar **lines; + gint linecntr, lineindex; + gchar *address; + gint cntr; + gboolean found_po_box, found_postal; + + EAddressWestern *eaw; + gint start, end; /* To be used to classify address lines. */ + + if (in_address == NULL) + return NULL; + + eaw = (EAddressWestern *)g_malloc (sizeof(EAddressWestern)); + eaw->po_box = NULL; + eaw->extended = NULL; + eaw->street = NULL; + eaw->locality = NULL; + eaw->region = NULL; + eaw->postal_code = NULL; + eaw->country = NULL; + + address = g_strdup (in_address); + + /* The first thing I'll do is divide the multiline input string + into lines. */ + + /* ... count the lines. */ + linecntr = 1; + lineindex = 0; + while (address[lineindex] != '\0') { + if (address[lineindex] == '\n') + linecntr++; + + lineindex++; + } + + /* ... tally them. */ + lines = (gchar **)g_malloc (sizeof(gchar *) * (linecntr+3)); + lineindex = 0; + lines[0] = &address[0]; + linecntr = 1; + while (address[lineindex] != '\0') { + if (address[lineindex] == '\n') { + lines[linecntr] = &address[lineindex + 1]; + linecntr++; + } + + lineindex++; + } + + /* Convert the newlines at the end of each line (except the last, + because it is already NULL terminated) to NULLs. */ + for (cntr = 0; cntr < (linecntr - 1); cntr++) { + *(strchr (lines[cntr], '\n')) = '\0'; + } + + e_address_western_remove_blank_lines (lines, &linecntr); + + /* Let's just test these functions. */ + found_po_box = FALSE; + found_postal = FALSE; + + for (cntr = 0; cntr < linecntr; cntr++) { + if (e_address_western_is_po_box (lines[cntr])) { + eaw->po_box = e_address_western_extract_po_box (lines[cntr]); + found_po_box = TRUE; + } + else if (e_address_western_is_postal (lines[cntr])) { + eaw->locality = e_address_western_extract_locality (lines[cntr]); + eaw->region = e_address_western_extract_region (lines[cntr]); + eaw->postal_code = e_address_western_extract_postal_code (lines[cntr]); + found_postal = TRUE; + } + else { + if (found_postal) { + if (eaw->country == NULL) + eaw->country = g_strdup (lines[cntr]); + else { + gchar *temp; + temp = g_strconcat (eaw->country, "\n", lines[cntr]); + g_free (eaw->country); + eaw->country = temp; + } + } + else { + if (eaw->street == NULL) { + eaw->street = g_strdup (lines[cntr]); + } + else { + if (eaw->extended == NULL) { + eaw->extended = g_strdup (lines[cntr]); + } + else { + gchar *temp; + temp = g_strconcat (eaw->extended, "\n", lines[cntr]); + g_free (eaw->extended); + eaw->extended = temp; + } + } + } + } + } + + g_free (lines); + g_free (address); + + return eaw; +} + + +void +e_address_western_free (EAddressWestern *eaw) +{ + if (eaw == NULL) + return; + + if (eaw->po_box != NULL) + g_free(eaw->po_box); + if (eaw->extended != NULL) + g_free(eaw->extended); + if (eaw->street != NULL) + g_free(eaw->street); + if (eaw->locality != NULL) + g_free(eaw->locality); + if (eaw->region != NULL) + g_free(eaw->region); + if (eaw->postal_code != NULL) + g_free(eaw->postal_code); + if (eaw->country != NULL) + g_free(eaw->country); + + g_free (eaw); +} + |