1 
2 /**
3  * Part of the D programming language runtime library.
4  */
5 
6 /*
7  *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
8  *  Written by Walter Bright
9  *
10  *  This software is provided 'as-is', without any express or implied
11  *  warranty. In no event will the authors be held liable for any damages
12  *  arising from the use of this software.
13  *
14  *  Permission is granted to anyone to use this software for any purpose,
15  *  including commercial applications, and to alter it and redistribute it
16  *  freely, in both source and binary form, subject to the following
17  *  restrictions:
18  *
19  *  o  The origin of this software must not be misrepresented; you must not
20  *     claim that you wrote the original software. If you use this software
21  *     in a product, an acknowledgment in the product documentation would be
22  *     appreciated but is not required.
23  *  o  Altered source versions must be plainly marked as such, and must not
24  *     be misrepresented as being the original software.
25  *  o  This notice may not be removed or altered from any source
26  *     distribution.
27  */
28 
29 module rt.compiler.gdc.rt.aApplyR;
30 
31 /*
32  *  Modified by Sean Kelly <sean@f4.ca> for use with Tango.
33  */
34 
35 /* This code handles decoding UTF strings for foreach_reverse loops.
36  * There are 6 combinations of conversions between char, wchar,
37  * and dchar, and 2 of each of those.
38  */
39 
40 private import rt.compiler.util.utf;
41 
42 /**********************************************/
43 /* 1 argument versions */
44 
45 // dg is D, but _aApplyRcd() is C
46 extern (D) typedef int delegate(void *) dg_t;
47 
48 extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
49 {   int result;
50 
51     debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
52     for (size_t i = aa.length; i != 0; )
53     {   dchar d;
54 
55         i--;
56         d = aa[i];
57         if (d & 0x80)
58         {   char c = cast(char)d;
59             uint j;
60             uint m = 0x3F;
61             d = 0;
62             while ((c & 0xC0) != 0xC0)
63             {   if (i == 0)
64                     onUnicodeError("Invalid UTF-8 sequence", 0);
65                 i--;
66                 d |= (c & 0x3F) << j;
67                 j += 6;
68                 m >>= 1;
69                 c = aa[i];
70             }
71             d |= (c & m) << j;
72         }
73         result = dg(cast(void *)&d);
74         if (result)
75             break;
76     }
77     return result;
78 }
79 
80 unittest
81 {
82     debug(apply) printf("_aApplyRcd1.unittest\n");
83 
84     auto s = "hello"c[];
85     int i;
86 
87     foreach_reverse(dchar d; s)
88     {
89         switch (i)
90         {
91             case 0:     assert(d == 'o'); break;
92             case 1:     assert(d == 'l'); break;
93             case 2:     assert(d == 'l'); break;
94             case 3:     assert(d == 'e'); break;
95             case 4:     assert(d == 'h'); break;
96             default:    assert(0);
97         }
98         i++;
99     }
100     assert(i == 5);
101 
102     s = "a\u1234\U00100456b";
103     i = 0;
104     foreach_reverse(dchar d; s)
105     {
106         //printf("i = %d, d = %x\n", i, d);
107         switch (i)
108         {
109             case 0:     assert(d == 'b'); break;
110             case 1:     assert(d == '\U00100456'); break;
111             case 2:     assert(d == '\u1234'); break;
112             case 3:     assert(d == 'a'); break;
113             default:    assert(0);
114         }
115         i++;
116     }
117     assert(i == 4);
118 }
119 
120 /*****************************/
121 
122 extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
123 {   int result;
124 
125     debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
126     for (size_t i = aa.length; i != 0; )
127     {   dchar d;
128 
129         i--;
130         d = aa[i];
131         if (d >= 0xDC00 && d <= 0xDFFF)
132         {   if (i == 0)
133                 onUnicodeError("Invalid UTF-16 sequence", 0);
134             i--;
135             d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
136         }
137         result = dg(cast(void *)&d);
138         if (result)
139             break;
140     }
141     return result;
142 }
143 
144 unittest
145 {
146     debug(apply) printf("_aApplyRwd1.unittest\n");
147 
148     auto s = "hello"w[];
149     int i;
150 
151     foreach_reverse(dchar d; s)
152     {
153         switch (i)
154         {
155             case 0:     assert(d == 'o'); break;
156             case 1:     assert(d == 'l'); break;
157             case 2:     assert(d == 'l'); break;
158             case 3:     assert(d == 'e'); break;
159             case 4:     assert(d == 'h'); break;
160             default:    assert(0);
161         }
162         i++;
163     }
164     assert(i == 5);
165 
166     s = "a\u1234\U00100456b";
167     i = 0;
168     foreach_reverse(dchar d; s)
169     {
170         //printf("i = %d, d = %x\n", i, d);
171         switch (i)
172         {
173             case 0:     assert(d == 'b'); break;
174             case 1:     assert(d == '\U00100456'); break;
175             case 2:     assert(d == '\u1234'); break;
176             case 3:     assert(d == 'a'); break;
177             default:    assert(0);
178         }
179         i++;
180     }
181     assert(i == 4);
182 }
183 
184 /*****************************/
185 
186 extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
187 {   int result;
188 
189     debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
190     for (size_t i = aa.length; i != 0; )
191     {   dchar d;
192         wchar w;
193 
194         i--;
195         w = aa[i];
196         if (w & 0x80)
197         {   char c = cast(char)w;
198             uint j;
199             uint m = 0x3F;
200             d = 0;
201             while ((c & 0xC0) != 0xC0)
202             {   if (i == 0)
203                     onUnicodeError("Invalid UTF-8 sequence", 0);
204                 i--;
205                 d |= (c & 0x3F) << j;
206                 j += 6;
207                 m >>= 1;
208                 c = aa[i];
209             }
210             d |= (c & m) << j;
211 
212             if (d <= 0xFFFF)
213                 w = cast(wchar) d;
214             else
215             {
216                 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
217                 result = dg(cast(void *)&w);
218                 if (result)
219                     break;
220                 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
221             }
222         }
223         result = dg(cast(void *)&w);
224         if (result)
225             break;
226     }
227     return result;
228 }
229 
230 unittest
231 {
232     debug(apply) printf("_aApplyRcw1.unittest\n");
233 
234     auto s = "hello"c[];
235     int i;
236 
237     foreach_reverse(wchar d; s)
238     {
239         switch (i)
240         {
241             case 0:     assert(d == 'o'); break;
242             case 1:     assert(d == 'l'); break;
243             case 2:     assert(d == 'l'); break;
244             case 3:     assert(d == 'e'); break;
245             case 4:     assert(d == 'h'); break;
246             default:    assert(0);
247         }
248         i++;
249     }
250     assert(i == 5);
251 
252     s = "a\u1234\U00100456b";
253     i = 0;
254     foreach_reverse(wchar d; s)
255     {
256         //printf("i = %d, d = %x\n", i, d);
257         switch (i)
258         {
259             case 0:     assert(d == 'b'); break;
260             case 1:     assert(d == 0xDBC1); break;
261             case 2:     assert(d == 0xDC56); break;
262             case 3:     assert(d == 0x1234); break;
263             case 4:     assert(d == 'a'); break;
264             default:    assert(0);
265         }
266         i++;
267     }
268     assert(i == 5);
269 }
270 
271 /*****************************/
272 
273 extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
274 {   int result;
275 
276     debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
277     for (size_t i = aa.length; i != 0; )
278     {   dchar d;
279         char c;
280 
281         i--;
282         d = aa[i];
283         if (d >= 0xDC00 && d <= 0xDFFF)
284         {   if (i == 0)
285                 onUnicodeError("Invalid UTF-16 sequence", 0);
286             i--;
287             d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
288         }
289 
290         if (d & ~0x7F)
291         {
292             char[4] buf;
293 
294             auto b = toUTF8(buf, d);
295             foreach (char c2; b)
296             {
297                 result = dg(cast(void *)&c2);
298                 if (result)
299                     return result;
300             }
301             continue;
302         }
303         c = cast(char)d;
304         result = dg(cast(void *)&c);
305         if (result)
306             break;
307     }
308     return result;
309 }
310 
311 unittest
312 {
313     debug(apply) printf("_aApplyRwc1.unittest\n");
314 
315     auto s = "hello"w[];
316     int i;
317 
318     foreach_reverse(char d; s)
319     {
320         switch (i)
321         {
322             case 0:     assert(d == 'o'); break;
323             case 1:     assert(d == 'l'); break;
324             case 2:     assert(d == 'l'); break;
325             case 3:     assert(d == 'e'); break;
326             case 4:     assert(d == 'h'); break;
327             default:    assert(0);
328         }
329         i++;
330     }
331     assert(i == 5);
332 
333     s = "a\u1234\U00100456b";
334     i = 0;
335     foreach_reverse(char d; s)
336     {
337         //printf("i = %d, d = %x\n", i, d);
338         switch (i)
339         {
340             case 0:     assert(d == 'b'); break;
341             case 1:     assert(d == 0xF4); break;
342             case 2:     assert(d == 0x80); break;
343             case 3:     assert(d == 0x91); break;
344             case 4:     assert(d == 0x96); break;
345             case 5:     assert(d == 0xE1); break;
346             case 6:     assert(d == 0x88); break;
347             case 7:     assert(d == 0xB4); break;
348             case 8:     assert(d == 'a'); break;
349             default:    assert(0);
350         }
351         i++;
352     }
353     assert(i == 9);
354 }
355 
356 /*****************************/
357 
358 extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
359 {   int result;
360 
361     debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
362     for (size_t i = aa.length; i != 0;)
363     {   dchar d = aa[--i];
364         char c;
365 
366         if (d & ~0x7F)
367         {
368             char[4] buf;
369 
370             auto b = toUTF8(buf, d);
371             foreach (char c2; b)
372             {
373                 result = dg(cast(void *)&c2);
374                 if (result)
375                     return result;
376             }
377             continue;
378         }
379         else
380         {
381             c = cast(char)d;
382         }
383         result = dg(cast(void *)&c);
384         if (result)
385             break;
386     }
387     return result;
388 }
389 
390 unittest
391 {
392     debug(apply) printf("_aApplyRdc1.unittest\n");
393 
394     auto s = "hello"d[];
395     int i;
396 
397     foreach_reverse(char d; s)
398     {
399         switch (i)
400         {
401             case 0:     assert(d == 'o'); break;
402             case 1:     assert(d == 'l'); break;
403             case 2:     assert(d == 'l'); break;
404             case 3:     assert(d == 'e'); break;
405             case 4:     assert(d == 'h'); break;
406             default:    assert(0);
407         }
408         i++;
409     }
410     assert(i == 5);
411 
412     s = "a\u1234\U00100456b";
413     i = 0;
414     foreach_reverse(char d; s)
415     {
416         //printf("i = %d, d = %x\n", i, d);
417         switch (i)
418         {
419             case 0:     assert(d == 'b'); break;
420             case 1:     assert(d == 0xF4); break;
421             case 2:     assert(d == 0x80); break;
422             case 3:     assert(d == 0x91); break;
423             case 4:     assert(d == 0x96); break;
424             case 5:     assert(d == 0xE1); break;
425             case 6:     assert(d == 0x88); break;
426             case 7:     assert(d == 0xB4); break;
427             case 8:     assert(d == 'a'); break;
428             default:    assert(0);
429         }
430         i++;
431     }
432     assert(i == 9);
433 }
434 
435 /*****************************/
436 
437 extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
438 {   int result;
439 
440     debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
441     for (size_t i = aa.length; i != 0; )
442     {   dchar d = aa[--i];
443         wchar w;
444 
445         if (d <= 0xFFFF)
446             w = cast(wchar) d;
447         else
448         {
449             w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
450             result = dg(cast(void *)&w);
451             if (result)
452                 break;
453             w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
454         }
455         result = dg(cast(void *)&w);
456         if (result)
457             break;
458     }
459     return result;
460 }
461 
462 unittest
463 {
464     debug(apply) printf("_aApplyRdw1.unittest\n");
465 
466     auto s = "hello"d[];
467     int i;
468 
469     foreach_reverse(wchar d; s)
470     {
471         switch (i)
472         {
473             case 0:     assert(d == 'o'); break;
474             case 1:     assert(d == 'l'); break;
475             case 2:     assert(d == 'l'); break;
476             case 3:     assert(d == 'e'); break;
477             case 4:     assert(d == 'h'); break;
478             default:    assert(0);
479         }
480         i++;
481     }
482     assert(i == 5);
483 
484     s = "a\u1234\U00100456b";
485     i = 0;
486     foreach_reverse(wchar d; s)
487     {
488         //printf("i = %d, d = %x\n", i, d);
489         switch (i)
490         {
491             case 0:     assert(d == 'b'); break;
492             case 1:     assert(d == 0xDBC1); break;
493             case 2:     assert(d == 0xDC56); break;
494             case 3:     assert(d == 0x1234); break;
495             case 4:     assert(d == 'a'); break;
496             default:    assert(0);
497         }
498         i++;
499     }
500     assert(i == 5);
501 }
502 
503 
504 /****************************************************************************/
505 /* 2 argument versions */
506 
507 // dg is D, but _aApplyRcd2() is C
508 extern (D) typedef int delegate(void *, void *) dg2_t;
509 
510 extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
511 {   int result;
512     size_t i;
513     size_t len = aa.length;
514 
515     debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
516     for (i = len; i != 0; )
517     {   dchar d;
518 
519         i--;
520         d = aa[i];
521         if (d & 0x80)
522         {   char c = cast(char)d;
523             uint j;
524             uint m = 0x3F;
525             d = 0;
526             while ((c & 0xC0) != 0xC0)
527             {   if (i == 0)
528                     onUnicodeError("Invalid UTF-8 sequence", 0);
529                 i--;
530                 d |= (c & 0x3F) << j;
531                 j += 6;
532                 m >>= 1;
533                 c = aa[i];
534             }
535             d |= (c & m) << j;
536         }
537         result = dg(&i, cast(void *)&d);
538         if (result)
539             break;
540     }
541     return result;
542 }
543 
544 unittest
545 {
546     debug(apply) printf("_aApplyRcd2.unittest\n");
547 
548     auto s = "hello"c[];
549     int i;
550 
551     foreach_reverse(k, dchar d; s)
552     {
553         assert(k == 4 - i);
554         switch (i)
555         {
556             case 0:     assert(d == 'o'); break;
557             case 1:     assert(d == 'l'); break;
558             case 2:     assert(d == 'l'); break;
559             case 3:     assert(d == 'e'); break;
560             case 4:     assert(d == 'h'); break;
561             default:    assert(0);
562         }
563         i++;
564     }
565     assert(i == 5);
566 
567     s = "a\u1234\U00100456b";
568     i = 0;
569     foreach_reverse(k, dchar d; s)
570     {
571         //printf("i = %d, k = %d, d = %x\n", i, k, d);
572         switch (i)
573         {
574             case 0:     assert(d == 'b'); assert(k == 8); break;
575             case 1:     assert(d == '\U00100456'); assert(k == 4); break;
576             case 2:     assert(d == '\u1234'); assert(k == 1); break;
577             case 3:     assert(d == 'a'); assert(k == 0); break;
578             default:    assert(0);
579         }
580         i++;
581     }
582     assert(i == 4);
583 }
584 
585 /*****************************/
586 
587 extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
588 {   int result;
589 
590     debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
591     for (size_t i = aa.length; i != 0; )
592     {   dchar d;
593 
594         i--;
595         d = aa[i];
596         if (d >= 0xDC00 && d <= 0xDFFF)
597         {   if (i == 0)
598                 onUnicodeError("Invalid UTF-16 sequence", 0);
599             i--;
600             d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
601         }
602         result = dg(&i, cast(void *)&d);
603         if (result)
604             break;
605     }
606     return result;
607 }
608 
609 unittest
610 {
611     debug(apply) printf("_aApplyRwd2.unittest\n");
612 
613     auto s = "hello"w[];
614     int i;
615 
616     foreach_reverse(k, dchar d; s)
617     {
618         //printf("i = %d, k = %d, d = %x\n", i, k, d);
619         assert(k == 4 - i);
620         switch (i)
621         {
622             case 0:     assert(d == 'o'); break;
623             case 1:     assert(d == 'l'); break;
624             case 2:     assert(d == 'l'); break;
625             case 3:     assert(d == 'e'); break;
626             case 4:     assert(d == 'h'); break;
627             default:    assert(0);
628         }
629         i++;
630     }
631     assert(i == 5);
632 
633     s = "a\u1234\U00100456b";
634     i = 0;
635     foreach_reverse(k, dchar d; s)
636     {
637         //printf("i = %d, k = %d, d = %x\n", i, k, d);
638         switch (i)
639         {
640             case 0:     assert(k == 4); assert(d == 'b'); break;
641             case 1:     assert(k == 2); assert(d == '\U00100456'); break;
642             case 2:     assert(k == 1); assert(d == '\u1234'); break;
643             case 3:     assert(k == 0); assert(d == 'a'); break;
644             default:    assert(0);
645         }
646         i++;
647     }
648     assert(i == 4);
649 }
650 
651 /*****************************/
652 
653 extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
654 {   int result;
655 
656     debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
657     for (size_t i = aa.length; i != 0; )
658     {   dchar d;
659         wchar w;
660 
661         i--;
662         w = aa[i];
663         if (w & 0x80)
664         {   char c = cast(char)w;
665             uint j;
666             uint m = 0x3F;
667             d = 0;
668             while ((c & 0xC0) != 0xC0)
669             {   if (i == 0)
670                     onUnicodeError("Invalid UTF-8 sequence", 0);
671                 i--;
672                 d |= (c & 0x3F) << j;
673                 j += 6;
674                 m >>= 1;
675                 c = aa[i];
676             }
677             d |= (c & m) << j;
678 
679             if (d <= 0xFFFF)
680                 w = cast(wchar) d;
681             else
682             {
683                 w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
684                 result = dg(&i, cast(void *)&w);
685                 if (result)
686                     break;
687                 w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
688             }
689         }
690         result = dg(&i, cast(void *)&w);
691         if (result)
692             break;
693     }
694     return result;
695 }
696 
697 unittest
698 {
699     debug(apply) printf("_aApplyRcw2.unittest\n");
700 
701     auto s = "hello"c[];
702     int i;
703 
704     foreach_reverse(k, wchar d; s)
705     {
706         //printf("i = %d, k = %d, d = %x\n", i, k, d);
707         assert(k == 4 - i);
708         switch (i)
709         {
710             case 0:     assert(d == 'o'); break;
711             case 1:     assert(d == 'l'); break;
712             case 2:     assert(d == 'l'); break;
713             case 3:     assert(d == 'e'); break;
714             case 4:     assert(d == 'h'); break;
715             default:    assert(0);
716         }
717         i++;
718     }
719     assert(i == 5);
720 
721     s = "a\u1234\U00100456b";
722     i = 0;
723     foreach_reverse(k, wchar d; s)
724     {
725         //printf("i = %d, k = %d, d = %x\n", i, k, d);
726         switch (i)
727         {
728             case 0:     assert(k == 8); assert(d == 'b'); break;
729             case 1:     assert(k == 4); assert(d == 0xDBC1); break;
730             case 2:     assert(k == 4); assert(d == 0xDC56); break;
731             case 3:     assert(k == 1); assert(d == 0x1234); break;
732             case 4:     assert(k == 0); assert(d == 'a'); break;
733             default:    assert(0);
734         }
735         i++;
736     }
737     assert(i == 5);
738 }
739 
740 /*****************************/
741 
742 extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
743 {   int result;
744 
745     debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
746     for (size_t i = aa.length; i != 0; )
747     {   dchar d;
748         char c;
749 
750         i--;
751         d = aa[i];
752         if (d >= 0xDC00 && d <= 0xDFFF)
753         {   if (i == 0)
754                 onUnicodeError("Invalid UTF-16 sequence", 0);
755             i--;
756             d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
757         }
758 
759         if (d & ~0x7F)
760         {
761             char[4] buf;
762 
763             auto b = toUTF8(buf, d);
764             foreach (char c2; b)
765             {
766                 result = dg(&i, cast(void *)&c2);
767                 if (result)
768                     return result;
769             }
770             continue;
771         }
772         c = cast(char)d;
773         result = dg(&i, cast(void *)&c);
774         if (result)
775             break;
776     }
777     return result;
778 }
779 
780 unittest
781 {
782     debug(apply) printf("_aApplyRwc2.unittest\n");
783 
784     auto s = "hello"w[];
785     int i;
786 
787     foreach_reverse(k, char d; s)
788     {
789         //printf("i = %d, k = %d, d = %x\n", i, k, d);
790         assert(k == 4 - i);
791         switch (i)
792         {
793             case 0:     assert(d == 'o'); break;
794             case 1:     assert(d == 'l'); break;
795             case 2:     assert(d == 'l'); break;
796             case 3:     assert(d == 'e'); break;
797             case 4:     assert(d == 'h'); break;
798             default:    assert(0);
799         }
800         i++;
801     }
802     assert(i == 5);
803 
804     s = "a\u1234\U00100456b";
805     i = 0;
806     foreach_reverse(k, char d; s)
807     {
808         //printf("i = %d, k = %d, d = %x\n", i, k, d);
809         switch (i)
810         {
811             case 0:     assert(k == 4); assert(d == 'b'); break;
812             case 1:     assert(k == 2); assert(d == 0xF4); break;
813             case 2:     assert(k == 2); assert(d == 0x80); break;
814             case 3:     assert(k == 2); assert(d == 0x91); break;
815             case 4:     assert(k == 2); assert(d == 0x96); break;
816             case 5:     assert(k == 1); assert(d == 0xE1); break;
817             case 6:     assert(k == 1); assert(d == 0x88); break;
818             case 7:     assert(k == 1); assert(d == 0xB4); break;
819             case 8:     assert(k == 0); assert(d == 'a'); break;
820             default:    assert(0);
821         }
822         i++;
823     }
824     assert(i == 9);
825 }
826 
827 /*****************************/
828 
829 extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
830 {   int result;
831 
832     debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
833     for (size_t i = aa.length; i != 0; )
834     {   dchar d = aa[--i];
835         char c;
836 
837         if (d & ~0x7F)
838         {
839             char[4] buf;
840 
841             auto b = toUTF8(buf, d);
842             foreach (char c2; b)
843             {
844                 result = dg(&i, cast(void *)&c2);
845                 if (result)
846                     return result;
847             }
848             continue;
849         }
850         else
851         {   c = cast(char)d;
852         }
853         result = dg(&i, cast(void *)&c);
854         if (result)
855             break;
856     }
857     return result;
858 }
859 
860 unittest
861 {
862     debug(apply) printf("_aApplyRdc2.unittest\n");
863 
864     auto s = "hello"d[];
865     int i;
866 
867     foreach_reverse(k, char d; s)
868     {
869         //printf("i = %d, k = %d, d = %x\n", i, k, d);
870         assert(k == 4 - i);
871         switch (i)
872         {
873             case 0:     assert(d == 'o'); break;
874             case 1:     assert(d == 'l'); break;
875             case 2:     assert(d == 'l'); break;
876             case 3:     assert(d == 'e'); break;
877             case 4:     assert(d == 'h'); break;
878             default:    assert(0);
879         }
880         i++;
881     }
882     assert(i == 5);
883 
884     s = "a\u1234\U00100456b";
885     i = 0;
886     foreach_reverse(k, char d; s)
887     {
888         //printf("i = %d, k = %d, d = %x\n", i, k, d);
889         switch (i)
890         {
891             case 0:     assert(k == 3); assert(d == 'b'); break;
892             case 1:     assert(k == 2); assert(d == 0xF4); break;
893             case 2:     assert(k == 2); assert(d == 0x80); break;
894             case 3:     assert(k == 2); assert(d == 0x91); break;
895             case 4:     assert(k == 2); assert(d == 0x96); break;
896             case 5:     assert(k == 1); assert(d == 0xE1); break;
897             case 6:     assert(k == 1); assert(d == 0x88); break;
898             case 7:     assert(k == 1); assert(d == 0xB4); break;
899             case 8:     assert(k == 0); assert(d == 'a'); break;
900             default:    assert(0);
901         }
902         i++;
903     }
904     assert(i == 9);
905 }
906 
907 /*****************************/
908 
909 extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
910 {   int result;
911 
912     debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
913     for (size_t i = aa.length; i != 0; )
914     {   dchar d = aa[--i];
915         wchar w;
916 
917         if (d <= 0xFFFF)
918             w = cast(wchar) d;
919         else
920         {
921             w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
922             result = dg(&i, cast(void *)&w);
923             if (result)
924                 break;
925             w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
926         }
927         result = dg(&i, cast(void *)&w);
928         if (result)
929             break;
930     }
931     return result;
932 }
933 
934 unittest
935 {
936     debug(apply) printf("_aApplyRdw2.unittest\n");
937 
938     auto s = "hello"d[];
939     int i;
940 
941     foreach_reverse(k, wchar d; s)
942     {
943         //printf("i = %d, k = %d, d = %x\n", i, k, d);
944         assert(k == 4 - i);
945         switch (i)
946         {
947             case 0:     assert(d == 'o'); break;
948             case 1:     assert(d == 'l'); break;
949             case 2:     assert(d == 'l'); break;
950             case 3:     assert(d == 'e'); break;
951             case 4:     assert(d == 'h'); break;
952             default:    assert(0);
953         }
954         i++;
955     }
956     assert(i == 5);
957 
958     s = "a\u1234\U00100456b";
959     i = 0;
960     foreach_reverse(k, wchar d; s)
961     {
962         //printf("i = %d, k = %d, d = %x\n", i, k, d);
963         switch (i)
964         {
965             case 0:     assert(k == 3); assert(d == 'b'); break;
966             case 1:     assert(k == 2); assert(d == 0xDBC1); break;
967             case 2:     assert(k == 2); assert(d == 0xDC56); break;
968             case 3:     assert(k == 1); assert(d == 0x1234); break;
969             case 4:     assert(k == 0); assert(d == 'a'); break;
970             default:    assert(0);
971         }
972         i++;
973     }
974     assert(i == 5);
975 }