git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [RFC 1/8] UTF helpers

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
May 13, 2009, 00:20 UTC
Message-ID
<alpine.DEB.1.00.0905130215260.27348@pacific.mpi-cbg.de>
In-Reply-To
<1242168631-30753-2-git-send-email-robin.rosenberg@dewire.com>
Hi,
On Wed, 13 May 2009, Robin Rosenberg wrote:
> ---
No SOB.
Show 17 quoted lines
> diff --git a/git.c b/git.c
> index 6475847..bd4e726 100644
> --- a/git.c
> +++ b/git.c
> @@ -272,6 +272,15 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
>  	};
>  	int i;
>  
> +#ifdef DEBUG
> +	if (debug()) {
> +		fprintf(stderr,"GIT-");
> +		for (i = 1; i<argc; ++i)
> +			fprintf(stderr,"%s",argv[i]);
> +		fprintf(stderr,"\n");
> +	}
> +#endif
> +
What does that have to do with UTF support?
Show 17 quoted lines
> diff --git a/t/test-lib.sh b/t/test-lib.sh
> index 07cb706..e8aefd8 100755
> --- a/t/test-lib.sh
> +++  b/t/test-lib.sh
> @@ -4,11 +4,9 @@
>  #
>  
>  # For repeatability, reset the environment to known value.
> -LANG=C
> -LC_ALL=C
>  PAGER=cat
>  TZ=UTC
> -export LANG LC_ALL PAGER TZ
> +export PAGER TZ
>  EDITOR=:
>  VISUAL=:
>  unset AUTHOR_DATE
Likewise.
Show 67 quoted lines
> diff --git a/test-utf.c b/test-utf.c
> new file mode 100644
> index 0000000..133eea0
> --- /dev/null
> +++ b/test-utf.c
> @@ -0,0 +1,61 @@
> +#include <stdio.h>
> +#include <time.h>
> +#include <assert.h>
> +
> +#include "cache.h"
> +#include "utf.h"
> +
> +int main(int argc, char **argv)
> +{
> +	int i;
> +
> +#if 0
> +	for (i = 1; i < argc; i++) {
> +		char result1[100];
> +		char result2[100];
> +
> +		utfcpy(result1, argv[i], strlen(argv[i])+1);
> +		localcpy(result2, result1, strlen(result1)+1);
> +
> +		printf("%s -> %s -> %s\n", argv[i], result1, result2);
> +	}
> +	return 0;
> +#endif
> +
> +#define test(name) case __LINE__: current_name=name; n++; printf("Testing case #%d: %s\n", n, current_name);
> +#define end_test break;
> +#define begin_suite() char *current_name=0; int n=1; for (i=0; i<1000; ++i) { switch(i) { 
> +#define concats(a,b) #a #b
> +
> +#undef strcmp
> +#define assertStringEquals(a,b) assert(#a #b && strcmp(a,b)==0)
> +#define assertIntEquals(a,b) assert(#a #b && (a)==(b))
> +
> +#define end_suite() }}
> +
> +	begin_suite();
> +
> +	test("utfcpy") {
> +	  char result[100];
> +	  utfcpy(result,"?ndrad",7);
> +	  assertStringEquals(result,"\303\204ndrad");
> +	} end_test;
> +
> +	test("utflen") {
> +	  int result=utflen("?ndrad",7);
> +	  assertIntEquals(result,8);
> +	} end_test;
> +
> +	test("localcpy") {
> +	  char result[100];
> +	  localcpy(result,"\303\204ndrad",8);
> +	  assertStringEquals(result,"?ndrad");
> +	} end_test;
> +
> +	test("locallen") {
> +	  int result=locallen("\303\204ndrad",8);
> +	  assertIntEquals(result,7);
> +	} end_test;
> +
> +	end_suite();
> +}

Should the test-utf binary not rather perform _actions_ (i.e. transformations) instead of checks?

Show 22 quoted lines
> diff --git a/utf.c b/utf.c
> new file mode 100644
> index 0000000..eb430b2
> --- /dev/null
> +++ b/utf.c
> @@ -0,0 +1,207 @@
> +#undef UTF8INTERNAL
> +
> +#include <langinfo.h>
> +#include <iconv.h>
> +#include "cache.h"
> +#include <locale.h>
> +#include <stdarg.h>
> +
> +static iconv_t local_to_utf8 = (iconv_t)-1;
> +static iconv_t utf8_to_local = (iconv_t)-1;
> +static iconv_t utf8_to_utf8 = (iconv_t)-1;
> +static int same = 0;
> +
> +#if TEST
> +#define die printf
> +#endif
This is ugly.
Show 10 quoted lines
> +
> +static void	initlocale()
> +{
> +#ifndef NO_ICONV
> +	if (!same && local_to_utf8 == (iconv_t)-1) {
> +		setlocale(LC_CTYPE, "");
> +		char *local_encoding = nl_langinfo(CODESET);
> +#ifdef DEBUG
> +		if (debug()) fprintf(stderr,"encoding=%s\n", local_encoding);
> +#endif
This is ugly.
Show 11 quoted lines
> +		if (strcmp(local_encoding,"UTF-8") == 0) {
> +			same = 1;
> +			return;
> +		}
> +		local_to_utf8 = iconv_open("UTF-8",  local_encoding);
> +		if (local_to_utf8 == (iconv_t)-1) {
> +			die("cannot setup locale conversion from %s: %s", local_encoding, strerror(errno));
> +		}
> +#ifdef DEBUG
> +		if (debug()) fprintf(stderr,"utf8_to_local = iconv_open(%s,UTF-8)\n",local_encoding);
> +#endif
This is ugly.
Show 88 quoted lines
> +		utf8_to_local = iconv_open(local_encoding,  "UTF-8");
> +		if (utf8_to_local == (iconv_t)-1) {
> +			die("cannot setup locale conversion from %s: %s", local_encoding, strerror(errno));
> +		}
> +
> +		utf8_to_utf8 = iconv_open("UTF-8","UTF-8");
> +		if (utf8_to_utf8 == (iconv_t)-1) {
> +			die("cannot setup locale conversion from UTF-8 to UTF-8: %s",strerror(errno));
> +		}
> +	}
> +#endif
> +}
> +
> +int maybe_utf8(const char *local, size_t len)
> +{
> +  char *self = xcalloc(1,len+1);
> +  char *selfp = self;
> +  size_t outlen = len+1;
> +  int ret = iconv(utf8_to_utf8, (char**)&local, &len, &selfp, &outlen);
> +  free(self);
> +  P(("maybelocal: %0.*s %s\n", len, local, ret!=-1 ? "yes" : "no"));
> +  return ret != -1;
> +}
> +
> +size_t utflen(const char *local, size_t locallen)
> +{
> +#ifndef NO_ICONV
> +	initlocale();
> +	if (same) {
> +		return locallen;
> +	}
> +	if (maybe_utf8(local, locallen))
> +		return locallen;
> +
> +	size_t outlen=locallen*6;
> +	char *outbuf=xcalloc(outlen,1);
> +	char *out=outbuf;
> +	iconv(local_to_utf8, NULL, NULL, NULL, NULL);
> +	const char *vlocal = local;
> +	size_t vlocallen = locallen;
> +	if (iconv(local_to_utf8,  (char**)&vlocal,  &vlocallen,  &out,  &outlen) == -1) {
> +#if TEST
> +		perror("failed");
> +#endif
> +		free(outbuf);
> +		return locallen;
> +	}
> +	*out = 0;
> +	free(outbuf);
> +	return locallen*6 - outlen;
> +#else
> +	return locallen;
> +#endif
> +}
> +
> +/* Copy and transform */
> +void utfcpy(char *to_utf, char *from_local, size_t localsize)
> +{
> +#ifdef DEBUG
> +	char *a=to_utf,*b=from_local;
> +#endif
> +#ifndef NO_ICONV
> +	initlocale();
> +	if (same) {
> +		memcpy(to_utf, from_local, localsize);
> +		return;
> +	}
> +	if (maybe_utf8(from_local, localsize)) {
> +		memcpy(to_utf, from_local, localsize);
> +		return;
> +	}
> +
> +	size_t outlen=localsize*6;
> +	iconv(local_to_utf8, NULL, NULL, NULL, NULL);
> +	char *vfrom_local = from_local;
> +	char *vto_utf = to_utf;
> +	size_t vlocalsize = localsize;
> +	if (iconv(local_to_utf8,  &vfrom_local,  &vlocalsize,  &vto_utf,  &outlen) == -1) {
> +		fprintf(stderr,"Failed to convert %0.*s to UTF\n", localsize, from_local);
> +		memcpy(to_utf,  from_local,  localsize);
> +	}
> +#else
> +	memcpy(to_utf, from_local, localsize);
> +#endif
> +#ifdef DEBUG
> +	if (debug()) fprintf(stderr,"%0.*s ->UTF %0.*s\n", localsize, b, localsize*6 - outlen, a);
> +#endif
> +}

Okay, I'll stop here. You might want to clean up your patch series before resending.

Ciao, Dscho

Previous: Robin RosenbergNext: Robin Rosenberg
Message 6 of 20 in “[RFC 0/8] Antique UTF-8 filename support”
  1. Robin RosenbergMay 12, 2009
  2. 1/8 UTF helpersRobin Rosenberg, May 12, 2009
  3. 2/8 Messages in locale.Robin Rosenberg, May 12, 2009
  4. 3/8 Extend tests to cover locale wrt to commit messages.Robin Rosenberg, May 12, 2009
  5. 4/8 UTF file names.Robin Rosenberg, May 12, 2009
  6. Johannes SchindelinMay 13, 2009
  7. Robin RosenbergMay 13, 2009
  8. Esko LuontolaMay 13, 2009
  9. Andreas EricssonMay 13, 2009
  10. Esko LuontolaMay 13, 2009
  11. Alex RiesenMay 13, 2009
  12. Junio C HamanoMay 13, 2009
  13. Esko LuontolaMay 13, 2009
  14. Junio C HamanoMay 13, 2009
  15. Johannes SchindelinMay 13, 2009
  16. Junio C HamanoMay 14, 2009
  17. Jay SoffianMay 14, 2009
  18. 6/8 test of utf_locallinksRobin Rosenberg, May 12, 2009
  19. 7/8 Convert symlink dest in diffRobin Rosenberg, May 12, 2009
  20. 8/8 UTF-8 in non-SHA1-objectsRobin Rosenberg, May 12, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.