Re: Gtk+ print support - request for feedback



On Fri, 2006-03-03 at 13:59 -0500, Morten Welinder wrote:
> What's the status of thread safety?  Last I looked at cups it was
> not thread safe due to calling setlocale, and there was little
> understanding as to why that was a problem.
> 
> (And recall that just about any gtk+ program is at least
> minimally threaded.)

Hmm, cups still seems to be changing the locale. Both for parsing floats
in the ppd with "." as separator, and in cupsLangGet() (where it calls
setlocale(LC_ALL, NULL) if the locale wasn't already set).

We can avoid calling anything that results in cupsLangGet(), but not the
float parsing. 

Michael, is there any chance that this will be fixed in cups? The way
gtk+ does threadsafe locale-independent float parsing is this: 
(I wrote this code, so if you want to use it in cups I'm ok with
re-licensing it in a suitable way)

/**
 * g_ascii_strtod:
 * @nptr:    the string to convert to a numeric value.
 * @endptr:  if non-%NULL, it returns the character after
 *           the last character used in the conversion.
 * 
 * Converts a string to a #gdouble value.
 * This function behaves like the standard strtod() function
 * does in the C locale. It does this without actually
 * changing the current locale, since that would not be
 * thread-safe.
 *
 * This function is typically used when reading configuration
 * files or other non-user input that should be locale independent.
 * To handle input from the user you should normally use the
 * locale-sensitive system strtod() function.
 *
 * To convert from a #gdouble to a string in a locale-insensitive
 * way, use g_ascii_dtostr().
 *
 * If the correct value would cause overflow, plus or minus %HUGE_VAL
 * is returned (according to the sign of the value), and %ERANGE is
 * stored in %errno. If the correct value would cause underflow,
 * zero is returned and %ERANGE is stored in %errno.
 * 
 * This function resets %errno before calling strtod() so that
 * you can reliably detect overflow and underflow.
 *
 * Return value: the #gdouble value.
 **/
gdouble
g_ascii_strtod (const gchar *nptr,
		gchar      **endptr)
{
  gchar *fail_pos;
  gdouble val;
  struct lconv *locale_data;
  const char *decimal_point;
  int decimal_point_len;
  const char *p, *decimal_point_pos;
  const char *end = NULL; /* Silence gcc */
  int strtod_errno;

  g_return_val_if_fail (nptr != NULL, 0);

  fail_pos = NULL;

  locale_data = localeconv ();
  decimal_point = locale_data->decimal_point;
  decimal_point_len = strlen (decimal_point);

  g_assert (decimal_point_len != 0);
  
  decimal_point_pos = NULL;
  end = NULL;

  if (decimal_point[0] != '.' || 
      decimal_point[1] != 0)
    {
      p = nptr;
      /* Skip leading space */
      while (g_ascii_isspace (*p))
	p++;
      
      /* Skip leading optional sign */
      if (*p == '+' || *p == '-')
	p++;
      
      if (p[0] == '0' && 
	  (p[1] == 'x' || p[1] == 'X'))
	{
	  p += 2;
	  /* HEX - find the (optional) decimal point */
	  
	  while (g_ascii_isxdigit (*p))
	    p++;
	  
	  if (*p == '.')
	    decimal_point_pos = p++;
	      
	  while (g_ascii_isxdigit (*p))
	    p++;
	  
	  if (*p == 'p' || *p == 'P')
	    p++;
	  if (*p == '+' || *p == '-')
	    p++;
	  while (g_ascii_isdigit (*p))
	    p++;

	  end = p;
	}
      else if (g_ascii_isdigit (*p) || *p == '.')
	{
	  while (g_ascii_isdigit (*p))
	    p++;
	  
	  if (*p == '.')
	    decimal_point_pos = p++;
	  
	  while (g_ascii_isdigit (*p))
	    p++;
	  
	  if (*p == 'e' || *p == 'E')
	    p++;
	  if (*p == '+' || *p == '-')
	    p++;
	  while (g_ascii_isdigit (*p))
	    p++;

	  end = p;
	}
      /* For the other cases, we need not convert the decimal point */
    }

  if (decimal_point_pos)
    {
      char *copy, *c;

      /* We need to convert the '.' to the locale specific decimal point */
      copy = g_malloc (end - nptr + 1 + decimal_point_len);
      
      c = copy;
      memcpy (c, nptr, decimal_point_pos - nptr);
      c += decimal_point_pos - nptr;
      memcpy (c, decimal_point, decimal_point_len);
      c += decimal_point_len;
      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
      c += end - (decimal_point_pos + 1);
      *c = 0;

      errno = 0;
      val = strtod (copy, &fail_pos);
      strtod_errno = errno;

      if (fail_pos)
	{
	  if (fail_pos - copy > decimal_point_pos - nptr)
	    fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
	  else
	    fail_pos = (char *)nptr + (fail_pos - copy);
	}
      
      g_free (copy);
	  
    }
  else if (end)
    {
      char *copy;
      
      copy = g_malloc (end - (char *)nptr + 1);
      memcpy (copy, nptr, end - nptr);
      *(copy + (end - (char *)nptr)) = 0;
      
      errno = 0;
      val = strtod (copy, &fail_pos);
      strtod_errno = errno;

      if (fail_pos)
	{
	  fail_pos = (char *)nptr + (fail_pos - copy);
	}
      
      g_free (copy);
    }
  else
    {
      errno = 0;
      val = strtod (nptr, &fail_pos);
      strtod_errno = errno;
    }

  if (endptr)
    *endptr = fail_pos;

  errno = strtod_errno;

  return val;
}

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 Alexander Larsson                                            Red Hat, Inc 
                   alexl redhat com    alla lysator liu se 
He's a shy chivalrous househusband living undercover at Ringling Bros. Circus. 
She's a ditzy punk museum curator with the soul of a mighty warrior. They 
fight crime! 




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]