Blame telepathy-account-widgets/tp-account-widgets/tpaw-string-parser.c

Packit 79f644
/*
Packit 79f644
 * Copyright (C) 2010 Collabora Ltd.
Packit 79f644
 *
Packit 79f644
 * This library is free software; you can redistribute it and/or
Packit 79f644
 * modify it under the terms of the GNU Lesser General Public
Packit 79f644
 * License as published by the Free Software Foundation; either
Packit 79f644
 * version 2.1 of the License, or (at your option) any later version.
Packit 79f644
 *
Packit 79f644
 * This library is distributed in the hope that it will be useful,
Packit 79f644
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 79f644
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 79f644
 * Lesser General Public License for more details.
Packit 79f644
 *
Packit 79f644
 * You should have received a copy of the GNU Lesser General Public
Packit 79f644
 * License along with this library; if not, write to the Free Software
Packit 79f644
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 79f644
 *
Packit 79f644
 * Authors: Xavier Claessens <xclaesse@gmail.com>
Packit 79f644
 */
Packit 79f644
Packit 79f644
#include "config.h"
Packit 79f644
#include "tpaw-string-parser.h"
Packit 79f644
Packit 79f644
#include <string.h>
Packit 79f644
Packit 79f644
#include "tpaw-utils.h"
Packit 79f644
Packit 79f644
#define SCHEMES           "([a-zA-Z\\+]+)"
Packit 79f644
#define INVALID_CHARS     "\\s\"<>"
Packit 79f644
#define INVALID_CHARS_EXT INVALID_CHARS "\\[\\](){},;:"
Packit 79f644
#define INVALID_CHARS_FULL INVALID_CHARS_EXT "?'"
Packit 79f644
#define BODY              "([^"INVALID_CHARS_FULL"])([^"INVALID_CHARS_EXT"]*)"
Packit 79f644
#define BODY_END          "([^"INVALID_CHARS"]*)[^"INVALID_CHARS_FULL".]"
Packit 79f644
#define URI_REGEX         "("SCHEMES"://"BODY_END")" \
Packit 79f644
                          "|((www|ftp)\\."BODY_END")" \
Packit 79f644
                          "|((mailto:)?"BODY"@"BODY"\\."BODY_END")"
Packit 79f644
Packit 79f644
static GRegex *
Packit 79f644
uri_regex_dup_singleton (void)
Packit 79f644
{
Packit 79f644
  static GRegex *uri_regex = NULL;
Packit 79f644
Packit 79f644
  /* We intentionally leak the regex so it's not recomputed */
Packit 79f644
  if (!uri_regex)
Packit 79f644
    {
Packit 79f644
      GError *error = NULL;
Packit 79f644
Packit 79f644
      uri_regex = g_regex_new (URI_REGEX, 0, 0, &error);
Packit 79f644
      if (uri_regex == NULL)
Packit 79f644
        {
Packit 79f644
          g_warning ("Failed to create reg exp: %s", error->message);
Packit 79f644
          g_error_free (error);
Packit 79f644
          return NULL;
Packit 79f644
        }
Packit 79f644
    }
Packit 79f644
Packit 79f644
  return g_regex_ref (uri_regex);
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
tpaw_string_parser_substr (const gchar *text,
Packit 79f644
    gssize len,
Packit 79f644
    TpawStringParser *parsers,
Packit 79f644
    gpointer user_data)
Packit 79f644
{
Packit 79f644
  if (parsers != NULL && parsers[0].match_func != NULL)
Packit 79f644
    {
Packit 79f644
      parsers[0].match_func (text, len,
Packit 79f644
          parsers[0].replace_func, parsers + 1,
Packit 79f644
          user_data);
Packit 79f644
    }
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
tpaw_string_match_link (const gchar *text,
Packit 79f644
    gssize len,
Packit 79f644
    TpawStringReplace replace_func,
Packit 79f644
    TpawStringParser *sub_parsers,
Packit 79f644
    gpointer user_data)
Packit 79f644
{
Packit 79f644
  GRegex *uri_regex;
Packit 79f644
  GMatchInfo *match_info;
Packit 79f644
  gboolean match;
Packit 79f644
  gint last = 0;
Packit 79f644
Packit 79f644
  uri_regex = uri_regex_dup_singleton ();
Packit 79f644
  if (uri_regex == NULL)
Packit 79f644
    {
Packit 79f644
      tpaw_string_parser_substr (text, len, sub_parsers, user_data);
Packit 79f644
      return;
Packit 79f644
    }
Packit 79f644
Packit 79f644
  match = g_regex_match_full (uri_regex, text, len, 0, 0, &match_info, NULL);
Packit 79f644
  if (match)
Packit 79f644
    {
Packit 79f644
      gint s = 0, e = 0;
Packit 79f644
Packit 79f644
      do
Packit 79f644
        {
Packit 79f644
          g_match_info_fetch_pos (match_info, 0, &s, &e);
Packit 79f644
Packit 79f644
          if (s > last)
Packit 79f644
            {
Packit 79f644
              /* Append the text between last link (or the
Packit 79f644
               * start of the message) and this link */
Packit 79f644
              tpaw_string_parser_substr (text + last,
Packit 79f644
                  s - last,
Packit 79f644
                  sub_parsers,
Packit 79f644
                  user_data);
Packit 79f644
            }
Packit 79f644
Packit 79f644
          replace_func (text + s, e - s, NULL, user_data);
Packit 79f644
Packit 79f644
          last = e;
Packit 79f644
        } while (g_match_info_next (match_info, NULL));
Packit 79f644
    }
Packit 79f644
Packit 79f644
  tpaw_string_parser_substr (text + last, len - last, sub_parsers, user_data);
Packit 79f644
Packit 79f644
  g_match_info_free (match_info);
Packit 79f644
  g_regex_unref (uri_regex);
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
tpaw_string_match_all (const gchar *text,
Packit 79f644
    gssize len,
Packit 79f644
    TpawStringReplace replace_func,
Packit 79f644
    TpawStringParser *sub_parsers,
Packit 79f644
    gpointer user_data)
Packit 79f644
{
Packit 79f644
  replace_func (text, len, NULL, user_data);
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
tpaw_string_replace_link (const gchar *text,
Packit 79f644
    gssize len,
Packit 79f644
    gpointer match_data,
Packit 79f644
    gpointer user_data)
Packit 79f644
{
Packit 79f644
  GString *string = user_data;
Packit 79f644
  gchar *real_url;
Packit 79f644
  gchar *title;
Packit 79f644
  gchar *markup;
Packit 79f644
Packit 79f644
  real_url = tpaw_make_absolute_url_len (text, len);
Packit 79f644
Packit 79f644
  /* Need to copy manually, because g_markup_printf_escaped does not work
Packit 79f644
   * with string precision pitfalls. */
Packit 79f644
  title = g_strndup (text, len);
Packit 79f644
Packit 79f644
  /* Append the link inside  tag */
Packit 79f644
  markup = g_markup_printf_escaped ("%s", real_url, title);
Packit 79f644
Packit 79f644
  g_string_append (string, markup);
Packit 79f644
Packit 79f644
  g_free (real_url);
Packit 79f644
  g_free (title);
Packit 79f644
  g_free (markup);
Packit 79f644
}
Packit 79f644
Packit 79f644
void
Packit 79f644
tpaw_string_replace_escaped (const gchar *text,
Packit 79f644
    gssize len,
Packit 79f644
    gpointer match_data,
Packit 79f644
    gpointer user_data)
Packit 79f644
{
Packit 79f644
  GString *string = user_data;
Packit 79f644
  gchar *escaped;
Packit 79f644
  guint i;
Packit 79f644
  gsize escaped_len, old_len;
Packit 79f644
Packit 79f644
  escaped = g_markup_escape_text (text, len);
Packit 79f644
  escaped_len = strlen (escaped);
Packit 79f644
Packit 79f644
  /* Allocate more space to string (we really need a g_string_extend...) */
Packit 79f644
  old_len = string->len;
Packit 79f644
  g_string_set_size (string, old_len + escaped_len);
Packit 79f644
  g_string_truncate (string, old_len);
Packit 79f644
Packit 79f644
  /* Remove '\r' */
Packit 79f644
  for (i = 0; i < escaped_len; i++)
Packit 79f644
    {
Packit 79f644
      if (escaped[i] != '\r')
Packit 79f644
        g_string_append_c (string, escaped[i]);
Packit 79f644
    }
Packit 79f644
Packit 79f644
  g_free (escaped);
Packit 79f644
}
Packit 79f644
Packit 79f644
gchar *
Packit 79f644
tpaw_add_link_markup (const gchar *text)
Packit 79f644
{
Packit 79f644
  TpawStringParser parsers[] = {
Packit 79f644
        {tpaw_string_match_link, tpaw_string_replace_link},
Packit 79f644
        {tpaw_string_match_all, tpaw_string_replace_escaped},
Packit 79f644
        {NULL, NULL}};
Packit 79f644
  GString *string;
Packit 79f644
Packit 79f644
  g_return_val_if_fail (text != NULL, NULL);
Packit 79f644
Packit 79f644
  string = g_string_sized_new (strlen (text));
Packit 79f644
  tpaw_string_parser_substr (text, -1, parsers, string);
Packit 79f644
Packit 79f644
  return g_string_free (string, FALSE);
Packit 79f644
}