1. Си / Говнокод #6241

    +134

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 96
    97. 97
    98. 98
    99. 99
    int _Mbtowcx(wchar_t *pwc, const char *s, size_t nin, mbstate_t *pst, _Statab *pmbstate)
    	char state = (char)pst->_State;
    	unsigned char *su = (unsigned char *)s;
    	wchar_t wc = (wchar_t)pst->_Wchar;
    	static const mbstate_t initial = {0};
    
    	if (pmbstate->_Tab[0] == 0)	{	/* no table, convert from UTF8 */
    		if (s == 0)
    			{	/* set initial state */
    			*pst = initial;
    			return (0);
    			}
    
    		for (; ; ++su, --nin) {	/* consume an input byte */
    			if (nin == 0) {	/* report incomplete conversion */
    				pst->_Wchar = wc;
    				pst->_State = state;
    				return (-2);
    				}
    			else if (0 < state)	{	/* fold in a successor byte */
    				if ((*su & 0xc0) != 0x80) {	/* report invalid sequence */
    					errno = EILSEQ;
    					return (-1);
    					}
    				wc = (wchar_t)((wc << 6) | (*su & 0x3f));
    				--state;
    				}
    			else if ((*su & 0x80) == 0)
    				wc = *su;	/* consume a single byte */
    			else if ((*su & 0xe0) == 0xc0)	{	/* consume first of two bytes */
    				wc = (wchar_t)(*su & 0x1f);
    				state = 1;
    				}
    			else if ((*su & 0xf0) == 0xe0)	{	/* consume first of three bytes */
    				wc = (wchar_t)(*su & 0x0f);
    				state = 2;
    				}
    
    			else{	/* report invalid sequence */
    				errno = EILSEQ;
    				return (-1);
    				}
    			if (state == 0)	{	/* produce an output wchar */
    				if (pwc != 0)
    					*pwc = wc;
    				pst->_State = 0;
    				return (wc == 0 ? 0 : (const char *)++su - s);
    				}
    			}
    
    		}
    	else
    		{	/* run finite state machine */
    		int limit = 0;
    
    		if (s == 0)	{	/* set initial state */
    			*pst = initial;
    			return (pmbstate->_Tab[0][0] & _ST_STATE);
    			}
    
    		for (; ; )	{	/* perform a state transformation */
    			unsigned short code;
    			const unsigned short *stab;
    
    			if (nin == 0)
    				{	/* report incomplete conversion */
    				pst->_Wchar = wc;
    				pst->_State = state;
    				return (-2);
    				}
    			else if (_NSTATE <= state
    				|| (stab = pmbstate->_Tab[state]) == 0
    				|| (_NSTATE*UCHAR_MAX) <= ++limit
    				|| (code = stab[*su]) == 0)
    				{	/* report invalid sequence */
    				errno = EILSEQ;
    				return (-1);
    				}
    			state = (char)((code & _ST_STATE) >> _ST_STOFF);
    			if (code & _ST_FOLD)
    				wc = (wchar_t)(wc & ~UCHAR_MAX | code & _ST_CH);
    			if (code & _ST_ROTATE)
    				wc = (wchar_t)(wc << CHAR_BIT | UCHAR_MAX
    					& wc >> CHAR_BIT * (sizeof (wchar_t) - 1));
    			if (code & _ST_INPUT && *su != '\0')
    				++su, --nin, limit = 0;
    			if (code & _ST_OUTPUT)
    				{	/* produce an output wchar */
    				int nused = (const char *)su - s;
    
    				if (pwc)
    					*pwc = wc;
    				pst->_Wchar = wc;
    				pst->_State = state;
    				return (wc == 0 ? 0 : nused == 0 ? -3 : nused);
    				}
    			}
    		}
    	}

    Долго не мог понять почему не работает
    setlocale(...);
    _setmbcp(...);
    mbtowc(...);

    на C++ Builder. Пока не заглянул в исходники.

    Запостил: sanchousf, 05 Апреля 2011

    Комментарии (17) RSS

    • я ничего не понял.
      Ответить
      • я чо комментишь тады ?
        Ответить
      • Эта функция использует, неведомый мне, алгоритм для преобразования символов из ANSII таблицы в wchar_t, а не с Multi byte в wchar_t. Она ведет себя не так как написано в документации.
        Аналогичная функция с MS Visual Studio делает примерно так
        MultiByteToWideChar( _loc_update.GetLocaleT()->locinfo->lc_codepage,
                                          MB_PRECOMPOSED | MB_ERR_INVALID_CHARS,
                                          s,
                                          _loc_update.GetLocaleT()->locinfo->mb_cur_max,
                                          pwc,
                                          (pwc) ? 1 : 0 )
        Ответить
    • Ну и что? В какой конкретно строчке ошибка?
      Ответить
      • Где-то между первой и второй.
        Ответить
      • Во первых: это же STD. А значит и работать функция должна в соответствии с документацией по C++.

        Во вторых: Реализация. Вот список кодовых таблиц поддерживаемых Виндой
        http://msdn.microsoft.com/en-us/library/dd317756(v=VS.85).aspx
        А в данная функция, вроде бы, поддерживает UTF8 и OEM.
        Зачем придумывать такой алгоритм если надежней воспользоваться функцией MultiByteToWideChar?
        Ответить
        • Такой функции нет в стандарте, это какие-то внутренние детали реализации (и имя на подчёркивание намекает), пользователям о этой функции знать незачем.

          Эта функция как раз и реализует перекодировку из многобайтной кодировки в wchar. Для этого используется конечный автомат, управляемый таблицами (а кроме 8-битных кодировок существуют и многобайтные азиатские кодировки). В частном случае UTF-8 автомат закодирован явно (таблицы были бы слишком большими). Загляните в код iconv (или MultiByteToWideChar) — там увидите ещё сложнее.

          Почему не используется MultiByteToWideChar? Ну, возможно, когда писался этот код, её ещё не было. Или она поддерживала очень ограниченный набор кодировок. Или медленнее. Или часть рантайма MS VС, а не системная.
          Ответить
          • int (mbtowc)(wchar_t *_Restrict pwc, const char *_Restrict s, size_t n)
            	{	/*	determine next multibyte code */
            	int i = _Mbtowc(pwc, s,
            		n <= MB_CUR_MAX ? n : MB_CUR_MAX, _TLS_DATA_PTR(mbst));
            
            	return (i < 0 ? -1 : i);
            	}
            
            int _Mbtowc(wchar_t *pwc, const char *s, size_t nin, mbstate_t *pst)
            	{	/* translate multibyte to widechar using global locale */
            	return (_Mbtowcx(pwc, s, nin, pst, _TLS_DATA_PTR(_Mbstate)));
            	}
            Ответить
            • Нормальный код.
              Ответить
              • Я хотел показать что mbtowc вызывает _Mbtowcx, а mbtowc это STD.
                P. S. Код mbtowc и _Mbtowc приведен полностью
                Ответить
                • Ну так я и не сумневался.

                  Для работы этой перекодировщику нужны ещё таблицы, на которые ссылается pmbstate (они могут занимать сотни килобайт и даже мегабайты). Полюбопытствуйте, разберитесь, как оно работает.
                  Ответить
          • Код взят из Embarcadero RAD Studio 2010
            Ответить
    • - Давай-ка задом, мила, - я шлёпнул Елену по ляжке, и она неловко перевернулась, встала на колени, высоко подняла зад.
      Ответить

    Добавить комментарий