/*************************************************************** MPU-STR16ING.C This file contains string operation functions for strict UCS-2 strings. PART OF : MPUIO - library . Copyright (C) 2000 - 2026 by Andrey V.Kosteltsev. All Rights Reserved. ***************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include /*************************************************************** mpu_str16cat() Добавляет строку SRC в конец строки DEST. NOTE: ==== Размер памяти, выделенной для размещения строки DEST, должен быть достаточен для размещения двух строк SRC и DEST. Например, код: __mpu_char16_t *dest = MPU_UCS2("string1 "); __mpu_char16_t *src = MPU_UCS2("string2"); mpu_str16cat( dest, src ); даст ошибку на этапе выполнения программы. ***************************************************************/ __mpu_char16_t * mpu_str16cat( __mpu_char16_t *dest, const __mpu_char16_t *src ) { __mpu_char16_t *p = dest + mpu_str16len( dest ); while( (*p++ = *src++) != 0 ) ; return dest; } /*************************************************************** mpu_str16chr() Поиск символа C в первых N символах строки S. ***************************************************************/ __mpu_char16_t * mpu_str16chr( const __mpu_char16_t *s, __mpu_char16_t c ) { do { if( *s == c ) return (__mpu_char16_t *)s; } while( *s++ != 0 ); return NULL; } /*************************************************************** mpu_str16chrnul() Поиск символа C в первых N символах строки S. Если символ не найден, функция возвращает указатель на завершающий нуль( '\0' ). ***************************************************************/ __mpu_char16_t * mpu_str16chrnul( const __mpu_char16_t *s, __mpu_char16_t c ) { while( *s != 0 && *s != c ) ++s; return (__mpu_char16_t *)s; } /*************************************************************** mpu_str16cmp() Сравнивает лексикографически строки S1 и S2. Возвращает значение: меньше нуля, если S1 < S2; равное нулю, если S1 == S2; больше нуля, если S1 > S2. ***************************************************************/ int mpu_str16cmp( const __mpu_char16_t *s1, const __mpu_char16_t *s2 ) { while( *s1 == *s2 ) { if( *s1 == 0 ) return 0; ++s1; ++s2; } return (*s1 < *s2) ? -1 : 1; } /*************************************************************** mpu_str16cpy() Копирует SRC в DEST. ***************************************************************/ __mpu_char16_t * mpu_str16cpy( __mpu_char16_t *dest, const __mpu_char16_t *src ) { __mpu_char16_t *ret = dest; while( (*dest++ = *src++) != 0 ) ; return ret; } /*************************************************************** mpu_str16cspn() Возвращает длину начального сегмента строки S не содержашего ни одного символа из набора REJECT. Завершающий нуль не учитывается. Если S начинается с символа из набора REJECT, то функция возвращает 0. ***************************************************************/ __mpu_size_t mpu_str16cspn( const __mpu_char16_t *s, const __mpu_char16_t *reject ) { const __mpu_char16_t *p = s; while( *p != 0 && mpu_str16chr( reject, *p ) == NULL ) ++p; return (__mpu_size_t)(p - s); } /*************************************************************** mpu_str16len() Возвращает длину строки S. ***************************************************************/ __mpu_size_t mpu_str16len( const __mpu_char16_t *s ) { const __mpu_char16_t *p = s; while( *p != 0 ) ++p; return (__mpu_size_t)(p - s); } /*************************************************************** mpu_str16ncat() Добавляет не более N символов из строки SRC в конец строки DEST. NOTE: ==== Размер памяти, выделенной для размещения строки DEST, должен быть достаточен для размещения строки DEST и еще N символов плюс завершающий нуль. Например, код: __tx_char16_t *dest = MPU_UCS2("string1 "); __tx_char16_t *src = MPU_UCS2("string2"); __tx_str16ncat( dest, src, 7 ); даст ошибку на этапе выполнения программы. ***************************************************************/ __mpu_char16_t * mpu_str16ncat( __mpu_char16_t *dest, const __mpu_char16_t *src, __mpu_size_t n ) { __mpu_char16_t *p = dest + mpu_str16len( dest ); while( n != 0 && *src != 0 ) { *p++ = *src++; --n; } *p = 0; return dest; } /*************************************************************** mpu_str16ncmp() Сравнивает лексикографически не более N символов в строках S1 и S2. Возвращает значение: меньше нуля, если S1 < S2; равное нулю, если S1 == S2; больше нуля, если S1 > S2. ***************************************************************/ int mpu_str16ncmp( const __mpu_char16_t *s1, const __mpu_char16_t *s2, __mpu_size_t n ) { while( n != 0 && *s1 == *s2 ) { if( *s1 == 0 ) return 0; ++s1; ++s2; --n; } if( n == 0 ) return 0; return (*s1 < *s2) ? -1 : 1; } /*************************************************************** mpu_str16ncpy() Копирует не более N символов из SRC в DEST. ***************************************************************/ __mpu_char16_t * mpu_str16ncpy( __mpu_char16_t *dest, const __mpu_char16_t *src, __mpu_size_t n ) { __mpu_char16_t *ret = dest; while( n != 0 && *src != 0 ) { *dest++ = *src++; --n; } while( n != 0 ) { *dest++ = 0; --n; } return ret; } /*************************************************************** mpu_str16nlen() Возвращает число равное длине строки S, но не большее чем MAXLEN. ***************************************************************/ __mpu_size_t mpu_str16nlen( const __mpu_char16_t *s, __mpu_size_t maxlen ) { const __mpu_char16_t *p = s; while( maxlen != 0 && *p != 0 ) { ++p; --maxlen; } return (__mpu_size_t)(p - s); } /*************************************************************** mpu_str16pbrk() Находит первое вхождение любого символа из набора ACCEPT в строке S. ***************************************************************/ __mpu_char16_t * mpu_str16pbrk( const __mpu_char16_t *s, const __mpu_char16_t *accept ) { while( *s != 0 ) { if( mpu_str16chr( accept, *s ) != NULL ) return (__mpu_char16_t *)s; ++s; } return NULL; } /*************************************************************** mpu_str16rchr() Поиск последнего вхождения символа C в строке S. ***************************************************************/ __mpu_char16_t * mpu_str16rchr( const __mpu_char16_t *s, __mpu_char16_t c ) { const __mpu_char16_t *last = NULL; do { if( *s == c ) last = s; } while( *s++ != 0 ); return (__mpu_char16_t *)last; } /*************************************************************** mpu_str16spn() Возвращает длину начального сегмента строки S содержашего только символы из набора ACCEPT. Завершающий нуль не учитывается. Если S начинается с символа, не входящего в набор ACCEPT, то функция возвращает 0. ***************************************************************/ __mpu_size_t mpu_str16spn( const __mpu_char16_t *s, const __mpu_char16_t *accept ) { const __mpu_char16_t *p = s; while( *p != 0 && mpu_str16chr( accept, *p ) != NULL ) ++p; return (__mpu_size_t)(p - s); } /*************************************************************** mpu_str16str() Возвращает указатель на первое вхождение подстроки, адрес которой задается значением параметра NEEDLE, в строке, адрес которой задается значением параметра HAYSTACK. Возвращаемое значение: Указатель по строке HAYSTACK на символ, с которого начинается первое вхождение подстроки NEEDLE в строке HAYSTACK. Значение NULL, если вхождение не найдено. ***************************************************************/ __mpu_char16_t * mpu_str16str( const __mpu_char16_t *haystack, const __mpu_char16_t *needle ) { __mpu_size_t nlen = mpu_str16len( needle ); if( nlen == 0 ) return (__mpu_char16_t *)haystack; while( *haystack != 0 ) { if( *haystack == *needle && mpu_str16ncmp( haystack, needle, nlen ) == 0 ) return (__mpu_char16_t *)haystack; ++haystack; } return NULL; } /*************************************************************** mpu_str16rstr() Возвращает указатель на последнее вхождение подстроки, адрес которой задается значением параметра NEEDLE, в строке, адрес которой задается значением параметра HAYSTACK. Возвращаемое значение: Указатель по строке HAYSTACK на символ, с которого начинается последнее вхождение подстроки NEEDLE в строке HAYSTACK. Значение NULL, если вхождение не найдено. Значение HAYSTACK, если строка NEEDLE пуста. ***************************************************************/ __mpu_char16_t * mpu_str16rstr( const __mpu_char16_t *haystack, const __mpu_char16_t *needle ) { const __mpu_char16_t *last = NULL; const __mpu_char16_t *p = haystack; __mpu_size_t nlen = mpu_str16len( needle ); if( nlen == 0 ) return (__mpu_char16_t *)(haystack + mpu_str16len( haystack )); while( (p = mpu_str16str( p, needle )) != NULL ) { last = p; ++p; } return (__mpu_char16_t *)last; } /*************************************************************** mpu_str16pcpy() Копирует SRC в DEST. Возвращает адрес завершающего нуля в DEST. ***************************************************************/ __mpu_char16_t * mpu_str16pcpy( __mpu_char16_t *dest, const __mpu_char16_t *src ) { while( (*dest = *src) != 0 ) { ++dest; ++src; } return dest; } /*************************************************************** mpu_str16pncpy() Копирует не более N символов из SRC в DEST. Возвращает адрес последнего скопированного символа в DEST. ***************************************************************/ __mpu_char16_t * mpu_str16pncpy( __mpu_char16_t *dest, const __mpu_char16_t *src, __mpu_size_t n ) { __mpu_char16_t *p = dest; __mpu_char16_t *end; while( n != 0 && *src != 0 ) { *p++ = *src++; --n; } if( n == 0 ) return p; end = p; while( n-- != 0 ) *p++ = 0; return end; } /*************************************************************** mpu_str16tok() Разбор строки, расположенной по адресу S, на лексические единицы (tokens). Символы DELIM, находящиеся по адресу DELIM, используются как разделители лексических единиц. Если token заканчивается символом из набора DELIM, то разделитель (непосредственно следующий за token) заменяется нулем ('\0'), а функция mpu_str16tok() возвращает адрес следующего за разделителем символа. Каждый вызов mpu_str16tok() дает один token, и для разбора всей строки надо организовать цикл обращений к функции mpu_str16tok(). Символы в наборе DELIM могут быть разными для каждого вызова функции mpu_str16tok(). NOTE: ==== Функция mpu_str16tok() изменяет содержимое памяти по адресу S. Функция mpu_str16tok() не может использоваться со строками имеющими тип const. Если S равен нулю, SAVE_PTR используется как указатель на следующую стартовую точку разбора. Например: __mpu_char16_t s[] = MPU_UCS2("-abc-=-def"); __mpu_char16_t *sp; x = str16tok( s, "-", &sp ); // x = "abc", sp = "=-def" x = str16tok( NULL, "-=", &sp ); // x = "def", sp = NULL x = str16tok( NULL, "-=", &sp ); // x = NULL В результате содержимое S будет равно S = "-abc\0=-def\0". Возвращаемое значение: Указатель на следующую лексическую единицу или NULL, если таковых не осталось. ***************************************************************/ __mpu_char16_t * mpu_str16tok( __mpu_char16_t *s, const __mpu_char16_t *delim ) { static MPU_THREAD_LOCAL __mpu_char16_t *saveptr; return mpu_str16tok_r( s, delim, &saveptr ); } __mpu_char16_t * mpu_str16tok_r( __mpu_char16_t *s, const __mpu_char16_t *delim, __mpu_char16_t **saveptr ) { __mpu_char16_t *token; if( s == NULL ) s = *saveptr; s += mpu_str16spn( s, delim ); if( *s == 0 ) { *saveptr = s; return NULL; } token = s; s = mpu_str16pbrk( token, delim ); if( s == NULL ) *saveptr = token + mpu_str16len( token ); else { *s = 0; *saveptr = s + 1; } return token; } __mpu_char16_t * mpu_str16ndup( const __mpu_char16_t *s, __mpu_size_t n ) { __mpu_size_t units; __mpu_size_t bytes; __mpu_char16_t *copy; if( s == NULL ) { errno = EINVAL; return NULL; } units = mpu_str16nlen( s, n ); if( units == SIZE_MAX || units + 1 > SIZE_MAX / sizeof( *copy ) ) { errno = ENOMEM; return NULL; } bytes = (units + 1) * sizeof( *copy ); copy = (__mpu_char16_t *)malloc( bytes ); if( copy == NULL ) return NULL; if( units != 0 ) memcpy( copy, s, units * sizeof( *copy ) ); copy[units] = 0; return copy; } __mpu_char16_t * mpu_str16dup( const __mpu_char16_t *s ) { __mpu_size_t units; __mpu_size_t bytes; __mpu_char16_t *copy; if( s == NULL ) { errno = EINVAL; return NULL; } units = mpu_str16len( s ) + 1; if( units > SIZE_MAX / sizeof( *copy ) ) { errno = ENOMEM; return NULL; } bytes = units * sizeof( *copy ); copy = (__mpu_char16_t *)malloc( bytes ); if( copy == NULL ) return NULL; memcpy( copy, s, bytes ); return copy; } __mpu_size_t mpu_ucs2_to_utf8( __mpu_char8_t *dest, const __mpu_char16_t *src, __mpu_size_t nb ) { __mpu_size_t count = 0; while( *src != 0 ) { __mpu_char8_t tmp[4]; __mpu_size_t len; __mpu_char32_t value = (__mpu_char32_t)*src++; if( value >= 0xd800 && value <= 0xdfff ) { errno = EILSEQ; return (__mpu_size_t)-1; } if( __mpu_utf8_encode( value, tmp, &len ) < 0 ) { errno = EILSEQ; return (__mpu_size_t)-1; } if( dest != NULL ) { if( len > nb ) return count; memcpy( dest + count, tmp, len ); nb -= len; } count += len; } if( dest != NULL && nb != 0 ) dest[count] = '\0'; return count; }