diff --git a/bin/make_ci.pike b/bin/make_ci.pike
index a3f0c0ee899d64ffa430b978bad1c7d027d54f77..90393dab9eba39493da1782089c33eeaa1a111fe 100644
--- a/bin/make_ci.pike
+++ b/bin/make_ci.pike
@@ -1,5 +1,5 @@
 /*
- * $Id: make_ci.pike,v 1.4 1999/03/20 16:30:55 grubba Exp $
+ * $Id: make_ci.pike,v 1.5 2000/07/27 17:46:47 lange Exp $
  *
  * Creates the file case_info.h
  *
@@ -73,7 +73,7 @@ int main(int argc, array(string) argv)
 
   write(sprintf("/*\n"
 		" * Created by\n"
-		" * $Id: make_ci.pike,v 1.4 1999/03/20 16:30:55 grubba Exp $\n"
+		" * $Id: make_ci.pike,v 1.5 2000/07/27 17:46:47 lange Exp $\n"
 		" * on %s"
 		" *\n"
 		" * Table used for looking up the case of\n"
@@ -90,6 +90,11 @@ int main(int argc, array(string) argv)
 		  (info[2]<0)?"-":"",
 		  (info[2]<0)?-info[2]:info[2]));
   }
+  
+  for (lineno=0; lineno<sizeof(ci); lineno++)
+    if (ci[lineno][0] > 0xff)
+      break;
+  write(sprintf("#define CASE_INFO_SHIFT0_HIGH 0x%04x\n", lineno));
 
   exit(0);
 }
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 497c25f00c6069baa69004017201a48c26340cb8..064dc2f63d970c147f18a024da514384d72f4519 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.291 2000/07/19 16:48:51 lange Exp $");
+RCSID("$Id: builtin_functions.c,v 1.292 2000/07/27 17:47:29 lange Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -169,7 +169,7 @@ static struct case_info *find_ci(int c)
     return NULL;
 
   if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) {
-    return ci;
+    return ci; 
   }
 
   while (lo != hi-1) {
@@ -186,6 +186,34 @@ static struct case_info *find_ci(int c)
   return(cache = (struct case_info *)case_info + lo);
 }
 
+static struct case_info *find_ci_shift0(int c)
+{
+  static struct case_info *cache = NULL;
+  struct case_info *ci = cache;
+  int lo = 0;
+  int hi = CASE_INFO_SHIFT0_HIGH;
+
+  if ((c < 0) || (c > 0xffff))
+    return NULL;
+
+  if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) {
+    return ci; 
+  }
+
+  while (lo != hi-1) {
+    int mid = (lo + hi)>>1;
+    if (case_info[mid].low < c) {
+      lo = mid;
+    } else if (case_info[mid].low == c) {
+      lo = mid;
+      break;
+    } else {
+      hi = mid;
+    }
+  }
+  return(cache = (struct case_info *)case_info + lo);
+}
+
 #define DO_LOWER_CASE(C) do {\
     int c = C; \
     struct case_info *ci = find_ci(c); \
@@ -200,6 +228,20 @@ static struct case_info *find_ci(int c)
    } \
   } while(0)
 
+#define DO_LOWER_CASE_SHIFT0(C) do {\
+    int c = C; \
+    struct case_info *ci = find_ci_shift0(c); \
+    if (ci) { \
+      switch(ci->mode) { \
+      case CIM_NONE: case CIM_LOWERDELTA: break; \
+      case CIM_UPPERDELTA: C = c + ci->data; break; \
+      case CIM_CASEBIT: C = c | ci->data; break; \
+      case CIM_CASEBITOFF: C = ((c - ci->data) | ci->data) + ci->data; break; \
+      default: fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); \
+    } \
+   } \
+  } while(0)
+
 #define DO_UPPER_CASE(C) do {\
     int c = C; \
     struct case_info *ci = find_ci(c); \
@@ -214,6 +256,20 @@ static struct case_info *find_ci(int c)
    } \
   } while(0)
 
+#define DO_UPPER_CASE_SHIFT0(C) do {\
+    int c = C; \
+    struct case_info *ci = find_ci_shift0(c); \
+    if (ci) { \
+      switch(ci->mode) { \
+      case CIM_NONE: case CIM_UPPERDELTA: break; \
+      case CIM_LOWERDELTA: C = c - ci->data; break; \
+      case CIM_CASEBIT: C = c & ~ci->data; break; \
+      case CIM_CASEBITOFF: C = ((c - ci->data)& ~ci->data) + ci->data; break; \
+      default: fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); \
+    } \
+   } \
+  } while(0)
+
 void f_lower_case(INT32 args)
 {
   INT32 i;
@@ -231,7 +287,7 @@ void f_lower_case(INT32 args)
     p_wchar0 *str = STR0(ret);
 
     while(i--) {
-      DO_LOWER_CASE(str[i]);
+      DO_LOWER_CASE_SHIFT0(str[i]);
     }
   } else if (orig->size_shift == 1) {
     p_wchar1 *str = STR1(ret);
@@ -271,7 +327,7 @@ void f_upper_case(INT32 args)
 
     while(i--) {
       if(str[i]!=0xff && str[i]!=0xb5) {
-	DO_UPPER_CASE(str[i]);
+	DO_UPPER_CASE_SHIFT0(str[i]);
       } else {
 	widen = 1;
       }
diff --git a/src/dummy_ci.h b/src/dummy_ci.h
index 8224dd80c4cd7475faf19e4ad91e276a10570ebe..e96837932fe809f4c6df63575ab992a7c2f5aac9 100644
--- a/src/dummy_ci.h
+++ b/src/dummy_ci.h
@@ -1,5 +1,5 @@
 /*
- * $Id: dummy_ci.h,v 1.3 1999/03/20 16:33:34 grubba Exp $
+ * $Id: dummy_ci.h,v 1.4 2000/07/27 17:47:03 lange Exp $
  *
  * Fallback case_info file.
  * Only ISO-8859-1 in this one.
@@ -11,6 +11,8 @@
 { 0x005b, CIM_NONE, 0x0000, },
 { 0x0061, CIM_CASEBIT, 0x0020, },
 { 0x007b, CIM_NONE, 0x0000, },
+{ 0x00b5, CIM_LOWERDELTA, -0x02e7, },
+{ 0x00b6, CIM_NONE, 0x0000, },
 { 0x00c0, CIM_CASEBIT, 0x0020, },
 { 0x00d7, CIM_NONE, 0x0000, },
 { 0x00d8, CIM_CASEBIT, 0x0020, },
@@ -20,3 +22,4 @@
 { 0x00f8, CIM_CASEBIT, 0x0020, },
 { 0x00ff, CIM_LOWERDELTA, -0x0079, },
 { 0x0100, CIM_NONE, 0x0000, },
+#define CASE_INFO_SHIFT0_HIGH 0x000f