のらぬこの日常を描く

ノージャンルのお役立ち情報やアニメとゲームの話、ソフトウェア開発に関する話などを中心としたブログです。

GNU screenのcaption, hardstatus で日本語が文字化けする問題 その2

昨日のエントリー

GNU screend(ry について

使ってて気づいた不具合を修正したのでパッチを再リリースします。

・フォントレンダリング位置がずれる問題を修正

・%= の左側にマルチバイト文字があると終端位置がおかしくなるバグを修正

・hardstatusにたぶん対応

f:id:mikenekoDX:20100209012251p:image

まずは導入方法から。環境はFedora12 x86_64で確認してます。

パッチだけ持ってきたい人は1~2画面ほどスクロールして下さい。

2/10日追記

以下を実行する前に、事前にこのエントリーに貼りつけてあるパッチテキストを

適当な作業ディレクトリに、screen-4.0.3-caption.patch という名前で保存しておいてください。

$ cd <適当な作業ディレクトリ>
$ su
# yum install rpm-build yum-utils
# exit

$ yumdownloader --source screen
$ ls
  screen-4.0.3.fc12.src.rpm
$ rpm -ivh screen-4.0.3.fc12.src.rpm
.....
src.rpmが ~/rpmbuild 以下にインストールされる

$ cp screen-4.0.3-caption.patch ~/rpmbuild/SOURCES/
$ cd ~/rpmbuild/SPECS/
$ vi screen.spec
# add部分を追記する
...
Patch13: screen-4.0.3-resize.patch
Patch15: screen-4.0.3-caption.patch  # add
...
%patch13 -p2 -b .resize
%patch15 -p1 -b .caption # add

$ rpmbuild -bb screen.spec
....
環境に合わせてi686もしくはx86-64用のrpmが作成される

$ cd ../RPMS/i686/
もしくは
$ cd ../RPMS/x86-64/

$ su 
# yum remove screen
  screenが既に導入済みの場合アンインストール

# rpm -ivh screen-4.0.3-15.fc12.i686.rpm 
もしくは
# rpm -ivh screen-4.0.3-15.fc12.x86_64.rpm 


んで、以下がpatch本体

コピーして、Linux環境に screen-4.0.3-caption.patch として保存してください。

2010/02/08 02:05am

デバッグコードが残ってたのをこっそり修正 m(__)m

diff -Naur screen-4.0.3-old/display.c screen-4.0.3/display.c
--- screen-4.0.3-old/display.c	2010-02-09 01:58:31.740872546 +0900
+++ screen-4.0.3/display.c	2010-02-09 01:56:26.416126479 +0900
@@ -874,13 +874,68 @@
 RAW_PUTCHAR(c)
 int c;
 {
-  ASSERT(display);
+#ifdef UTF8
+	static int utfPhase = 0;
+	static int utfLength = 0;
+	static char utfBuffer[4] = 
+		{ '\0', '\0', '\0', '\0' };
+	static int utfIsError = 0;
+#endif
+
+	ASSERT(display);
 
 #ifdef FONT
 # ifdef UTF8
   if (D_encoding == UTF8)
     {
-      c = (c & 255) | (unsigned char)D_rend.font << 8;
+		if( D_rendering_status )
+		{
+			if( ( c & 0xc0 ) == 0x80 )
+			{
+				if( ( utfLength == 0 ) && ( utfIsError == 0 ) )
+				{
+					c = ' ';
+					utfIsError = 1;
+				}
+				else if( utfLength == 0 )
+				{
+					return;
+				}
+				else
+				{
+					utfPhase ++;
+					if( utfPhase < utfLength )
+						utfBuffer[utfPhase] = c;
+					if( utfPhase == utfLength - 1 )
+					{
+						int index = 0;
+						for( index = 0; index < utfLength; index ++ )
+							AddChar( utfBuffer[index] );
+						utfPhase = 0;
+						utfLength = 0;
+						return;
+					}
+					else
+					{
+						return;
+					}
+				}
+			}
+			else
+			{
+				utfPhase = 0;
+				utfBuffer[utfPhase] = c;
+				if( ( c & 0x80 ) == 0 )
+					utfLength = 1;
+				else if( ( c & 0xe0 ) == 0xc0 )
+					utfLength = 2;
+				else if( ( c & 0xf0 ) == 0xe0 )
+					utfLength = 3;
+				if( utfLength > 1 )
+					return;
+			}
+		}
+		c = (c & 255) | (unsigned char)D_rend.font << 8;
 #  ifdef DW_CHARS
       if (D_mbcs)
 	{
@@ -2457,7 +2512,9 @@
   buf = MakeWinMsgEv(hstatusstring, D_fore, '%', (D_HS && D_has_hstatus == HSTATUS_HS && D_WS > 0) ? D_WS : D_width - !D_CLP, &D_hstatusev, 0);
   if (buf && *buf)
     {
+		D_rendering_status = 1;
       ShowHStatus(buf);
+		D_rendering_status = 0;
       if (D_has_hstatus != HSTATUS_IGNORE && D_hstatusev.timeout.tv_sec)
         evenq(&D_hstatusev);
     }
diff -Naur screen-4.0.3-old/display.h screen-4.0.3/display.h
--- screen-4.0.3-old/display.h	2010-02-09 01:58:31.740872546 +0900
+++ screen-4.0.3/display.h	2010-02-09 01:56:32.908996544 +0900
@@ -187,6 +187,7 @@
   int   d_blankerpid;
   struct event d_blankerev;
 #endif
+  int d_rendering_status;	/* rendering caption / status */
 };
 
 #ifdef MULTI
@@ -301,8 +302,7 @@
 #define D_idleev	DISPLAY(d_idleev)
 #define D_blankerev	DISPLAY(d_blankerev)
 #define D_blankerpid	DISPLAY(d_blankerpid)
-
-
+#define D_rendering_status DISPLAY(d_rendering_status)
 #define GRAIN 4096	/* Allocation grain size for output buffer */
 #define OBUF_MAX 256	/* default for obuflimit */
 
diff -Naur screen-4.0.3-old/screen.c screen-4.0.3/screen.c
--- screen-4.0.3-old/screen.c	2010-02-09 01:58:31.778751717 +0900
+++ screen-4.0.3/screen.c	2010-02-09 01:56:14.738871018 +0900
@@ -2050,33 +2050,111 @@
 int numpad;
 int padlen;
 {
-  char *pn, *pn2;
-  int i, r;
-
-  padlen = padlen - (p - buf);	/* space for rent */
-  if (padlen < 0)
-    padlen = 0;
-  pn2 = pn = p + padlen;
-  r = winmsg_numrend;
-  while (p >= buf)
-    {
-      if (r && p - buf == winmsg_rendpos[r - 1])
+	if( ( D_encoding != UTF8 ) && ( ( numpad == 0 ) || ( numpad > 1 ) ) )
 	{
-	  winmsg_rendpos[--r] = pn - buf;
-	  continue;
+		char *pn, *pn2;
+		int i, r;
+		padlen = padlen - (p - buf);	/* space for rent */
+		if (padlen < 0)
+			padlen = 0;
+		pn2 = pn = p + padlen;
+		r = winmsg_numrend;
+		while (p >= buf)
+	    {
+			if (r && p - buf == winmsg_rendpos[r - 1])
+			{
+				winmsg_rendpos[--r] = pn - buf;
+				continue;
+			}
+			*pn-- = *p;
+			if (*p-- == 127)
+			{
+				pn[1] = ' ';
+				i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0;
+				padlen -= i;
+				while (i-- > 0)
+					*pn-- = ' ';
+				numpad--;
+			}
+		}
+		return pn2;
 	}
-      *pn-- = *p;
-      if (*p-- == 127)
+	else
 	{
-	  pn[1] = ' ';
-	  i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0;
-	  padlen -= i;
-	  while (i-- > 0)
-	    *pn-- = ' ';
-	  numpad--;
+		int index = 0, index2 = 0;
+		int div = 0;			// begin right side of byte position.
+		int lengthRight = 0;	// total right display length of %=.
+		int lengthLeft = 0;		// total left display length of %=. 
+		int lengthTarget = 0;	// total byte length.
+		int topRight = 0;
+		int lengthMove = 0;
+		
+		lengthTarget = p - buf;
+		p = buf;
+		for( index = 0; index < lengthTarget; index ++ )
+		{
+			if( p[index] == 127 )
+				break;
+		}
+		p[index] = ' ';
+		index ++;
+		div = index;
+		for( index = 0; index < div; index ++ )
+		{
+			if( ( p[index] & 0x80 ) == 0 )
+			{
+				lengthLeft ++;	// display length = 1
+			}
+			else if( ( p[index] & 0xe0 ) == 0xc0 )
+			{
+				// U+0080-U+0FFF
+				lengthLeft ++;	// display length == 1?
+				index++;		// skip next 1 byte.
+				padlen ++;		// fix padlen
+			}
+			else if( ( p[index] & 0xf0 ) == 0xe0 )
+			{
+				// U+1000-
+				lengthLeft += 2;	// display length = 2
+				index += 2;			// skip next 2 byte.
+				padlen ++;			// fix padlen
+			}
+		}
+		for( index = div; index < lengthTarget; index ++ )
+		{
+			if( ( p[index] & 0x80 ) == 0 )
+			{
+				lengthRight ++;
+			}
+			else if( ( p[index] & 0xe0 ) == 0xc0 )
+			{
+				lengthRight ++;
+				index++;
+				padlen ++;
+			}
+			else if( ( p[index] & 0xf0 ) == 0xe0 )
+			{
+				lengthRight += 2;
+				index += 2;
+				padlen ++;
+			}
+		}
+		topRight = padlen - ( lengthTarget - div );
+		lengthMove = topRight - div;
+		if( lengthMove > 0 )
+		{
+			for( index = lengthTarget - 1, index2 = 0; index >= div; index --, index2 ++ )
+				p[padlen - (index2 + 1)] = p[index];
+			for( index = div; index < topRight; index ++ )
+				p[index] = ' ';
+		}
+		for( index = 0; index < winmsg_numrend; index ++ )
+		{
+			if( winmsg_rendpos[index] >= div )
+				winmsg_rendpos[index] += lengthMove;
+		}
+		return p;
 	}
-    }
-  return pn2;
 }
 
 struct backtick {
@@ -2809,6 +2887,8 @@
 
   if (s != winmsg_buf)
     return 0;
+
+  D_rendering_status = 1;
   rend = D_rend;
   p = 0;
   l = strlen(s);
@@ -2818,47 +2898,74 @@
       if (p > winmsg_rendpos[i] || winmsg_rendpos[i] > l)
 	break;
       if (p < winmsg_rendpos[i])
-	{
-	  n = winmsg_rendpos[i] - p;
-	  if (n > max)
-	    n = max;
-	  max -= n;
-	  p += n;
-	  while(n-- > 0)
-	    {
-	      if (start-- > 0)
-		s++;
-	      else
-	        PUTCHARLP(*s++);
-	    }
-	}
-      r = winmsg_rend[i];
-      if (r == -1)
-	{
-	  if (rendstackn > 0)
-	    rend = rendstack[--rendstackn];
-	}
+	  {
+		  n = winmsg_rendpos[i] - p;
+		  if (n > max)
+			  n = max;
+		  max -= n;
+		  p += n;
+		  while (n-- > 0)
+		  {
+			  if (start-- > 0)
+			  {
+				  s++;
+			  }
+			  else
+			  {
+				  if( D_encoding == UTF8 )
+				  {
+					  /* multibyte char start */
+					  if( ( (*s) & 0xf0 ) == 0xe0 )
+					  {
+						  max ++;
+						  l ++;
+					  }
+				  }
+				  PUTCHARLP (*s++);
+			  }
+		  }
+	  }
+	  r = winmsg_rend[i];
+	  if (r == -1)
+	  {
+		  if (rendstackn > 0)
+			  rend = rendstack[--rendstackn];
+	  }
       else
+	  {
+		  rendstack[rendstackn++] = rend;
+		  ApplyAttrColor (r, &rend);
+	  }
+      SetRendition (&rend);
+  }
+	if (p < l)
 	{
-	  rendstack[rendstackn++] = rend;
-	  ApplyAttrColor(r, &rend);
-	}
-      SetRendition(&rend);
-    }
-  if (p < l)
-    {
-      n = l - p;
-      if (n > max)
-	n = max;
-      while(n-- > 0)
-	{
-	  if (start-- > 0)
-	    s++;
-	  else
-	    PUTCHARLP(*s++);
+		n = l - p;
+		if (n > max)
+			n = max;
+		while (n-- > 0)
+		{
+			if (start-- > 0)
+			{
+				s++;
+			}
+			else
+			{
+				if( D_encoding == UTF8 )
+				{
+					if( ( (*s) & 0xf0 ) == 0xe0 )
+					{
+						max ++;
+						l ++;
+						n ++;
+					}
+				}
+				PUTCHARLP (*s++);
+			}
+		}
 	}
-    }
-  return 1;
+	D_rendering_status = 0;
+	return 1;
 }