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