Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
char.cpp
Go to the documentation of this file.
1
27// expand _TEST_EXPORT macros
28#define _RWSTD_TEST_SRC
29
30#include <rw_char.h>
31#include <rw_printf.h> // for rw_snprintfa()
32
33#include <ctype.h> // for isdigit()
34#include <stdarg.h> // for va_arg(), va_list, ...
35#include <stdlib.h> // for strtol()
36#include <string.h> // for memcpy(), strlen(), ...
37
38
39// for convenience
40typedef unsigned char UChar;
41
42
44assign (char_type &dst, const char_type &src)
45{
46 ++n_calls_ [MemFun::assign];
47 Base::assign (dst, src);
48}
49
50
52eq (const char_type &ch1, const char_type &ch2)
53{
54 ++n_calls_ [MemFun::eq];
55 return Base::eq (ch1, ch2);
56}
57
58
60lt (const char_type &ch1, const char_type &ch2)
61{
62 ++n_calls_ [MemFun::lt];
63 return Base::lt (ch1, ch2);
64}
65
66
68compare (const char_type *s1, const char_type *s2, size_t n)
69{
70 ++n_calls_ [MemFun::compare];
71 return Base::compare (s1, s2, n);
72}
73
74
76length (const char_type *s)
77{
78 ++n_calls_ [MemFun::length];
79 return Base::length (s);
80}
81
82
85find (const char_type *s, size_t n, const char_type &ch)
86{
87 ++n_calls_ [MemFun::find];
88 return Base::find (s, n, ch);
89}
90
91
94copy (char_type *dst, const char_type *src, size_t n)
95{
96 ++n_calls_ [MemFun::copy];
97 return Base::copy (dst, src, n);
98}
99
100
103move (char_type *dst, const char_type *src, size_t n)
104{
105 ++n_calls_ [MemFun::move];
106 return Base::move (dst, src, n);
107}
108
109
112assign (char_type *s, size_t n, char_type ch)
113{
114 ++n_calls_ [MemFun::assign];
115 return Base::assign (s, n, ch);
116}
117
118
121not_eof (const int_type &i)
122{
123 ++n_calls_ [MemFun::not_eof];
124 return eof () == i ? ~i : i;
125}
126
127
130to_char_type (const int_type &i)
131{
132 ++n_calls_ [MemFun::to_char_type];
133 return Base::to_char_type (i);
134}
135
136
139to_int_type (const char_type &ch)
140{
141 ++n_calls_ [MemFun::to_int_type];
142 return Base::to_int_type (ch);
143}
144
145
147eq_int_type (const int_type &i1, const int_type &i2)
148{
149 ++n_calls_ [MemFun::eq_int_type];
150 return Base::eq_int_type (i1, i2);
151}
152
153
156eof ()
157{
158 return eof_;
159}
160
161
162size_t UserTraits<char>::
164
165
168eof_ = std::char_traits<char>::eof ();
169
170
171#ifndef _RWSTD_NO_WCHAR_T
172
174assign (char_type &dst, const char_type &src)
175{
176 ++n_calls_ [MemFun::assign];
177 Base::assign (dst, src);
178}
179
180
182eq (const char_type &ch1, const char_type &ch2)
183{
184 ++n_calls_ [MemFun::eq];
185 return Base::eq (ch1, ch2);
186}
187
188
190lt (const char_type &ch1, const char_type &ch2)
191{
192 ++n_calls_ [MemFun::lt];
193 return Base::lt (ch1, ch2);
194}
195
196
198compare (const char_type *s1, const char_type *s2, size_t n)
199{
200 ++n_calls_ [MemFun::compare];
201 return Base::compare (s1, s2, n);
202}
203
204
206length (const char_type *s)
207{
208 ++n_calls_ [MemFun::length];
209 return Base::length (s);
210}
211
212
215find (const char_type *s, size_t n, const char_type &ch)
216{
217 ++n_calls_ [MemFun::find];
218 return Base::find (s, n, ch);
219}
220
221
224copy (char_type *dst, const char_type *src, size_t n)
225{
226 ++n_calls_ [MemFun::copy];
227 return Base::copy (dst, src, n);
228}
229
230
233move (char_type *dst, const char_type *src, size_t n)
234{
235 ++n_calls_ [MemFun::move];
236 return Base::move (dst, src, n);
237}
238
239
242assign (char_type *s, size_t n, char_type ch)
243{
244 ++n_calls_ [MemFun::assign];
245 return Base::assign (s, n, ch);
246}
247
248
251not_eof (const int_type &i)
252{
253 ++n_calls_ [MemFun::not_eof];
254 return eof () == i ? ~i : i;
255}
256
257
260to_char_type (const int_type &i)
261{
262 ++n_calls_ [MemFun::to_char_type];
263 return Base::to_char_type (i);
264}
265
266
269to_int_type (const char_type &ch)
270{
271 ++n_calls_ [MemFun::to_int_type];
272 return Base::to_int_type (ch);
273}
274
275
277eq_int_type (const int_type &i1, const int_type &i2)
278{
279 ++n_calls_ [MemFun::eq_int_type];
280 return Base::eq_int_type (i1, i2);
281}
282
283
286eof ()
287{
288 return eof_;
289}
290
291
292size_t UserTraits<wchar_t>::
294
295
298eof_ = std::char_traits<wchar_t>::eof ();
299
300#endif // _RWSTD_NO_WCHAR_T
301
302
303size_t
306
307
308void
310assign (char_type &c1, const char_type &c2)
311{
312 ++n_calls_ [MemFun::assign];
313
314 c1.f = c2.f;
315 c1.c = c2.c;
316}
317
318
319bool
321eq (const char_type &c1, const char_type &c2)
322{
323 ++n_calls_ [MemFun::eq];
324
325 return c1.f == c2.f && c1.c == c2.c;
326}
327
328
329bool
331lt (const char_type &c1, const char_type &c2)
332{
333 ++n_calls_ [MemFun::lt];
334
335 return c1.f < c2.f || (c1.f == c2.f && c1.c < c2.c);
336}
337
338
340compare (const char_type *s1, const char_type *s2, size_t n)
341{
342 RW_ASSERT (0 == n || (s1 && s2));
343
344 ++n_calls_ [MemFun::compare];
345
346 for (size_t i = 0; i != n; ++i) {
347 if (s1 [i].f != s2 [i].f || s1 [i].c != s2 [i].c) {
348 if ( s1 [i].f < s2 [i].f
349 || (s1 [i].f == s2 [i].f && s1 [i].c < s2 [i].c))
350 return -1;
351
352 return 1;
353 }
354 }
355
356 return 0;
357}
358
359
361length (const char_type *s)
362{
363 RW_ASSERT (0 != s);
364
365 ++n_calls_ [MemFun::length];
366
367 size_t len = 0;
368
369 for (; s [len].f || s [len].c; ++len);
370
371 return len;
372}
373
374
377find (const char_type *s, size_t n, const char_type &c)
378{
379 RW_ASSERT (0 == n || s);
380
381 ++n_calls_ [MemFun::find];
382
383 for (; n--; ++s) {
384 if (s->f == c.f && s->c == c.c)
385 return s;
386 }
387
388 return 0;
389}
390
391
394copy (char_type *dst, const char_type *src, size_t n)
395{
396 RW_ASSERT (0 == n || (dst && src));
397
398 ++n_calls_ [MemFun::copy];
399
400 for (size_t i = 0; i != n; i++)
401 dst [i] = src [i];
402
403 return dst;
404}
405
406
409move (char_type *dst, const char_type *src, size_t n)
410{
411 RW_ASSERT (0 == n || (dst && src));
412
413 ++n_calls_ [MemFun::move];
414
415 if (dst < src) {
416 for (size_t i = 0; i != n; ++i)
417 dst [i] = src [i];
418 }
419 else {
420 while (n--)
421 dst [n] = src [n];
422 }
423
424 return dst;
425}
426
427
430assign (char_type *s, size_t n, char_type c)
431{
432 RW_ASSERT (0 == n || s);
433
434 ++n_calls_ [MemFun::assign2];
435
436 for (; n--; s [n] = c);
437
438 return s;
439}
440
441
444not_eof (const int_type &i)
445{
446 ++n_calls_ [MemFun::not_eof];
447
448 if (i.equal (int_type::eof ())) {
449 const char_type c = { 0, 0 };
450
451 return int_type::from_char (c);
452 }
453
454 return i;
455}
456
457
460to_char_type (const int_type &i)
461{
462 ++n_calls_ [MemFun::to_char_type];
463
464 return i.to_char ();
465}
466
467
470to_int_type (const char_type &c)
471{
472 ++n_calls_ [MemFun::to_int_type];
473
474 return int_type::from_char (c);
475}
476
477
478bool
480eq_int_type (const int_type &i1, const int_type &i2)
481{
482 ++n_calls_ [MemFun::eq_int_type];
483
484 return i1.equal (i2);
485}
486
487
490eof ()
491{
492 ++n_calls_ [MemFun::eof];
493
494 return int_type::eof ();
495}
496
497
500char*
501rw_widen (char *dst, const char *src, size_t len /* = SIZE_MAX */)
502{
503 // compute the length of src if not specified
504 if (_RWSTD_SIZE_MAX == len)
505 len = src ? strlen (src) : 0;
506
507 if (len) {
508 RW_ASSERT (0 != dst);
509
510 if (src) {
511 // copy src into dst
512 memcpy (dst, src, len);
513 dst [len] = '\0';
514 }
515 else {
516 // set dst to all NUL
517 memset (dst, 0, len);
518 }
519 }
520 else if (dst)
521 *dst = '\0';
522
523 return dst;
524}
525
526
528static unsigned long
529_rw_get_char (const char *src, const char** end, size_t *count)
530{
531 RW_ASSERT (0 != src);
532 RW_ASSERT (0 != end);
533 RW_ASSERT (0 != count);
534
535 if (0 == *count) {
536 *end = src;
537 return 0;
538 }
539
540 unsigned long ch = UChar (*src++);
541
542 if (0 == ch && _RWSTD_SIZE_MAX == *count) {
543 // stop at the terminating NUL
544 *end = src;
545 *count = 1;
546 return ch;
547 }
548
549 if ('<' == char (ch) && 'U' == src [0] && isxdigit (src [1])) {
550 // this looks like the beginning of a <Unnn...>
551 // sequence encoding a Unicode character, look
552 // for a sequence of digits followed by the
553 // closing '>'
554
555 char *tmp_end;
556 const unsigned long val = strtoul (src + 1, &tmp_end, 16);
557 if ('>' == *tmp_end) {
558 ch = val;
559 src = tmp_end + 1;
560 }
561 }
562
563 if ('@' == src [0] && isdigit (src [1])) {
564 // <char>@<count> denotes a repeat directive representing
565 // <count> consecutive occurrences of the character <char>
566
567 char* tmp_end;
568 *count = strtoul (src + 1, &tmp_end, 10);
569 src = tmp_end;
570 }
571 else
572 *count = 1;
573
574 *end = src;
575
576 return ch;
577}
578
579
580static void*
581_rw_expand (void *dst, size_t elemsize,
582 const char *src, size_t src_len /* = SIZE_MAX */,
583 size_t *dst_len /* = 0 */)
584{
585 // create a typedef for "genericity"
586#ifndef _RWSTD_NO_WCHAR_T
587 typedef wchar_t WChar;
588#else // if defined (_RWSTD_NO_WCHAR_T)
589 // dummy, will never be used
590 typedef int WChar;
591#endif // _RWSTD_NO_WCHAR_T
592
593 RW_ASSERT ( sizeof (char) == elemsize
594 || sizeof (WChar) == elemsize
595 || sizeof (UserChar) == elemsize);
596
597 if (0 == src) {
598 src = "";
599 src_len = 0;
600 }
601
602 // save the original value of dst and avoid deallocating
603 // it when a large buffer is needed
604 const void* const dst_save = dst;
605
606 // when both dst and dst_size are non-null use *dst_len
607 // as the size of the destination buffer
608 size_t bufsize = dst ? dst_len ? *dst_len : _RWSTD_SIZE_MAX : 0;
609 size_t buflen = 0;
610
611 if (_RWSTD_SIZE_MAX == src_len)
612 src_len = strlen (src);
613
614 void *pnext = dst;
615
616 for (const char *psrc = src; ; ) {
617
618 size_t count = src_len;
619 const char *end = 0;
620 const unsigned long ch = _rw_get_char (psrc, &end, &count);
621
622 const size_t nchars = size_t (end - psrc);
623 if (nchars <= src_len)
624 src_len -= nchars;
625 else
626 src_len = 0;
627
628 psrc = end;
629
630 if (bufsize - buflen <= count) {
631 // increase the size of the buffer
632 bufsize = (bufsize + count) * 2;
633 if (bufsize < 128)
634 bufsize = 128;
635
636 // allocate larger buffer
637 void* tmp;
638
639 switch (elemsize) {
640 case sizeof (WChar): tmp = new WChar [bufsize]; break;
641 case sizeof (UserChar): tmp = new UserChar [bufsize]; break;
642 default: tmp = new char [bufsize]; break;
643 }
644
645 // copy old buffer into new one
646 memcpy (tmp, dst, buflen * elemsize);
647
648 // dispose of previously allocated buffer
649 if (dst != dst_save) {
650 switch (elemsize) {
651 case sizeof (WChar): delete[] (WChar*)dst; break;
652 case sizeof (UserChar): delete[] (UserChar*)dst; break;
653 default: delete[] (char*)dst; break;
654 }
655 }
656
657 dst = tmp;
658
659 pnext = (char*)dst + buflen * elemsize;
660 }
661
662 if (sizeof (WChar) == elemsize) {
663 for (size_t i = 0; i != count; ++i)
664 ((WChar*)pnext)[i] = WChar (ch);
665 }
666 else if (sizeof (UserChar) == elemsize) {
667 for (size_t i = 0; i != count; ++i) {
668 ((UserChar*)pnext)[i].f = 0;
669 ((UserChar*)pnext)[i].c = UChar (ch);
670 }
671 }
672 else if (ch < 0x80U) {
673 memset (pnext, UChar (ch), count);
674 }
675 else {
676#if 1
677 // narrow the wide character to char
678 memset (pnext, UChar (ch), count);
679
680 pnext = (char*)pnext + count * elemsize;
681 buflen += count;
682
683#else // disabled
684
685 // FIXME: enable UCS to UTF-8 conversion
686 // (need to allocate sufficient storage above)
687
688 const char* const pnext_start = pnext;
689
690 // count the number of UTF-8 bytes
691 size_t nbytes = 0;
692
693 for (size_t i = 0; i != count; ++i) {
694 if (ch < 0x800U) {
695 *pnext++ = UChar (0xc0U | (ch >> 6));
696 *pnext++ = UChar (0x80U | (ch & 0x3fU));
697 nbytes += 2;
698 }
699 else if (ch < 0x10000U) {
700 *pnext++ = UChar (0xe0U | (ch >> 12));
701 *pnext++ = UChar (0x80U | (ch >> 6 & 0x3fU));
702 *pnext++ = UChar (0x80U | (ch & 0x3fU));
703 nbytes += 3;
704 }
705 else if (ch < 0x200000U) {
706 *pnext++ = UChar (0xf0U | (ch >> 18));
707 *pnext++ = UChar (0x80U | (ch >> 12 & 0x3fU));
708 *pnext++ = UChar (0x80U | (ch >> 6 & 0x3fU));
709 *pnext++ = UChar (0x80U | (ch & 0x3fU));
710 nbytes += 4;
711 }
712 else if (ch < 0x4000000U) {
713 *pnext++ = UChar (0xf8U | (ch >> 24));
714 *pnext++ = UChar (0x80U | (ch >> 18 & 0x3fU));
715 *pnext++ = UChar (0x80U | (ch >> 12 & 0x3fU));
716 *pnext++ = UChar (0x80U | (ch >> 6 & 0x3fU));
717 *pnext++ = UChar (0x80U | (ch & 0x3fU));
718 nbytes += 5;
719 }
720 else {
721 *pnext++ = UChar (0xfcU | (ch >> 30));
722 *pnext++ = UChar (0x80U | (ch >> 24 & 0x3fU));
723 *pnext++ = UChar (0x80U | (ch >> 18 & 0x3fU));
724 *pnext++ = UChar (0x80U | (ch >> 12 & 0x3fU));
725 *pnext++ = UChar (0x80U | (ch >> 6 & 0x3fU));
726 *pnext++ = UChar (0x80U | (ch & 0x3fU));
727 nbytes += 6;
728 }
729 }
730
731#endif // 0/1
732
733 }
734
735 pnext = (char*)pnext + count * elemsize;
736 buflen += count;
737
738 if (0 == src_len) {
739 memset (pnext, 0, elemsize);
740 break;
741 }
742 }
743
744 if (dst_len)
745 *dst_len = buflen;
746
747 return dst;
748}
749
750
753char*
754rw_expand (char *dst, const char *src, size_t src_len /* = SIZE_MAX */,
755 size_t *dst_len /* = 0 */)
756{
757 void* const result = _rw_expand (dst, sizeof *dst, src, src_len, dst_len);
758
759 return _RWSTD_STATIC_CAST (char*, result);
760}
761
762
764char*
765rw_narrow (char *dst, const char *src, size_t len /* = SIZE_MAX */)
766{
767 return rw_widen (dst, src, len);
768}
769
770
772size_t
773rw_match (const char *s1, const char *s2, size_t len /* = SIZE_MAX */)
774{
775 // the length of the initial subsequence of s1 and s2
776 // consisting solely of characters that compare equal
777 size_t count = 0;
778
779 if (0 == s1) {
780 s1 = s2;
781 s2 = 0;
782 }
783
784 const char* p1 = s1;
785
786 if (0 == s2) {
787 // when one of the strings is null, compute the length
788 // of the other string when all directives are expanded
789 if (0 == s1 || 0 == *s1)
790 return 0;
791
792 do {
793 size_t n = _RWSTD_SIZE_MAX == len ? len : len - count;
794
795 _rw_get_char (p1, &p1, &n);
796
797 count += n;
798 } while (p1 && *p1);
799
800 return count;
801 }
802
803 const char* p2 = s2;
804
805 size_t n1 = 0;
806 size_t n2 = 0;
807
808 for (unsigned long ch1, ch2; count < len; ) {
809
810 while (0 == n1) {
811 n1 = _RWSTD_SIZE_MAX == len ? len : len - count;
812 ch1 = _rw_get_char (p1, &p1, &n1);
813 }
814
815 while (0 == n2) {
816 n2 = _RWSTD_SIZE_MAX == len ? len : len - count;
817 ch2 = _rw_get_char (p2, &p2, &n2);
818 }
819
820 if (ch1 != ch2)
821 break;
822
823 if (n1 < n2) {
824 // the repeat count specified by the first directive
825 // is less than the repeat count given by the second
826 count += n1;
827 n2 -= n1;
828 n1 = 0;
829
830 }
831 else if (n2 <= n1) {
832 // the repeat count specified by the second directive
833 // is less than or equal than that given by the first
834 count += n2;
835 n1 -= n2;
836 n2 = 0;
837 }
838
839 if (_RWSTD_SIZE_MAX == len && 0 == ch1)
840 break;
841 }
842
843 return len < count ? len : count;
844}
845
846
847#ifndef _RWSTD_NO_WCHAR_T
848
850wchar_t*
851rw_widen (wchar_t *dst, const char *src, size_t len /* = SIZE_MAX */)
852{
853 // compute the length of src if not specified
854 if (_RWSTD_SIZE_MAX == len)
855 len = src ? strlen (src) : 0;
856
857 // if len is non-zero dst must be non-0 as well
858 RW_ASSERT (0 == len || 0 != dst);
859
860 if (dst) {
861 if (src) {
862 // widen src into dst one element at a time
863 for (size_t i = 0; ; ++i) {
864 if (i == len) {
865 dst [i] = L'\0';
866 break;
867 }
868
869 dst [i] = wchar_t (UChar (src [i]));
870 }
871 }
872 else {
873 // set dst to all NUL
874 memset (dst, 0, len * sizeof *dst);
875 }
876 }
877
878 return dst;
879}
880
881
883wchar_t*
884rw_expand (wchar_t *dst, const char *src, size_t src_len /* = SIZE_MAX */,
885 size_t *dst_len /* = 0 */)
886{
887 void* const result = _rw_expand (dst, sizeof *dst, src, src_len, dst_len);
888
889 return _RWSTD_STATIC_CAST (wchar_t*, result);
890}
891
892
894char*
895rw_narrow (char *dst, const wchar_t *src, size_t len /* = SIZE_MAX */)
896{
897 // compute the length of src if not specified
898 if (_RWSTD_SIZE_MAX == len) {
899 if (src) {
900 for (len = 0; src [len]; ++len);
901 }
902 else
903 len = 0;
904 }
905
906 // if len is non-zero dst must be non-0 as well
907 RW_ASSERT (0 == len || 0 != dst);
908
909 if (dst) {
910 if (src) {
911 // narrow src into dst one element at a time
912 for (size_t i = 0; ; ++i) {
913 if (i == len) {
914 dst [i] = '\0';
915 break;
916 }
917
918 dst [i] = char (UChar (src [i]));
919 }
920 }
921 else {
922 // set dst to all NUL
923 memset (dst, 0, len);
924 }
925 }
926
927 return dst;
928}
929
930
932size_t
933rw_match (const char *s1, const wchar_t *s2, size_t len /* = SIZE_MAX */)
934{
935 if (0 == s1) {
936 if (s2) {
937 // return the length of s2
938 for (len = 0; s2 [len]; ++len);
939 return len;
940 }
941
942 return 0;
943 }
944
945 if (0 == s2)
946 return rw_match (s1, (char*)0, len);
947
948 const char* p1 = s1;
949 const wchar_t* p2 = s2;
950
951 // the length of the initial subsequence of s1 and s2
952 // consisting solely of characters that compare equal
953 size_t count = 0;
954
955 size_t n1 = 0;
956 size_t n2 = 0;
957
958 for (unsigned long ch1, ch2; count < len; ) {
959
960 while (0 == n1) {
961 n1 = _RWSTD_SIZE_MAX == len ? len : len - count;
962 ch1 = _rw_get_char (p1, &p1, &n1);
963 }
964
965 ch2 = _RWSTD_STATIC_CAST (unsigned long, *p2++);
966 n2 = 1;
967
968 if (ch1 != ch2)
969 break;
970
971 if (n1 < n2) {
972 // the repeat count specified by the first directive
973 // is less than the repeat count given by the second
974 count += n1;
975 n2 -= n1;
976 n1 = 0;
977
978 }
979 else if (n2 <= n1) {
980 // the repeat count specified by the second directive
981 // is less than or equal than that given by the first
982 count += n2;
983 n1 -= n2;
984 n2 = 0;
985 }
986
987 if (_RWSTD_SIZE_MAX == len && L'\0' == ch1)
988 break;
989 }
990
991 return len < count ? len : count;
992}
993
994#endif // _RWSTD_NO_WCHAR_T
995
996
999rw_widen (UserChar *dst, const char *src, size_t len /* = SIZE_MAX */)
1000{
1001 // compute the length of src if not specified
1002 if (_RWSTD_SIZE_MAX == len)
1003 len = src ? strlen (src) : 0;
1004
1005 // if len is non-zero dst must be non-0 as well
1006 RW_ASSERT (0 == len || 0 != dst);
1007
1008 if (dst) {
1009 if (src) {
1010 // widen src into dst one element at a time
1011 for (size_t i = 0; ; ++i) {
1012 if (i == len) {
1013 dst [i] = UserChar::eos ();
1014 break;
1015 }
1016
1017 dst [i].f = 0;
1018 dst [i].c = UChar (src [i]);
1019 }
1020 }
1021 else {
1022 // set dst to all NUL
1023 memset (dst, 0, len * sizeof *dst);
1024 }
1025 }
1026
1027 return dst;
1028}
1029
1030
1032UserChar*
1033rw_expand (UserChar *dst, const char *src, size_t src_len /* = SIZE_MAX */,
1034 size_t *dst_len /* = 0 */)
1035{
1036 void* const result = _rw_expand (dst, sizeof *dst, src, src_len, dst_len);
1037
1039}
1040
1041
1043char*
1044rw_narrow (char *dst, const UserChar *src, size_t len /* = SIZE_MAX */)
1045{
1046 // compute the length of src if not specified
1047 if (_RWSTD_SIZE_MAX == len) {
1048 if (src) {
1049 for (len = 0; src [len].f || src [len].c; ++len);
1050 }
1051 else
1052 len = 0;
1053 }
1054
1055 // if len is non-zero dst must be non-0 as well
1056 RW_ASSERT (0 == len || 0 != dst);
1057
1058 if (dst) {
1059 if (src) {
1060 // narrow src into dst one element at a time
1061 for (size_t i = 0; ; ++i) {
1062 if (i == len) {
1063 dst [i] = '\0';
1064 break;
1065 }
1066
1067 dst [i] = char (src [i].c);
1068 }
1069 }
1070 else {
1071 // set dst to all NUL
1072 memset (dst, 0, len);
1073 }
1074 }
1075
1076 return dst;
1077}
1078
1079
1081size_t
1082rw_match (const char *s1, const UserChar *s2, size_t len /* = SIZE_MAX */)
1083{
1084 if (0 == s1) {
1085 if (s2) {
1086 // return the length of s2
1087 for (len = 0; s2 [len].f || s2 [len].c; ++len);
1088 return len;
1089 }
1090
1091 return 0;
1092 }
1093
1094 if (0 == s2)
1095 return rw_match (s1, (char*)0, len);
1096
1097 const char* p1 = s1;
1098 const UserChar* p2 = s2;
1099
1100 // the length of the initial subsequence of s1 and s2
1101 // consisting solely of characters that compare equal
1102 size_t count = 0;
1103
1104 size_t n1 = 0;
1105 size_t n2 = 0;
1106
1107 unsigned long ch1;
1108
1109 for (UserChar ch2; count < len; ) {
1110
1111 while (0 == n1) {
1112 n1 = _RWSTD_SIZE_MAX == len ? len : len - count;
1113 ch1 = _rw_get_char (p1, &p1, &n1);
1114 }
1115
1116 ch2 = *p2++;
1117 n2 = 1;
1118
1119 if (ch1 != ch2.c)
1120 break;
1121
1122 if (n1 < n2) {
1123 // the repeat count specified by the first directive
1124 // is less than the repeat count given by the second
1125 count += n1;
1126 n2 -= n1;
1127 n1 = 0;
1128
1129 }
1130 else if (n2 <= n1) {
1131 // the repeat count specified by the second directive
1132 // is less than or equal than that given by the first
1133 count += n2;
1134 n1 -= n2;
1135 n2 = 0;
1136 }
1137
1138 if (_RWSTD_SIZE_MAX == len && L'\0' == ch1)
1139 break;
1140 }
1141
1142 return len < count ? len : count;
1143}
1144
1145
1147static int
1148_rw_fmtstringv (char **pbuf, size_t *pbufsize, const char *fmt, va_list va)
1149{
1150 RW_ASSERT (0 != pbuf);
1151 RW_ASSERT (0 != pbufsize);
1152 RW_ASSERT (0 != fmt);
1153
1154 // directive syntax:
1155 // '/' [ '#' ] { '*' | <n> } [ '.' '*' | <n> ] "Gs"
1156
1157 // NOTE:
1158 // leading slash (or any other violation of the "standard" directive
1159 // syntax) prevents the caller from extracting width and precision
1160 // (etc.) from its variable argument list and allows us to do so
1161
1162 static int nested_call;
1163
1164 if (nested_call || '/' != fmt [0])
1165 return _RWSTD_INT_MIN;
1166
1167 ++nested_call;
1168 ++fmt;
1169
1170 va_list* pva = 0;
1171 bool fl_pound = false;
1172 int nelems = -1;
1173 int paramno = -1;
1174 int elemsize = -1;
1175
1176 union UPtr {
1177 const char *pc;
1178 const wchar_t *pwc;
1179 const UserChar *puc;
1180 };
1181
1182 if ('#' == *fmt) {
1183 fl_pound = true;
1184 ++fmt;
1185 }
1186
1187 // saved caller's va_list in case it needs to be restored
1188 // to its orginal state after extracting argument from it
1189 va_list va_save;
1190
1191 if ('*' == *fmt) {
1192 // process element width (i.e., sizeof(charT))
1193 pva = va_arg (va, va_list*);
1194
1195 RW_ASSERT (0 != pva);
1196
1197 _RWSTD_VA_COPY (va_save, *pva);
1198
1199 // extract the width from rw_snprintfa's variable argument
1200 // list pass through to us by the caller
1201 elemsize = va_arg (*pva, int);
1202 ++fmt;
1203 }
1204 else if (isdigit (UChar (*fmt))) {
1205 // process positional parameter or width
1206 char* end = 0;
1207 const int arg = int (strtol (fmt, &end, 10));
1208 if ('$' == *end)
1209 paramno = arg;
1210 else
1211 elemsize = arg;
1212
1213 fmt = end;
1214 }
1215
1216 if ('.' == *fmt) {
1217 // process precision (the length of the array in elements)
1218 if ('*' == *++fmt) {
1219 if (0 == pva) {
1220 pva = va_arg (va, va_list*);
1221
1222 RW_ASSERT (0 != pva);
1223
1224 _RWSTD_VA_COPY (va_save, *pva);
1225 }
1226
1227 // extract the width from rw_snprintfa's variable argument
1228 // list passed through to us by the caller
1229 nelems = va_arg (*pva, int);
1230 ++fmt;
1231 }
1232 else if (isdigit (UChar (*fmt))) {
1233 char* end = 0;
1234 nelems = int (strtol (fmt, &end, 10));
1235 fmt = end;
1236 }
1237 }
1238
1239 // extract the address of the caller's variable argument list
1240 if (0 == pva) {
1241 pva = va_arg (va, va_list*);
1242
1243 RW_ASSERT (0 != pva);
1244
1245 _RWSTD_VA_COPY (va_save, *pva);
1246 }
1247
1248 if ('G' != fmt [0] || 's' != fmt [1] || '\0' != fmt [2]) {
1249
1250 // restore caller's (potentially modified) va_list
1251 _RWSTD_VA_COPY (*pva, va_save);
1252
1253 --nested_call;
1254
1255 // uknown directive, let caller process
1256 return _RWSTD_INT_MIN;
1257 }
1258
1259 // extract a pointer to the first character from rw_snprintfa's
1260 // variable argument list pass through to us by the caller
1261 const UPtr beg = { va_arg (*pva, char*) };
1262
1263 {
1264 // extract the address where to store the extracted argument
1265 // for use by any subsequent positional paramaters
1266 const char** const pparam = va_arg (va, const char**);
1267
1268 RW_ASSERT (0 != pparam);
1269
1270 // store the extracted argument
1271 *pparam = beg.pc;
1272 }
1273
1274 // compute the length of the buffer formatted so far
1275 const size_t buflen_0 = *pbuf ? strlen (*pbuf) : 0;
1276
1277 int nbytes = 0;
1278
1280 // invoke rw_asnprintf() recursively to format our arguments
1281 // and append the result to the end of the buffer; pass the
1282 // value returned from rw_asnprintf() (i.e., the number of
1283 // bytes appended) back to the caller
1284
1285 if (-1 == elemsize || 1 == elemsize) {
1286 if (nelems < 0)
1287 nelems = beg.pc ? int (strlen (beg.pc)) : 0;
1288
1289 nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*s}", nelems, beg.pc);
1290 }
1291 else if (_RWSTD_WCHAR_SIZE == elemsize) {
1292 if (nelems < 0)
1293 nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#ls}", beg.pwc);
1294 else
1295 nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*ls}",
1296 nelems, beg.pwc);
1297 }
1298 else if (sizeof (UserChar) == size_t (elemsize)) {
1299
1300 // narrow the argument into a local buffer of sufficient size
1301 // (dynamically allocating memory only when the length of the
1302 // string exceeds the size of the buffer for efficiency) and formt
1303 // the resulting narrow string
1304 char smallbuf [256];
1305 const size_t len = nelems < 0 ? rw_match (0, beg.puc) : size_t (nelems);
1306 char* const pb = len < sizeof smallbuf ? smallbuf : new char [len + 1];
1307 rw_narrow (pb, beg.puc, len);
1308
1309 if (nelems < 0)
1310 nelems = int (len);
1311
1312 nbytes = rw_asnprintf (pbuf, pbufsize, "%{+}%{#*s}",
1313 nelems, beg.pc ? pb : beg.pc);
1314
1315 if (pb != smallbuf)
1316 delete[] pb;
1317 }
1318 else {
1319 nbytes = rw_asnprintf (pbuf, pbufsize,
1320 "*** %%{/Gs}: bad element size: %d ***",
1321 elemsize);
1322 }
1323
1325
1326 // compute the new length of the buffer
1327 const size_t buflen_1 = *pbuf ? strlen (*pbuf) : 0;
1328
1329 // assert that the function really appended as many characters
1330 // as it said it did (assumes no NULs embedded in the output)
1331 // and that it didn't write past the end of the buffer
1332 RW_ASSERT (buflen_1 == buflen_0 + nbytes);
1333 RW_ASSERT (buflen_1 < *pbufsize);
1334
1335 --nested_call;
1336
1337 return nbytes;
1338}
1339
1340
1341static int
1342_rw_fmtstring (char **pbuf, size_t *pbufsize, const char *fmt, ...)
1343{
1344 va_list va;
1345 va_start (va, fmt);
1346
1347 const int nbytes = _rw_fmtstringv (pbuf, pbufsize, fmt, va);
1348
1349 va_end (va);
1350
1351 return nbytes;
1352}
1353
1354
1355UserCharFmatInit::
1356UserCharFmatInit ()
1357{
1358 // install the formatting callback function
1359 static int format_init = rw_printf ("%{+!}", _rw_fmtstring);
1360
1361 _RWSTD_UNUSED (format_init);
1362}
void count(T, T, const U &,...)
#define c2
Definition 17.names.cpp:253
#define i
Definition 17.names.cpp:126
#define s1
Definition 17.names.cpp:242
#define nchars
Definition 17.names.cpp:502
#define s2
Definition 17.names.cpp:268
#define n2
Definition 17.names.cpp:263
#define f
Definition 17.names.cpp:119
#define c1
Definition 17.names.cpp:227
#define p2
Definition 17.names.cpp:265
#define i2
Definition 17.names.cpp:259
#define i1
Definition 17.names.cpp:233
#define n1
Definition 17.names.cpp:237
#define c
Definition 17.names.cpp:111
#define tmp
Definition 17.names.cpp:553
#define s
#define len
Definition 17.names.cpp:488
#define n
Definition 17.names.cpp:130
#define p1
Definition 17.names.cpp:239
#define val
Definition 17.names.cpp:570
volatile int result
const int end
unsigned short wchar_t
#define va_arg(va, T)
#define va_end(ignore)
#define va_start(va, name)
#define _RWSTD_VA_COPY(va_dst, va_src)
Definition _defs.h:1597
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
unsigned char UChar
Definition char.cpp:40
_TEST_EXPORT size_t rw_match(const char *s1, const char *s2, size_t len)
Definition char.cpp:773
_TEST_EXPORT char * rw_expand(char *dst, const char *src, size_t src_len, size_t *dst_len)
Definition char.cpp:754
_TEST_EXPORT char * rw_narrow(char *dst, const char *src, size_t len)
Definition char.cpp:765
_TEST_EXPORT char * rw_widen(char *dst, const char *src, size_t len)
Definition char.cpp:501
_TEST_EXPORT int rw_printf(const char *,...)
Definition printf.cpp:3412
_TEST_EXPORT int rw_asnprintf(char **pbuf, _RWSTD_SIZE_T *pbufsize, const char *fmt,...)
#define _TEST_EXPORT
Definition rw_testdefs.h:55
#define RW_ASSERT(expr)
unsigned char UChar
Definition collate.cpp:122
unsigned char c
Definition rw_char.h:50
static UserChar eos()
Definition rw_char.h:52
long double f
Definition rw_char.h:43
Base::int_type int_type
Definition rw_char.h:208
Base::char_type char_type
Definition rw_char.h:207
Base::int_type int_type
Definition rw_char.h:279
Base::char_type char_type
Definition rw_char.h:278
int arg
Definition locale.cpp:2806