Example #1
0
static gboolean is_word_sep(gunichar c)
{
	return (g_unichar_isspace(c) || g_unichar_ispunct(c)) && c != (gunichar)'\'';
}
Example #2
0
static int
str_utf8_isspace (const char *text)
{
    gunichar uni = g_utf8_get_char_validated (text, -1);
    return g_unichar_isspace (uni);
}
Example #3
0
static gboolean
flags_from_string (GType        type,
                   const gchar *string,
                   gint        *flags_value)
{
  GFlagsClass *fclass;
  gchar *endptr, *prevptr;
  guint i, j, ret, value;
  gchar *flagstr;
  GFlagsValue *fv;
  const gchar *flag;
  gunichar ch;
  gboolean eos;

  g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
  g_return_val_if_fail (string != 0, 0);

  ret = TRUE;

  value = strtoul (string, &endptr, 0);
  if (endptr != string) /* parsed a number */
    *flags_value = value;
  else
    {
      fclass = g_type_class_ref (type);

      flagstr = g_strdup (string);
      for (value = i = j = 0; ; i++)
	{
	  eos = flagstr[i] == '\0';

	  if (!eos && flagstr[i] != '|')
	    continue;

	  flag = &flagstr[j];
	  endptr = &flagstr[i];

	  if (!eos)
	    {
	      flagstr[i++] = '\0';
	      j = i;
	    }

	  /* trim spaces */
	  for (;;)
	    {
	      ch = g_utf8_get_char (flag);
	      if (!g_unichar_isspace (ch))
		break;
	      flag = g_utf8_next_char (flag);
	    }

	  while (endptr > flag)
	    {
	      prevptr = g_utf8_prev_char (endptr);
	      ch = g_utf8_get_char (prevptr);
	      if (!g_unichar_isspace (ch))
		break;
	      endptr = prevptr;
	    }

	  if (endptr > flag)
	    {
	      *endptr = '\0';
	      fv = g_flags_get_value_by_name (fclass, flag);

	      if (!fv)
		fv = g_flags_get_value_by_nick (fclass, flag);

	      if (fv)
		value |= fv->value;
	      else
		{
		  ret = FALSE;
		  break;
		}
	    }

	  if (eos)
	    {
	      *flags_value = value;
	      break;
	    }
	}

      g_free (flagstr);

      g_type_class_unref (fclass);
    }

  return ret;
}
static ParseResult
gimp_number_pair_entry_parse_text (GimpNumberPairEntry *entry,
                                   const gchar         *text,
                                   gdouble             *left_value,
                                   gdouble             *right_value)
{
  GimpNumberPairEntryPrivate *priv = GIMP_NUMBER_PAIR_ENTRY_GET_PRIVATE (entry);

  gdouble   new_left_number;
  gdouble   new_right_number;
  gboolean  simplify = FALSE;
  gchar    *end;

  /* try to parse a number */
  new_left_number = strtod (text, &end);

  if (end == text)
    return PARSE_CLEAR;
  else
    text = end;

  /* skip over whitespace */
  while (g_unichar_isspace (g_utf8_get_char (text)))
    text = g_utf8_next_char (text);

  /* check for a valid separator */
  if (! gimp_number_pair_entry_valid_separator (entry, g_utf8_get_char (text)))
    return PARSE_INVALID;
  else
    text = g_utf8_next_char (text);

  /* try to parse another number */
  new_right_number = strtod (text, &end);

  if (end == text)
    return PARSE_INVALID;
  else
    text = end;

  /* skip over whitespace */
  while (g_unichar_isspace (g_utf8_get_char (text)))
    text = g_utf8_next_char (text);

  /* check for the simplification char */
  if (g_utf8_get_char (text) == SIMPLIFICATION_CHAR)
    {
      simplify = priv->allow_simplification;
      text = g_utf8_next_char (text);
    }

  /* skip over whitespace */
  while (g_unichar_isspace (g_utf8_get_char (text)))
    text = g_utf8_next_char (text);

  /* check for trailing garbage */
  if (*text)
    return PARSE_INVALID;

  if (! gimp_number_pair_entry_numbers_in_range (entry,
                                                 new_left_number,
                                                 new_right_number))
    return PARSE_INVALID;

  if (simplify && new_right_number != 0.0)
    {
      gimp_number_pair_entry_ratio_to_fraction (new_left_number /
                                                new_right_number,
                                                left_value,
                                                right_value);
    }
  else
    {
      *left_value = new_left_number;
      *right_value = new_right_number;
    }

  return PARSE_VALID;
}
Example #5
0
gint
donna_strcmp (const gchar *s1, const gchar *s2, DonnaSortOptions options)
{
    gboolean is_string = TRUE;
    gint     res_fb = 0; /* fallback */
    gint     res_cs = 0; /* case-sensitive */
    gint     res = 0;

    /* if at least one string if NULL or empty, we have a result */
    if (!s1 || *s1 == '\0')
    {
        if (s2 && *s2 != '\0')
            return -1;
        else
            return 0;
    }
    else if (!s2 || *s2 == '\0')
        return 1;

    if (options & DONNA_SORT_DOT_FIRST)
    {
        if (*s1 == '.')
        {
            if (*s2 != '.')
                /* only s1 is dotted, it comes first */
                return -1;
            else
            {
                /* both are dotted, skip the dot */
                ++s1;
                ++s2;
            }
        }
        else if (*s2 == '.')
            /* only s2 is dotted, it comes first */
            return 1;
    }
    else if (options & DONNA_SORT_DOT_MIXED)
    {
        if (*s1 == '.')
            ++s1;
        if (*s2 == '.')
            ++s2;
    }

    for (;;)
    {
        gunichar c1, c2;

        /* is at least one string over? */
        if (!*s1)
        {
            if (!*s2)
                res = 0;
            else
                /* shorter first */
                res = -1;
            goto done;
        }
        else if (!*s2)
        {
            /* shorter first */
            res = 1;
            goto done;
        }

        c1 = g_utf8_get_char (s1);
        c2 = g_utf8_get_char (s2);

        if (is_string)
        {
            if (options & DONNA_SORT_IGNORE_SPUNCT)
            {
                while (g_unichar_isspace (c1) || g_unichar_ispunct (c1))
                {
                    s1 = g_utf8_next_char (s1);
                    c1 = (*s1) ? g_utf8_get_char (s1) : 0;
                }
                while (g_unichar_isspace (c2) || g_unichar_ispunct (c2))
                {
                    s2 = g_utf8_next_char (s2);
                    c2 = (*s2) ? g_utf8_get_char (s2) : 0;
                }
                /* did we reached the end of a string? */
                if (!*s1 || !*s2)
                    continue;
            }

            /* is at least one string a number? */
            if (g_unichar_isdigit (c1))
            {
                if (g_unichar_isdigit (c2))
                {
                    if (options & DONNA_SORT_NATURAL_ORDER)
                    {
                        /* switch to number comparison */
                        is_string = FALSE;
                        continue;
                    }
                }
                else
                {
                    /* number first */
                    res = -1;
                    goto done;
                }
            }
            else if (g_unichar_isdigit (c2))
            {
                /* number first */
                res = 1;
                goto done;
            }

            /* compare chars */
            if (c1 > c2)
                res_cs = 1;
            else if (c1 < c2)
                res_cs = -1;

            if (options & DONNA_SORT_CASE_INSENSITIVE)
            {
                /* compare uppper chars */
                c1 = g_unichar_toupper (c1);
                c2 = g_unichar_toupper (c2);

                if (c1 > c2)
                {
                    res = 1;
                    goto done;
                }
                else if (c1 < c2)
                {
                    res = -1;
                    goto done;
                }
                else if (res_fb == 0)
                    /* set the case-sensitive result in case strings end up
                     * being the same otherwise */
                    res_fb = res_cs;
            }
            /* do we have a res_cs yet? */
            else if (res_cs != 0)
            {
                res = res_cs;
                goto done;
            }

            /* next chars */
            s1 = g_utf8_next_char (s1);
            s2 = g_utf8_next_char (s2);
        }
        /* mode number */
        else
        {
            unsigned long n1, n2;

            if (res_fb == 0)
            {
                /* count number of leading zeros */
                for (n1 = 0; *s1 == '0'; ++n1, ++s1)
                    ;
                for (n2 = 0; *s2 == '0'; ++n2, ++s2)
                    ;
                /* try to set a fallback to put less leading zeros first */
                if (n1 > n2)
                    res_fb = 1;
                else if (n1 < n2)
                    res_fb = -1;

                if (n1 > 0)
                    c1 = g_utf8_get_char (s1);
                if (n2 > 0)
                    c2 = g_utf8_get_char (s2);
            }

            n1 = 0;
            while (g_unichar_isdigit (c1))
            {
                int d;

                d = g_unichar_digit_value (c1);
                n1 *= 10;
                n1 += (unsigned long) d;
                s1 = g_utf8_next_char (s1);
                if (*s1)
                    c1 = g_utf8_get_char (s1);
                else
                    break;
            }

            n2 = 0;
            while (g_unichar_isdigit (c2))
            {
                int d;

                d = g_unichar_digit_value (c2);
                n2 *= 10;
                n2 += (unsigned long) d;
                s2 = g_utf8_next_char (s2);
                if (*s2)
                    c2 = g_utf8_get_char (s2);
                else
                    break;
            }

            if (n1 > n2)
            {
                res = 1;
                goto done;
            }
            else if (n1 < n2)
            {
                res = -1;
                goto done;
            }

            /* back to string comparison */
            is_string = TRUE;
        }
    }

done:
    return (res != 0) ? res : res_fb;
}
/* searhces for match inside value, if match is mixed case, hten use case-sensitive,
   else insensitive */
gboolean
camel_search_header_match (const gchar *value, const gchar *match, camel_search_match_t how, camel_search_t type, const gchar *default_charset)
{
	const gchar *name, *addr;
	const guchar *ptr;
	gint truth = FALSE, i;
	CamelInternetAddress *cia;
	gchar *v, *vdom, *mdom;
	gunichar c;

	ptr = (const guchar *)value;
	while ((c = camel_utf8_getc (&ptr)) && g_unichar_isspace (c))
		value = (const gchar *)ptr;

	switch (type) {
	case CAMEL_SEARCH_TYPE_ENCODED:
		v = camel_header_decode_string (value, default_charset); /* FIXME: Find header charset */
		truth = header_match (v, match, how);
		g_free (v);
		break;
	case CAMEL_SEARCH_TYPE_MLIST:
		/* Special mailing list old-version domain hack
		   If one of the mailing list names doesn't have an @ in it, its old-style, so
		   only match against the pre-domain part, which should be common */

		vdom = strchr (value, '@');
		mdom = strchr (match, '@');
		if (mdom == NULL && vdom != NULL) {
			v = g_alloca (vdom-value+1);
			memcpy (v, value, vdom-value);
			v[vdom-value] = 0;
			value = (gchar *)v;
		} else if (mdom != NULL && vdom == NULL) {
			v = g_alloca (mdom-match+1);
			memcpy (v, match, mdom-match);
			v[mdom-match] = 0;
			match = (gchar *)v;
		}
		/* Falls through */
	case CAMEL_SEARCH_TYPE_ASIS:
		truth = header_match (value, match, how);
		break;
	case CAMEL_SEARCH_TYPE_ADDRESS_ENCODED:
	case CAMEL_SEARCH_TYPE_ADDRESS:
		/* possible simple case to save some work if we can */
		if (header_match (value, match, how))
			return TRUE;

		/* Now we decode any addresses, and try asis matches on name and address parts */
		cia = camel_internet_address_new ();
		if (type == CAMEL_SEARCH_TYPE_ADDRESS_ENCODED)
			camel_address_decode ((CamelAddress *)cia, value);
		else
			camel_address_unformat ((CamelAddress *)cia, value);

		for (i=0; !truth && camel_internet_address_get (cia, i, &name, &addr);i++)
			truth = (name && header_match (name, match, how)) || (addr && header_match (addr, match, how));

		g_object_unref (cia);
		break;
	}

	return truth;
}
Example #7
0
static inline gboolean is_space (gunichar ch)
{ return g_unichar_isspace (ch) || ch == 0xfffc; }
Example #8
0
/*
 * ui_readline_loop()
 *
 * g³ówna pêtla programu. wczytuje dane z klawiatury w miêdzyczasie
 * obs³uguj±c sieæ i takie tam.
 */
int ui_readline_loop(void)
{
	char *line = my_readline();
	char *rline = line; /* for freeing */
	gchar *out, *p;
	gint len;

	if (!line) {
		/* Ctrl-D handler */
		if (window_current->id == 0) {			/* debug window */
			window_switch(1);
		} else if (window_current->id == 1) {		/* status window */
			if (config_ctrld_quits)	{
				return 0;
			} else {
				printf("\n");
			}
		} else if (window_current->id > 1) {		/* query window */
			window_kill(window_current);
		}
		return 1;
	}

	len = strlen(line);
	if (G_LIKELY(len > 0)) {
		if (G_UNLIKELY(line[len - 1] == '\\')) {
			/* multi line handler */
			GString *s = g_string_new_len(line, len-1);
			
			free(line);

			no_prompt = 1;
			rl_bind_key(9, rl_insert);

			while ((line = my_readline())) {
				if (!strcmp(line, "."))
					break;
				g_string_append(s, line);
				g_string_append_len(s, "\r\n", 2); /* XXX */
				free(line);
			}

			rl_bind_key(9, rl_complete);
			no_prompt = 0;

			if (line) {
				g_string_free(s, TRUE);
				free(line);
				return 1;
			}

			line = g_string_free(s, FALSE);
		}
		
		/* if no empty line and we save duplicate lines, add it to history */
		if (config_history_savedups || !history_length || strcmp(line, history_get(history_length)->line))
			add_history(line);
	}

	pager_lines = 0;

	/* now we can definitely recode */
	out = ekg_recode_from_locale(line);
	if (G_LIKELY(line == rline))
		free(rline); /* allocd by readline */
	else
		g_free(line); /* allocd by us */

	/* omit leading whitespace */
	for (p = out; g_unichar_isspace(g_utf8_get_char(p)); p = g_utf8_next_char(p));
	if (*p || config_send_white_lines)
		command_exec(window_current->target, window_current->session, out, 0);

	pager_lines = -1;

	g_free(out);
	return 1;
}
Example #9
0
static void
e_name_western_reorder_asshole (ENameWestern *name,
                                ENameWesternIdxs *idxs)
{
	gchar *prefix;
	gchar *last;
	gchar *suffix;
	gchar *firstmidnick;
	gchar *newfull;

	gchar *comma;
	gchar *p;

	if (!e_name_western_detect_backwards (name, idxs))
		return;

	/*
	 * Convert
	 *    <Prefix> <Last name>, <First name> <Middle[+nick] name> <Suffix>
	 * to
	 *    <Prefix> <First name> <Middle[+nick] name> <Last name> <Suffix>
	 */

	/*
	 * Grab the prefix from the beginning.
	 */
	prefix = e_name_western_get_prefix_at_str (name->full);

	/*
	 * Everything from the end of the prefix to the comma is the
	 * last name.
	 */
	comma = g_utf8_strchr (name->full, -1, ',');
	if (comma == NULL) {
		g_free (prefix);
		return;
	}

	p = name->full + (prefix == NULL ? 0 : strlen (prefix));

	while (g_unichar_isspace (g_utf8_get_char (p)) && *p != '\0')
		p = g_utf8_next_char (p);

	/*
	 * Consider this case, "Br.Gate,Br. Gate,W". I know this is a damn
	 * random name, but, I got this from the bug report of 317411.
	 *
	 * comma = ",Br.Gate,W"
	 * prefix = "Br.Gate,Br."
	 * p = " Gate,W"
	 * comma - p < 0 and hence the crash.
	 *
	 * Actually, we don't have to put lot of intelligence in reordering such
	 * screwedup names, just return.
	 */
	if (comma - p + 1 < 1) {
		g_free (prefix);
		return;
	}

	last = g_malloc0 (comma - p + 1);
	strncpy (last, p, comma - p);

	/*
	 * Get the suffix off the end.
	 */
	suffix = e_name_western_get_suffix_at_str_end (name->full);

	/*
	 * Firstmidnick is everything from the comma to the beginning
	 * of the suffix.
	 */
	p = g_utf8_next_char (comma);

	while (g_unichar_isspace (g_utf8_get_char (p)) && *p != '\0')
		p = g_utf8_next_char (p);

	if (suffix != NULL) {
		gchar *q;

		/*
		 * Point q at the beginning of the suffix.
		 */
		q = name->full + strlen (name->full) - strlen (suffix);
		q = g_utf8_prev_char (q);

		/*
		 * Walk backwards until we hit the space which
		 * separates the suffix from firstmidnick.
		 */
		while (!g_unichar_isspace (g_utf8_get_char (q)) && q > comma)
			q = g_utf8_prev_char (q);

		if ((q - p + 1) > 0) {
			firstmidnick = g_malloc0 (q - p + 1);
			strncpy (firstmidnick, p, q - p);
		} else
			firstmidnick = NULL;
	} else {
		firstmidnick = g_strdup (p);
	}

	/*
	 * Create our new reordered version of the name.
	 */
#define NULLSTR(a) ((a) == NULL ? "" : (a))
	newfull = g_strdup_printf (
		"%s %s %s %s",
		NULLSTR (prefix),
		NULLSTR (firstmidnick),
		NULLSTR (last),
		NULLSTR (suffix));
	g_strstrip (newfull);
	g_free (name->full);
	name->full = newfull;

	g_free (prefix);
	g_free (firstmidnick);
	g_free (last);
	g_free (suffix);
}
Example #10
0
static void
e_name_western_fixup (ENameWestern *name,
                      ENameWesternIdxs *idxs)
{
	/*
	 * The middle and last names cannot be the same.
	 */
	if (idxs->middle_idx != -1 && idxs->middle_idx == idxs->last_idx) {
		idxs->middle_idx = -1;
		g_free (name->middle);
		name->middle = NULL;
	}

	/*
	 * If we have a middle name and no last name, then we mistook
	 * the last name for the middle name.
	 */
	if (idxs->last_idx == -1 && idxs->middle_idx != -1) {
		idxs->last_idx = idxs->middle_idx;
		name->last = name->middle;
		name->middle = NULL;
		idxs->middle_idx = -1;
	}

	/*
	 * Check to see if we accidentally included the suffix in the
	 * last name.
	 */
	if (idxs->suffix_idx != -1 && idxs->last_idx != -1 &&
	    idxs->suffix_idx < (idxs->last_idx + strlen (name->last))) {
		gchar *sfx;

		sfx = name->last + (idxs->suffix_idx - idxs->last_idx);
		if (sfx != NULL) {
			gchar *newlast;
			gchar *p;

			p = sfx;
			p = g_utf8_prev_char (p);
			while (g_unichar_isspace (g_utf8_get_char (p)) && p > name->last)
				p = g_utf8_prev_char (p);
			p = g_utf8_next_char (p);

			newlast = g_malloc0 (p - name->last + 1);
			strncpy (newlast, name->last, p - name->last);
			g_free (name->last);
			name->last = newlast;
		}
	}

	/*
	 * If we have a prefix and a first name, but no last name,
	 * then we need to assign the first name to the last name.
	 * This way we get things like "Mr Friedman" correctly.
	 */
	if (idxs->first_idx != -1 && idxs->prefix_idx != -1 &&
	    idxs->last_idx == -1) {
		name->last = name->first;
		idxs->last_idx = idxs->first_idx;
		idxs->first_idx = -1;
		name->first = NULL;
	}

	if (idxs->middle_idx != -1) {
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("&");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("*");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("|");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("^");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("&&");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("||");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("+");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("-");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("and");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("or");
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("plus");

		/* Spanish */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("y");

		/* German */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("und");

		/* Italian */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("e");

		/* Czech */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("a");

		/* Finnish */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("ja");

		/* French */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION_CASE ("et");

		/* Russian */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("\xd0\x98"); /* u+0418 */
		CHECK_MIDDLE_NAME_FOR_CONJUNCTION ("\xd0\xb8"); /* u+0438 */
	}

	/*
	 * Remove stray spaces and commas (although there don't seem
	 * to be any in the test cases, they might show up later).
	 */
	e_name_western_cleanup_string (& name->prefix);
	e_name_western_cleanup_string (& name->first);
	e_name_western_cleanup_string (& name->middle);
	e_name_western_cleanup_string (& name->nick);
	e_name_western_cleanup_string (& name->last);
	e_name_western_cleanup_string (& name->suffix);

	/*
	 * Make zero-length strings just NULL.
	 */
	e_name_western_zap_nil (& name->prefix, & idxs->prefix_idx);
	e_name_western_zap_nil (& name->first,  & idxs->first_idx);
	e_name_western_zap_nil (& name->middle, & idxs->middle_idx);
	e_name_western_zap_nil (& name->nick,   & idxs->nick_idx);
	e_name_western_zap_nil (& name->last,   & idxs->last_idx);
	e_name_western_zap_nil (& name->suffix, & idxs->suffix_idx);
}
Example #11
0
static void
e_name_western_extract_last (ENameWestern *name,
                             ENameWesternIdxs *idxs)
{
	gchar *word;
	gint   idx = -1;
	gchar *last;

	idx = e_name_western_last_get_max_idx (name, idxs);

	/*
	 * In the case where there is no preceding name element, the
	 * name is either just a first name ("Nat", "John"), is a
	 * single-element name ("Cher", which we treat as a first
	 * name), or is just a last name.  The only time we can
	 * differentiate a last name alone from a single-element name
	 * or a first name alone is if it's a complex last name ("de
	 * Icaza", "van Josephsen").  So if there is no preceding name
	 * element, we check to see whether or not the first part of
	 * the name is the beginning of a complex name.  If it is,
	 * we subsume the entire string.  If we accidentally subsume
	 * the suffix, this will get fixed in the fixup routine.
	 */
	if (idx == -1) {
		word = e_name_western_get_words_at_idx (name->full, 0, 1);
		if (!e_name_western_is_complex_last_beginning (word)) {
			g_free (word);
			return;
		}

		name->last = g_strdup (name->full);
		idxs->last_idx = 0;
		return;
	}

	last = name->full + idx;

	/* Skip past the white space. */
	while (g_unichar_isspace (g_utf8_get_char (last)) && *last != '\0')
		last = g_utf8_next_char (last);

	if (*last == '\0')
		return;

	word = e_name_western_get_words_at_idx (name->full, last - name->full, 1);
	e_name_western_cleanup_string (& word);
	if (e_name_western_word_is_suffix (word)) {
		g_free (word);
		return;
	}
	g_free (word);

	/*
	 * Subsume the rest of the string into the last name.  If we
	 * accidentally include the prefix, it will get fixed later.
	 * This is the only way to handle things like "Miguel de Icaza
	 * Amozorrutia" without dropping data and forcing the user
	 * to retype it.
	 */
	name->last = g_strdup (last);
	idxs->last_idx = last - name->full;
}
Example #12
0
static void
e_name_western_extract_middle (ENameWestern *name,
                               ENameWesternIdxs *idxs)
{
	gchar *word;
	gchar *middle;

	/*
	 * Middle names can only exist if you have a first name.
	 */
	if (idxs->first_idx == -1)
		return;

	middle = name->full + idxs->first_idx + strlen (name->first);
	if (*middle == '\0')
		return;

	middle = g_utf8_next_char (middle);
	if (*middle == '\0')
		return;

	/*
	 * Search for the first space (or the terminating \0)
	 */
	while (g_unichar_isspace (g_utf8_get_char (middle)) &&
	       *middle != '\0')
		middle = g_utf8_next_char (middle);

	if (*middle == '\0')
		return;

	/*
	 * Skip past the nickname, if it's there.
	 */
	if (*middle == '\"') {
		if (idxs->nick_idx == -1)
			return;

		middle = name->full + idxs->nick_idx + strlen (name->nick);
		middle = g_utf8_next_char (middle);

		while (g_unichar_isspace (g_utf8_get_char (middle)) &&
		       *middle != '\0')
			middle = g_utf8_next_char (middle);

		if (*middle == '\0')
			return;
	}

	/*
	 * Make sure this isn't the beginning of a complex last name.
	 */
	word = e_name_western_get_words_at_idx (name->full, middle - name->full, 1);
	if (e_name_western_is_complex_last_beginning (word)) {
		g_free (word);
		return;
	}

	/*
	 * Make sure this isn't a suffix.
	 */
	e_name_western_cleanup_string (& word);
	if (e_name_western_word_is_suffix (word)) {
		g_free (word);
		return;
	}

	/*
	 * Make sure we didn't just grab a cute nickname.
	 */
	if (word[0] == '\"') {
		g_free (word);
		return;
	}

	idxs->middle_idx = middle - name->full;
	name->middle = word;
}
Example #13
0
static StfParseCellRes
stf_parse_csv_cell (GString *text, Source_t *src, StfParseOptions_t *parseoptions)
{
	char const *cur;
	gboolean saw_sep = FALSE;

	g_return_val_if_fail (src != NULL, STF_CELL_ERROR);
	g_return_val_if_fail (parseoptions != NULL, STF_CELL_ERROR);

	cur = src->position;
	g_return_val_if_fail (cur != NULL, STF_CELL_ERROR);

	/* Skip whitespace, but stop at line terminators.  */
	while (1) {
		int term_len;

		if (*cur == 0) {
			src->position = cur;
			return STF_CELL_EOF;
		}

		term_len = compare_terminator (cur, parseoptions);
		if (term_len) {
			src->position = cur + term_len;
			return STF_CELL_EOL;
		}

		if ((parseoptions->trim_spaces & TRIM_TYPE_LEFT) == 0)
			break;

		if (stf_parse_csv_is_separator (cur, parseoptions->sep.chr,
						parseoptions->sep.str))
			break;

		if (!g_unichar_isspace (g_utf8_get_char (cur)))
			break;
		cur = g_utf8_next_char (cur);
	}

	if (g_utf8_get_char (cur) == parseoptions->stringindicator) {
		cur = g_utf8_next_char (cur);
		while (*cur) {
			gunichar uc = g_utf8_get_char (cur);
			cur = g_utf8_next_char (cur);

			if (uc == parseoptions->stringindicator) {
				if (parseoptions->indicator_2x_is_single &&
				    g_utf8_get_char (cur) == parseoptions->stringindicator)
					cur = g_utf8_next_char (cur);
				else {
					/* "field content"dropped-garbage,  */
					while (*cur && !compare_terminator (cur, parseoptions)) {
						char const *post = stf_parse_csv_is_separator
							(cur, parseoptions->sep.chr, parseoptions->sep.str);
						if (post) {
							cur = post;
							saw_sep = TRUE;
							break;
						}
						cur = g_utf8_next_char (cur);
					}
					break;
				}
			}

			g_string_append_unichar (text, uc);
		}

		/* We silently allow a missing terminating quote.  */
	} else {
		/* Unquoted field.  */

		while (*cur && !compare_terminator (cur, parseoptions)) {

			char const *post = stf_parse_csv_is_separator
				(cur, parseoptions->sep.chr, parseoptions->sep.str);
			if (post) {
				cur = post;
				saw_sep = TRUE;
				break;
			}

			g_string_append_unichar (text, g_utf8_get_char (cur));
			cur = g_utf8_next_char (cur);
		}

		if (parseoptions->trim_spaces & TRIM_TYPE_RIGHT) {
			while (text->len) {
				const char *last = g_utf8_prev_char (text->str + text->len);
				if (!g_unichar_isspace (g_utf8_get_char (last)))
					break;
				g_string_truncate (text, last - text->str);
			}
		}
	}

	src->position = cur;

	if (saw_sep && parseoptions->duplicates)
		stf_parse_eat_separators (src, parseoptions);

	return saw_sep ? STF_CELL_FIELD_SEP : STF_CELL_FIELD_NO_SEP;
}
Example #14
0
gboolean
gb_vim_execute (GtkSourceView  *source_view,
                const gchar    *line,
                GError        **error)
{
  GtkTextBuffer *buffer;
  g_autofree gchar *name_slice = NULL;
  const GbVimCommand *command;
  const gchar *command_name = line;
  const gchar *options;
  g_autofree gchar *all_options = NULL;
  gboolean result;

  g_return_val_if_fail (GTK_SOURCE_IS_VIEW (source_view), FALSE);
  g_return_val_if_fail (line, FALSE);

  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (source_view));

  if (!GTK_SOURCE_IS_BUFFER (buffer))
    {
      g_set_error (error,
                   GB_VIM_ERROR,
                   GB_VIM_ERROR_NOT_SOURCE_VIEW,
                   _("vim mode requires GtkSourceView"));
      return FALSE;
    }

  for (options = line; *options; options = g_utf8_next_char (options))
    {
      gunichar ch;

      ch = g_utf8_get_char (options);

      if (g_unichar_isspace (ch))
        break;
    }

  if (g_unichar_isspace (g_utf8_get_char (options)))
    {
      command_name = name_slice = g_strndup (line, options - line);
      options = g_utf8_next_char (options);
    }

  command = lookup_command (command_name);

  if (command == NULL)
    {
      if (looks_like_search_and_replace (line))
        return gb_vim_command_search (source_view, line, "", error);

      g_set_error (error,
                   GB_VIM_ERROR,
                   GB_VIM_ERROR_NOT_FOUND,
                   _("Not an editor command: %s"),
                   command_name);
      return FALSE;
    }

  if (command->options_sup)
    all_options = g_strconcat (options, " ", command->options_sup, NULL);
  else
    all_options = g_strdup (options);

  result = command->func (source_view, command_name, all_options, error);
  g_free (command->options_sup);

  return result;
}
/*!
    shape() processes the information encapsulated by GR_ShapingInfo
    si and stores results in GR_*RenderInfo* pri.

    If the contents of pri are NULL the function must create a new
    instance of GR_*RenderInfo of the appropriate type and store the
    pointer in pri; it also must store pointer to this graphics
    instance in pri->m_pGraphics.

    If ri indicates that the text is justified, appropriate processing
    needs to be done

    This function is tied closely together to a class derrived from
    GR_RenderInfo which may contain caches of various data that will
    speed subsequent calls to prepareToRenderChars() and renderChars()
*/
bool GR_Graphics::shape(GR_ShapingInfo & si, GR_RenderInfo *& pri)
{
	if(!si.m_pItem || si.m_pItem->getType() == GRScriptType_Void || !si.m_pFont)
		return false;

	if(!pri)
	{
		pri = new GR_XPRenderInfo(si.m_pItem->getType());
		UT_return_val_if_fail(pri, false);
		pri->m_pGraphics = this;
	}

	GR_XPRenderInfo * pRI = (GR_XPRenderInfo *)pri;

	const GR_Font *pFont = si.m_pFont;
	
	// make sure that the buffers are of sufficient size ...
	if(si.m_iLength > pRI->m_iBufferSize) //buffer too small, reallocate
	{
		delete[] pRI->m_pChars;
		delete[] pRI->m_pWidths;
			
		pRI->m_pChars = new UT_UCS4Char[si.m_iLength + 1];
		UT_return_val_if_fail(pRI->m_pChars, false);

		pRI->m_pWidths = new UT_sint32[si.m_iLength + 1];
		UT_return_val_if_fail(pRI->m_pWidths, false);

		pRI->m_iBufferSize = si.m_iLength + 1;
	}

	pRI->m_iLength = si.m_iLength;
	pRI->m_iTotalLength = si.m_iLength;
	pRI->m_eScriptType = si.m_pItem->getType();
	pRI->m_pItem = si.m_pItem;

	UT_UCS4Char glyph, current;
	UT_UCS4Char * dst_ptr = pRI->m_pChars;
	bool previousWasSpace = si.m_previousWasSpace;

	for(UT_sint32 i = 0; i < si.m_iLength; ++i, ++si.m_Text)
	{
		UT_return_val_if_fail(si.m_Text.getStatus() == UTIter_OK, false);
		current = si.m_Text.getChar();

		if (si.m_TextTransform == GR_ShapingInfo::LOWERCASE)
			current = g_unichar_tolower(current);
		else if (si.m_TextTransform == GR_ShapingInfo::UPPERCASE)
			current = g_unichar_toupper(current);
		else if (si.m_TextTransform == GR_ShapingInfo::CAPITALIZE) {
				if (previousWasSpace) {
					current = g_unichar_toupper(current);
				}
		} // else si.m_TextTransform == GR_ShapingInfo::NONE

		previousWasSpace = g_unichar_isspace(current);

		if(si.m_iVisDir == UT_BIDI_RTL)
			glyph = s_getMirrorChar(current);
		else
			glyph = current;

		if(pFont->doesGlyphExist(glyph))
			*dst_ptr++ = glyph;
		else
		{
			UT_UCS4Char t = s_remapGlyph(glyph);
			if(pFont->doesGlyphExist(t))
			{
				*dst_ptr++ = t;
			}
			else
			{
				*dst_ptr++ = s_cDefaultGlyph;
			}
		}
	}
	
	pRI->m_eState = GRSR_BufferClean;
	
	if(pRI->isJustified())
		justify(*pRI);

	// make sure that we invalidate the static buffers if we own them
	if(pRI->s_pOwner == pRI)
		pRI->s_pOwner = NULL;
	
	return true;
}
Example #16
0
void insert_index_marks(openttsd_message * msg, SPDDataMode ssml_mode)
{
	GString *marked_text;
	char *pos;
	char character[6];
	char character2[6];
	gunichar u_char;
	int n = 0;
	int ret;
	int inside_tag = 0;

	marked_text = g_string_new("");

	assert(msg != NULL);
	assert(msg->buf != NULL);

	log_msg2(5, "index_marking",
		 "MSG before index marking: |%s|, ssml_mode=%d", msg->buf,
		 ssml_mode);

	if (ssml_mode == SPD_DATA_TEXT)
		g_string_printf(marked_text, "<speak>");

	pos = msg->buf;
	while (pos) {
		ret = read_utf8_char(pos, character);
		if (ret == 0 || (strlen(character) == 0))
			break;
		u_char = g_utf8_get_char(character);

		if (u_char == '<') {
			if (ssml_mode == SPD_DATA_SSML) {
				inside_tag = 1;
				g_string_append_printf(marked_text, "%s",
						       character);
			} else
				g_string_append_printf(marked_text, "&lt;");
		} else if (u_char == '>') {
			if (ssml_mode == SPD_DATA_SSML) {
				inside_tag = 0;
				g_string_append_printf(marked_text, "%s",
						       character);
			} else
				g_string_append_printf(marked_text, "&gt;");
		} else if (u_char == '&') {
			if (ssml_mode == SPD_DATA_SSML) {
				g_string_append_printf(marked_text, "%s",
						       character);
			} else {
				if (!inside_tag)
					g_string_append_printf(marked_text,
							       "&amp;");
			}
		} else
		    if (((u_char == '.') || (u_char == '?') || (u_char == '!'))
			&& !inside_tag) {
			pos = g_utf8_find_next_char(pos, NULL);
			ret = read_utf8_char(pos, character2);
			if ((ret == 0) || (strlen(character2) == 0)) {
				g_string_append_printf(marked_text, "%s",
						       character);
				log_msg2(6, "index_marking",
					 "MSG altering 1: |%s|",
					 marked_text->str);
				break;
			}
			u_char = g_utf8_get_char(character2);
			if ((g_unichar_isspace(u_char)) || (u_char == '<')
			    || (u_char == '&')) {
				g_string_append_printf(marked_text,
						       "%s" SD_MARK_HEAD "%d"
						       SD_MARK_TAIL,
						       character, n);
				n++;
				log_msg2(6, "index_marking",
					 "MSG altering 2: |%s|",
					 marked_text->str);
				continue;
			} else {
				g_string_append_printf(marked_text, "%s",
						       character);
				//              pos = g_utf8_find_prev_char(pos, NULL);
				log_msg2(6, "index_marking",
					 "MSG altering 3: |%s|",
					 marked_text->str);
				continue;
			}
		} else {
			g_string_append_printf(marked_text, "%s", character);
		}

		pos = g_utf8_find_next_char(pos, NULL);
	}

	if (ssml_mode == SPD_DATA_TEXT)
		g_string_append_printf(marked_text, "</speak>");

	g_free(msg->buf);
	msg->buf = marked_text->str;

	g_string_free(marked_text, 0);

	log_msg2(5, "index_marking", "MSG after index marking: |%s|", msg->buf);
}
static gboolean
emfe_text_html_format (EMailFormatterExtension *extension,
                       EMailFormatter *formatter,
                       EMailFormatterContext *context,
                       EMailPart *part,
                       GOutputStream *stream,
                       GCancellable *cancellable)
{
	if (g_cancellable_is_cancelled (cancellable))
		return FALSE;

	if (context->mode == E_MAIL_FORMATTER_MODE_RAW) {
		e_mail_formatter_format_text (
			formatter, part, stream, cancellable);

	} else if (context->mode == E_MAIL_FORMATTER_MODE_PRINTING) {
		GOutputStream *decoded_stream;
		GString *string;
		gchar *pos;
		GList *tags, *iter;
		gboolean valid;
		gchar *tag;
		const gchar *document_end;
		gpointer data;
		gsize length;
		gint i;

		decoded_stream = g_memory_output_stream_new_resizable ();

		/* FORMATTER FIXME: See above */
		e_mail_formatter_format_text (
			formatter, part, decoded_stream, cancellable);

		data = g_memory_output_stream_get_data (
			G_MEMORY_OUTPUT_STREAM (decoded_stream));
		length = g_memory_output_stream_get_data_size (
			G_MEMORY_OUTPUT_STREAM (decoded_stream));

		string = g_string_new_len ((gchar *) data, length);

		g_object_unref (decoded_stream);

		if (!g_utf8_validate (string->str, -1, NULL)) {
			gchar *valid_utf8;

			valid_utf8 = e_util_utf8_make_valid (string->str);
			g_string_free (string, TRUE);
			string = g_string_new (valid_utf8);
			g_free (valid_utf8);
		}

		tags = NULL;
		pos = string->str;
		valid = FALSE;

		do {
			gchar *tmp;
			gchar *closing;
			gchar *opening;

			tmp = g_utf8_find_next_char (pos, NULL);
			pos = g_utf8_strchr (tmp, -1, '<');
			if (!pos)
				break;

			opening = pos;
			closing = g_utf8_strchr (pos, -1, '>');

			/* Find where the actual tag name begins */
			while (tag = g_utf8_find_next_char (pos, NULL), tag != NULL) {
				gunichar c = g_utf8_get_char (tag);
				if (!g_unichar_isspace (c))
					break;
			}

			if (g_ascii_strncasecmp (tag, "style", 5) == 0) {
				tags = g_list_append (
					tags,
					get_tag (string->str, "style", opening, closing));
			} else if (g_ascii_strncasecmp (tag, "script", 6) == 0) {
				tags = g_list_append (
					tags,
					get_tag (string->str, "script", opening, closing));
			} else if (g_ascii_strncasecmp (tag, "link", 4) == 0) {
				tags = g_list_append (
					tags,
					get_tag (string->str, "link", opening, closing));
			} else if (g_ascii_strncasecmp (tag, "body", 4) == 0) {
				valid = TRUE;
				break;
			}

		} while (pos);

		/* Something's wrong, let's write the entire HTML and hope
		 * that WebKit can handle it */
		if (!valid) {
			EMailFormatterContext c = {
				.part_list = context->part_list,
				.flags = context->flags,
				.mode = E_MAIL_FORMATTER_MODE_RAW,
			};

			emfe_text_html_format (
				extension, formatter, &c,
				part, stream, cancellable);
			return FALSE;
		}

		/*	       include the "body" as well -----v */
		g_string_erase (string, 0, tag - string->str + 4);
		g_string_prepend (string, "<div ");

		for (iter = tags; iter; iter = iter->next) {
			if (iter->data)
				g_string_prepend (string, iter->data);
		}

		g_list_free_full (tags, g_free);

		document_end = NULL;
		/* We can probably use ASCII functions here */
		if (g_strrstr (string->str, "</body>")) {
			document_end = ">ydob/<";
		}

		if (g_strrstr (string->str, "</html>")) {
			if (document_end) {
				document_end = ">lmth/<>ydob/<";
			} else {
				document_end = ">lmth/<";
			}
		}

		if (document_end) {
			length = strlen (document_end);
			tag = string->str + string->len - 1;
			i = 0;
			valid = FALSE;
			while (i < length - 1) {
				gunichar c;

				c = g_utf8_get_char (tag);
				if (g_unichar_isspace (c)) {
					tag = g_utf8_find_prev_char (string->str, tag);
					continue;
				}

				c = g_unichar_tolower (c);

				if (c == document_end[i]) {
					tag = g_utf8_find_prev_char (string->str, tag);
					i++;
					valid = TRUE;
					continue;
				}

				tag = g_utf8_find_prev_char (string->str, tag);
				valid = FALSE;
			}
		} else {
			/* do not cut, if there is no end tag */
			valid = FALSE;
		}

		if (valid)
			g_string_truncate (string, tag - string->str);

		g_output_stream_write_all (
			stream, string->str, string->len,
			NULL, cancellable, NULL);

		g_string_free (string, TRUE);
	} else {
Example #18
0
static gboolean
find_end_element_char (gunichar ch,
                       gpointer user_data)
{
  return g_unichar_isspace (ch) || ch == '/' || ch == '>';
}
static gchar *
get_tag (const gchar *utf8_string,
         const gchar *tag_name,
         gchar *opening,
         gchar *closing)
{
	gchar *t;
	gunichar c;
	gboolean has_end;

	c = '\0';
	t = g_utf8_find_prev_char (utf8_string, closing);
	while (t != opening) {

		c = g_utf8_get_char (t);
		if (!g_unichar_isspace (c))
			break;
	}

	/* Not a pair tag */
	if (c == '/')
		return g_strndup (opening, closing - opening + 1);

	t = closing;
	while (t) {
		c = g_utf8_get_char (t);
		if (c == '<') {
			if (t[1] == '!' && t[2] == '-' && t[3] == '-') {
				/* it's a comment start, read until the end of "-->" */
				gchar *end = strstr (t + 4, "-->");
				if (end) {
					t = end + 2;
				} else
					break;
			} else
				break;
		}

		t = g_utf8_find_next_char (t, NULL);
	}

	has_end = FALSE;
	do {
		c = g_utf8_get_char (t);

		if (c == '/') {
			has_end = TRUE;
			break;
		}

		if (c == '>') {
			has_end = FALSE;
			break;
		}

		t = g_utf8_find_next_char (t, NULL);

	} while (t);

	/* Broken HTML? */
	if (!has_end)
		return NULL;

	do {
		c = g_utf8_get_char (t);
		if ((c != ' ') && (c != '/'))
			break;

		t = g_utf8_find_next_char (t, NULL);
	} while (t);

	/* tag_name is always ASCII */
	if (g_ascii_strncasecmp (t, tag_name, strlen (tag_name)) == 0) {

		closing = g_utf8_strchr (t, -1, '>');

		return g_strndup (opening, closing - opening + 1);
	}

	/* Broken HTML? */
	return NULL;
}
Example #20
0
static gboolean is_word_sep(gunichar c)
{
	return g_unichar_isspace(c) || g_unichar_ispunct(c);
}
Example #21
0
char *TextEdit::getScreenLine(const char *text, int max_width,
    size_t *res_length) const
{
  g_assert(text);
  g_assert(text < bufend);
  g_assert(max_width > 0);
  g_assert(res_length);

  const char *cur = text;
  const char *res = text;
  int prev_width = 0;
  int cur_width = 0;
  size_t cur_length = 0;
  bool space = false;
  *res_length = 0;

  while (cur < bufend) {
    prev_width = cur_width;
    gunichar uc = g_utf8_get_char(cur);
    cur_width += onScreenWidth(uc, cur_width);
    cur_length++;

    if (prev_width > max_width)
      break;

    // possibly too long word
    if (cur_width > max_width && !*res_length) {
      *res_length = cur_length - 1;
      res = cur;
    }

    // end of line (paragraph on screen) found
    if (*cur == '\n') {
      *res_length = cur_length;
      return nextChar(cur);
    }

    if (g_unichar_isspace(uc))
      space = true;
    else if (space) {
      /* Found start of a word and everything before that can fit into
       * a screen line. */
      *res_length = cur_length - 1;
      res = cur;
      space = false;
    }

    cur = nextChar(cur);
  }

  /* Fix for very small max_width and characters wider that 1 cell. For
   * example, max_width = 1 and text = "W" where W is a wide character (2
   * cells width) (or simply for tabs). In that case we can not draw anything
   * but we want to skip to another character. */
  if (res == text) {
    *res_length = 1;
    res = nextChar(res);
  }

  return const_cast<char*>(res);
}
Example #22
0
static gboolean is_space(gunichar ch, gpointer user_data) {
	return g_unichar_isspace(ch);
}
Example #23
0
static GnomePrintJob *create_job(GnomePrintConfig *gpc)
{
    GnomeFontFace *font_face;
    PangoFontDescription *font_desc;
    GtkTextIter start, end;
    gchar *text, *p;

    /* Get contents of TextBuffer */
    GtkTextBuffer *buffer = pub->mw->buffer;
    gtk_text_buffer_get_bounds(buffer, &start, &end);
    text = g_strchomp(gtk_text_buffer_get_text(buffer, &start, &end, FALSE));

    /* Initialize job */
    job = gnome_print_job_new(gpc);
    gnome_print_job_get_page_size_from_config(gpc, &page_width, &page_height);
    gnome_print_config_get_length(gpc,
                                  (guchar *)GNOME_PRINT_KEY_PAGE_MARGIN_LEFT, &margin_left, NULL);
    gnome_print_config_get_length(gpc,
                                  (guchar *)GNOME_PRINT_KEY_PAGE_MARGIN_RIGHT, &margin_right, NULL);
    gnome_print_config_get_length(gpc,
                                  (guchar *)GNOME_PRINT_KEY_PAGE_MARGIN_TOP, &margin_top, NULL);
    gnome_print_config_get_length(gpc,
                                  (guchar *)GNOME_PRINT_KEY_PAGE_MARGIN_BOTTOM, &margin_bottom, NULL);
    /*
    g_print("margin_left   = %f\n", margin_left);
    g_print("margin_right  = %f\n", margin_right);
    g_print("margin_top    = %f\n", margin_top);
    g_print("margin_bottom = %f\n", margin_bottom);
    	margin_top = margin_left;
    	margin_bottom = margin_left;
    */
    /* Initialize font */
    font_desc = gtk_widget_get_style(pub->mw->view)->font_desc;
    font_face = gnome_font_face_find_closest_from_pango_description(font_desc);
    font = gnome_font_face_get_font_default(font_face, FONT_SIZE);
//		pango_font_description_get_size(font_desc) / PANGO_SCALE);
//	g_print("PANGO_SCALE = %d\n", PANGO_SCALE);
//	g_print("font_size = %d\n", pango_font_description_get_size(font_desc));
    line_height = gnome_font_get_size(font);
    tab_width = gnome_font_face_get_glyph_width(font_face,
                gnome_font_face_lookup_default(font_face, g_utf8_get_char(" ")))
                / 1000 * FONT_SIZE * get_current_tab_width();
    DV(	g_print("tab_width = %f\n", tab_width));

    /* Draw texts to canvas */
    gpx = gnome_print_job_get_context(job);
    gnome_print_beginpage(gpx, NULL);
    gnome_print_setfont(gpx, font);

    page_x = margin_left;	// TODO RTL
    page_y = page_height - margin_top - line_height;
    gnome_print_moveto(gpx, page_x, page_y);

    gl = gnome_glyphlist_from_text_dumb(font, 0x000000ff, 0, 0, (guchar *)"");
    gl_width = 0;

    p = text;

    while (*p != '\0') {
        gunichar ch = g_utf8_get_char(p);
        gint glyph = gnome_font_lookup_default(font, ch);
        if (!glyph) {
            if (ch == '\n') {
                print_glyph_list(page_x + gl_width > page_width - margin_right);
                move_pen_to_newline();
                DV(				g_print("LF\n"));
            } else if (ch == '\t') {
                print_glyph_list(page_x + gl_width > page_width - margin_right);
                /*				page_x = page_x + tab_width
                					- ((page_x - margin_left) % tab_width); */
                gdouble tmp_x = margin_left;
                do {
                    tmp_x += tab_width;
                } while (tmp_x < page_x + 0.000001); // FIXME
                DV(				g_print("HT "));
                DV(				g_print("%f -> %f\n", page_x, tmp_x));
                page_x = tmp_x;
                gnome_print_moveto(gpx, page_x, page_y);
                /*			} else if (ch == '\f') {
                DV(				g_print("FF\n"));
                				print_glyph_list(page_x + gl_width > page_width - margin_right);
                				move_pen_to_nextpage();
                */
            }
            else {
                GnomeFont *tmp_font = find_proper_font(ch);
                GnomeFontFace *tmp_face = gnome_font_get_face(tmp_font);
                gdouble g_width;

                glyph = gnome_font_lookup_default(tmp_font, ch);
                g_width = gnome_font_face_get_glyph_width(tmp_face, glyph)
                          / 1000 * FONT_SIZE;
                if (page_x + gl_width + g_width > page_width - margin_right) {
                    if (g_unichar_iswide(ch)) {
                        print_glyph_list(FALSE);
                        move_pen_to_newline();
                    } else
                        print_glyph_list(TRUE);
                }
                gnome_glyphlist_font(gl, tmp_font);
                gnome_glyphlist_glyph(gl, glyph);
                gnome_glyphlist_font(gl, font);
                gl_width += g_width;
                DV(				g_print("** "));
            }
        } else {
//			if (ch == ' ') {
            if (g_unichar_isspace(ch)) {
                DV(				g_print("SP "));
                DV(				g_print("\n"));
                print_glyph_list(page_x + gl_width > page_width - margin_right);
                page_x +=
                    gnome_font_face_get_glyph_width(font_face, glyph) / 1000 * FONT_SIZE;
                gnome_print_moveto(gpx, page_x, page_y);
            } else {
                gdouble g_width
                    = gnome_font_face_get_glyph_width(font_face, glyph)
                      / 1000 * FONT_SIZE;
                if (page_x + gl_width + g_width > page_width - margin_right) {
                    if (g_unichar_iswide(ch)) {
                        print_glyph_list(FALSE);
                        move_pen_to_newline();
                    } else
                        print_glyph_list(TRUE);
                }
                gnome_glyphlist_glyph(gl, glyph);
                gl_width += g_width;
                DV(				g_print("%02X ", glyph));
                DV(				g_print("%f (%f)\n", gl_width, gnome_font_get_glyph_width(font, glyph)));
            }
        }
        p = g_utf8_next_char(p);
    }
    print_glyph_list(page_x + gl_width > page_width - margin_right);
    DV(	g_print("\n[EOT]\n"));

    gnome_print_showpage(gpx);
    gnome_print_context_close(gpx);
    g_object_unref(gpx);

    gnome_glyphlist_unref(gl);
    gnome_font_unref(font);
    gnome_font_face_unref(font_face);
    gnome_print_job_close(job);

    return job;
}