static char* validate_fname(char* name) { char* fname; char* p; char* q; unsigned code; int sz = strlen(name); q = fname = malloc(sz + 1); p = name; while (*p) { code = utf8_get_char(&p); if (code == 0) break; if ( (code > 0x7F) || (code == '\\') || (code == '/') || (code == ':') || (code == '*') || (code == '?') || (code == '<') || (code == '>') || (code == '|') || (code == 0)) { *q++ = '_'; } else { *q++ = code; } if (p - name > sz) break; } *q = 0; return fname; }
STATIC void uni_print_json(void (*print)(void *env, const char *fmt, ...), void *env, const byte *str_data, uint str_len) { print(env, "\""); const byte *s = str_data, *top = str_data + str_len; while (s < top) { unichar ch; ch = utf8_get_char(s); s = utf8_next_char(s); if (ch == '"' || ch == '\\' || ch == '/') { print(env, "\\%c", ch); } else if (32 <= ch && ch <= 126) { print(env, "%c", ch); } else if (*s == '\b') { print(env, "\\b"); } else if (*s == '\f') { print(env, "\\f"); } else if (*s == '\n') { print(env, "\\n"); } else if (*s == '\r') { print(env, "\\r"); } else if (*s == '\t') { print(env, "\\t"); } else { print(env, "\\u%04x", ch); } } print(env, "\""); }
int main(int argc, char* argv[]) { int i = 0; unsigned short codes[] = {0x9690, 0x5f0f, 0x58f0, 0x660e, 0x4e0e, 0x5185, 0x5efa, 0x51fd, 0x6570}; const char* str = "隐式声明与内建函数"; const char* p = str; for(i = 0; *p; i++) { assert(codes[i] == utf8_get_char(p, &p)); assert(codes[i] == utf8_get_prev_char(p, NULL)); } assert(utf8_count_char(str, strlen(str)) == 9); str = "abc"; assert(utf8_count_char(str, strlen(str)) == 3); str = "abc中国"; assert(utf8_count_char(str, strlen(str)) == 5); str = "abc中国"; assert(utf8_count_char(str, 3) == 3); test_normalize_path(); test_ftk_strs_cat(); test_atoi_itoa(); test_atof_ftoa(); test_ftk_parse_color(); test_strtol(); return 0; }
static void utf8towcs(wchar_t *o, const char *src) { for( ; *src; ) { int wc; src = utf8_get_char(src, &wc); *o++ = wc; } *o = 0; }
int main(int argc, char* argv[]) { int i = 0; unsigned short codes[] = {0x9690, 0x5f0f, 0x58f0, 0x660e, 0x4e0e, 0x5185, 0x5efa, 0x51fd, 0x6570}; const char* str = "隐式声明与内建函数"; const char* p = str; for(i = 0; *p; i++) { assert(codes[i] == utf8_get_char(p, &p)); } return 0; }
unicode_type_t _PL__utf8_type(const char *in, size_t len) { const char *end = &in[len]; int type = S_ASCII; while ( in < end ) { int chr; in = utf8_get_char(in, &chr); if (chr > 255) return S_WIDE; if (chr > 127) type = S_LATIN; } return type; }
void mp_token_show(const mp_token_t *tok) { printf("(%d:%d) kind:%d str:%p len:%d", tok->src_line, tok->src_column, tok->kind, tok->str, tok->len); if (tok->str != NULL && tok->len > 0) { const byte *i = (const byte *)tok->str; const byte *j = (const byte *)i + tok->len; printf(" "); while (i < j) { unichar c = utf8_get_char(i); i = utf8_next_char(i); if (unichar_isprint(c)) { printf("%c", c); } else { printf("?"); } } } printf("\n"); }
void mp_lexer_show_token(const mp_lexer_t *lex) { printf("(" UINT_FMT ":" UINT_FMT ") kind:%u str:%p len:%zu", lex->tok_line, lex->tok_column, lex->tok_kind, lex->vstr.buf, lex->vstr.len); if (lex->vstr.len > 0) { const byte *i = (const byte *)lex->vstr.buf; const byte *j = (const byte *)i + lex->vstr.len; printf(" "); while (i < j) { unichar c = utf8_get_char(i); i = utf8_next_char(i); if (unichar_isprint(c)) { printf("%c", c); } else { printf("?"); } } } printf("\n"); }
STATIC void uni_print_quoted(const mp_print_t *print, const byte *str_data, uint str_len) { // this escapes characters, but it will be very slow to print (calling print many times) bool has_single_quote = false; bool has_double_quote = false; for (const byte *s = str_data, *top = str_data + str_len; !has_double_quote && s < top; s++) { if (*s == '\'') { has_single_quote = true; } else if (*s == '"') { has_double_quote = true; } } unichar quote_char = '\''; if (has_single_quote && !has_double_quote) { quote_char = '"'; } mp_printf(print, "%c", quote_char); const byte *s = str_data, *top = str_data + str_len; while (s < top) { unichar ch; ch = utf8_get_char(s); s = utf8_next_char(s); if (ch == quote_char) { mp_printf(print, "\\%c", quote_char); } else if (ch == '\\') { mp_print_str(print, "\\\\"); } else if (32 <= ch && ch <= 126) { mp_printf(print, "%c", ch); } else if (ch == '\n') { mp_print_str(print, "\\n"); } else if (ch == '\r') { mp_print_str(print, "\\r"); } else if (ch == '\t') { mp_print_str(print, "\\t"); } else if (ch < 0x100) { mp_printf(print, "\\x%02x", ch); } else if (ch < 0x10000) { mp_printf(print, "\\u%04x", ch); } else { mp_printf(print, "\\U%08x", ch); } } mp_printf(print, "%c", quote_char); }
void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RString &sTexturePath, const RString &sPageName, RString sChars ) { cfg.m_sTexturePath = sTexturePath; /* If we have any characters to map, add them. */ for( unsigned n=0; n<sChars.size(); n++ ) { char c = sChars[n]; cfg.CharToGlyphNo[c] = n; } int iNumFramesWide, iNumFramesHigh; RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &iNumFramesWide, &iNumFramesHigh ); int iNumFrames = iNumFramesWide * iNumFramesHigh; ini.RenameKey("Char Widths", "main"); // LOG->Trace("Loading font page '%s' settings from page name '%s'", // TexturePath.c_str(), sPageName.c_str()); ini.GetValue( sPageName, "DrawExtraPixelsLeft", cfg.m_iDrawExtraPixelsLeft ); ini.GetValue( sPageName, "DrawExtraPixelsRight", cfg.m_iDrawExtraPixelsRight ); ini.GetValue( sPageName, "AddToAllWidths", cfg.m_iAddToAllWidths ); ini.GetValue( sPageName, "ScaleAllWidthsBy", cfg.m_fScaleAllWidthsBy ); ini.GetValue( sPageName, "LineSpacing", cfg.m_iLineSpacing ); ini.GetValue( sPageName, "Top", cfg.m_iTop ); ini.GetValue( sPageName, "Baseline", cfg.m_iBaseline ); ini.GetValue( sPageName, "DefaultWidth", cfg.m_iDefaultWidth ); ini.GetValue( sPageName, "AdvanceExtraPixels", cfg.m_iAdvanceExtraPixels ); ini.GetValue( sPageName, "TextureHints", cfg.m_sTextureHints ); /* Iterate over all keys. */ const XNode* pNode = ini.GetChild( sPageName ); if( pNode ) { FOREACH_CONST_Attr( pNode, pAttr ) { RString sName = pAttr->first; const XNodeValue *pValue = pAttr->second; sName.MakeUpper(); /* If val is an integer, it's a width, eg. "10=27". */ if( IsAnInt(sName) ) { cfg.m_mapGlyphWidths[atoi(sName)] = pValue->GetValue<int>(); continue; } /* "map codepoint=frame" maps a char to a frame. */ if( sName.substr(0, 4) == "MAP " ) { /* * map CODEPOINT=frame. CODEPOINT can be * 1. U+hexval * 2. an alias ("oq") * 3. a character in quotes ("X") * * map 1=2 is the same as * range unicode #1-1=2 */ RString sCodepoint = sName.substr(4); /* "CODEPOINT" */ wchar_t c; if( sCodepoint.substr(0, 2) == "U+" && IsHexVal(sCodepoint.substr(2)) ) sscanf( sCodepoint.substr(2).c_str(), "%x", &c ); else if( sCodepoint.size() > 0 && utf8_get_char_len(sCodepoint[0]) == int(sCodepoint.size()) ) { c = utf8_get_char( sCodepoint.c_str() ); if(c == wchar_t(-1)) LOG->Warn("Font definition '%s' has an invalid value '%s'.", ini.GetPath().c_str(), sName.c_str() ); } else if( !FontCharAliases::GetChar(sCodepoint, c) ) { LOG->Warn("Font definition '%s' has an invalid value '%s'.", ini.GetPath().c_str(), sName.c_str() ); continue; } cfg.CharToGlyphNo[c] = pValue->GetValue<int>(); continue; } if( sName.substr(0, 6) == "RANGE " ) { /* * range CODESET=first_frame or * range CODESET #start-end=first_frame * eg * range CP1252=0 (default for 256-frame fonts) * range ASCII=0 (default for 128-frame fonts) * * (Start and end are in hex.) * * Map two high-bit portions of ISO-8859- to one font: * range ISO-8859-2 #80-FF=0 * range ISO-8859-3 #80-FF=128 * * Map hiragana to 0-84: * range Unicode #3041-3094=0 */ vector<RString> asMatches; static Regex parse("^RANGE ([A-Z0-9\\-]+)( ?#([0-9A-F]+)-([0-9A-F]+))?$"); bool bMatch = parse.Compare( sName, asMatches ); ASSERT( asMatches.size() == 4 ); /* 4 parens */ if( !bMatch || asMatches[0].empty() ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": parse error.", ini.GetPath().c_str(), sName.c_str() ); /* We must have either 1 match (just the codeset) or 4 (the whole thing). */ int iCount = -1; int iFirst = 0; if( !asMatches[2].empty() ) { sscanf( asMatches[2].c_str(), "%x", &iFirst ); int iLast; sscanf( asMatches[3].c_str(), "%x", &iLast ); if( iLast < iFirst ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %i < %i.", ini.GetPath().c_str(), sName.c_str(), iLast, iFirst ); iCount = iLast - iFirst + 1; } RString sRet = cfg.MapRange( asMatches[0], iFirst, pValue->GetValue<int>(), iCount ); if( !sRet.empty() ) RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %s.", ini.GetPath().c_str(), sName.c_str(), sRet.c_str() ); continue; } if( sName.substr(0, 5) == "LINE " ) { /* line ROW=CHAR1CHAR2CHAR3CHAR4 * eg. * line 0=ABCDEFGH * * This lets us assign characters very compactly and readably. */ RString sRowStr = sName.substr(5); TrimLeft( sRowStr ); ASSERT( IsAnInt(sRowStr) ); const int iRow = atoi( sRowStr.c_str() ); const int iFirstFrame = iRow * iNumFramesWide; if( iRow > iNumFramesHigh ) RageException::Throw( "The font definition \"%s\" tries to assign line %i, but the font is only %i characters high.", ini.GetPath().c_str(), iFirstFrame, iNumFramesHigh ); /* Decode the string. */ const wstring wdata( RStringToWstring(pValue->GetValue<RString>()) ); if( int(wdata.size()) > iNumFramesWide ) RageException::Throw( "The font definition \"%s\" assigns %i characters to row %i (\"%ls\"), but the font is only %i characters wide.", ini.GetPath().c_str(), (int)wdata.size(), iRow, wdata.c_str(), iNumFramesWide ); for( unsigned i = 0; i < wdata.size(); ++i ) cfg.CharToGlyphNo[wdata[i]] = iFirstFrame+i; } } }
void TitleSubst::Load(const CString &filename, const CString §ion) { RageFile f; if( !f.Open(filename) ) { LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() ); return; } CString CurrentSection; TitleTrans tr; while (!f.AtEOF()) { CString line; int ret = f.GetLine( line ); if( ret == 0 ) break; if( ret < 0 ) { LOG->Trace("Error reading %s: %s", filename.c_str(), f.GetError().c_str() ); break; } if(line.size() > 0 && utf8_get_char(line.c_str()) == 0xFEFF) { /* Annoying header that Windows puts on UTF-8 plaintext * files; remove it. */ line.erase(0, utf8_get_char_len(line[0])); } TrimLeft(line); TrimRight(line); if(line.size() == 0) continue; /* blank */ if(line[0] == '#') continue; /* comment */ if(!line.CompareNoCase("DontTransliterate")) { tr.translit = false; continue; } size_t pos = line.find_first_of(':'); if(pos != string::npos) { /* x: y */ CString id = line.substr(0, pos); CString txt = line.substr(pos+1); TrimLeft(txt); /* Surround each regex with ^(...)$, to force all comparisons to default * to being a full-line match. (Add ".*" manually if this isn't wanted.) */ if(!id.CompareNoCase("TitleFrom")) tr.TitleFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("ArtistFrom")) tr.ArtistFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("SubtitleFrom")) tr.SubFrom = "^(" + txt + ")$"; else if(!id.CompareNoCase("TitleTo")) tr.Dest.Title = txt; else if(!id.CompareNoCase("ArtistTo")) tr.Dest.Artist = txt; else if(!id.CompareNoCase("SubtitleTo")) tr.Dest.Subtitle = txt; else if(!id.CompareNoCase("TitleTransTo")) tr.Dest.TitleTranslit = txt; else if(!id.CompareNoCase("ArtistTransTo")) tr.Dest.ArtistTranslit = txt; else if(!id.CompareNoCase("SubtitleTransTo")) tr.Dest.SubtitleTranslit = txt; else LOG->Warn( "Unknown TitleSubst tag: \"%s\"", id.c_str() ); } /* Add the translation if this is a terminator (*) or section * marker ([foo]). */ if(line[0] == '*' || line[0] == '[') { if(!CurrentSection.CompareNoCase(section)) AddTrans(tr); /* Reset. */ tr = TitleTrans(); } if(line[0] == '[' && line[line.size()-1] == ']') { CurrentSection = line.substr(1, line.size()-2); } } }
static void wordwrap(TextareaWidget *peer, char *text, int visible_lines, Uint16 scrollbar_width, bool has_scrollbar) { // maximum text width int width = peer->w.bounds.w - peer->w.padding.left - peer->w.padding.right; // lines points to the start of each line int max_lines = 100; unsigned int *lines = malloc(sizeof(int) * max_lines); int num_lines = 0; char *ptr = text; char *line_start = ptr; char *word_break = NULL; Uint16 line_width = 0; /* optimization, don't wrap text with width = 0 */ if (width <= 0) { lines[0] = 0; lines[1] = strlen(ptr); if (peer->lines) { free(peer->lines); } peer->num_lines = 1; peer->lines = realloc(lines, sizeof(int) * (1 + 1)); return; } peer->has_scrollbar = has_scrollbar; if (has_scrollbar && !peer->is_header_widget) { width -= scrollbar_width; } lines[num_lines++] = (ptr - text); while (*ptr) { char c; char *next; Uint32 code = utf8_get_char(ptr, (const char **)&next); switch (code) { case '\n': /* Line break */ ptr = next; word_break = NULL; if (max_lines == num_lines) { max_lines += 100; lines = realloc(lines, sizeof(int) * max_lines); } line_start = ptr; lines[num_lines++] = (ptr - text); line_width = 0; continue; case '.': /* Word break, but exclude urls */ if (utf8_get_char(next, NULL) != ' ') { break; } case ' ': case ',': case '-': /* Word break */ word_break = next; break; } // Calculate width of string to char c = *next; *next = '\0'; line_width += jive_font_width(peer->font, (char *)ptr); *next = c; // Line is less than widget width if (line_width < width) { ptr = next; continue; } if (max_lines == num_lines) { max_lines += 100; lines = realloc(lines, sizeof(int) * max_lines); } // Next line line_width = 0; if (!has_scrollbar && num_lines > visible_lines && !(peer->is_header_widget || peer->hide_scrollbar)) { free(lines); return wordwrap(peer, text, visible_lines, scrollbar_width, true); } if (word_break) { ptr = word_break; word_break = NULL; } /* trim extra \n caused by line breaks */ code = utf8_get_char(ptr, (const char **)&next); if (code == '\n') { ptr = next; code = utf8_get_char(ptr, (const char **)&next); } /* trim leading space on line break */ while (code != 0 && code == ' ') { ptr = next; code = utf8_get_char(ptr, (const char **)&next); } line_start = ptr; lines[num_lines++] = (ptr - text); } lines[num_lines] = (ptr - text); if (!has_scrollbar && num_lines > visible_lines && !(peer->is_header_widget || peer->hide_scrollbar)) { free(lines); return wordwrap(peer, text, visible_lines, scrollbar_width, true); } if (peer->lines) { free(peer->lines); } peer->num_lines = num_lines; peer->lines = realloc(lines, sizeof(int) * (num_lines + 1)); }
/** ColorBitmapText ***********************************************************/ void ColorBitmapText::SetText( const RString& _sText, const RString& _sAlternateText, int iWrapWidthPixels ) { ASSERT( m_pFont != NULL ); RString sNewText = StringWillUseAlternate(_sText,_sAlternateText) ? _sAlternateText : _sText; if( iWrapWidthPixels == -1 ) // wrap not specified iWrapWidthPixels = m_iWrapWidthPixels; if( m_sText == sNewText && iWrapWidthPixels==m_iWrapWidthPixels ) return; m_sText = sNewText; m_iWrapWidthPixels = iWrapWidthPixels; // Set up the first color. m_vColors.clear(); ColorChange change; change.c = RageColor (1, 1, 1, 1); change.l = 0; m_vColors.push_back( change ); m_wTextLines.clear(); RString sCurrentLine = ""; int iLineWidth = 0; RString sCurrentWord = ""; int iWordWidth = 0; int iGlyphsSoFar = 0; for( unsigned i = 0; i < m_sText.length(); i++ ) { int iCharsLeft = m_sText.length() - i - 1; // First: Check for the special (color) case. if( m_sText.length() > 8 && i < m_sText.length() - 9 ) { RString FirstThree = m_sText.substr( i, 3 ); if( FirstThree.CompareNoCase("|c0") == 0 && iCharsLeft > 8 ) { ColorChange cChange; unsigned int r, g, b; sscanf( m_sText.substr( i, 9 ).c_str(), "|%*c0%2x%2x%2x", &r, &g, &b ); cChange.c = RageColor( r/255.f, g/255.f, b/255.f, 1.f ); cChange.l = iGlyphsSoFar; if( iGlyphsSoFar == 0 ) m_vColors[0] = cChange; else m_vColors.push_back( cChange ); i+=8; continue; } } int iCharLength = min( utf8_get_char_len(m_sText[i]), iCharsLeft + 1 ); RString curCharStr = m_sText.substr( i, iCharLength ); wchar_t curChar = utf8_get_char( curCharStr ); i += iCharLength - 1; int iCharWidth = m_pFont->GetLineWidthInSourcePixels( wstring() + curChar ); switch( curChar ) { case L' ': if( /* iLineWidth == 0 &&*/ iWordWidth == 0 ) break; sCurrentLine += sCurrentWord + " "; iLineWidth += iWordWidth + iCharWidth; sCurrentWord = ""; iWordWidth = 0; iGlyphsSoFar++; break; case L'\n': if( iLineWidth + iWordWidth > iWrapWidthPixels ) { SimpleAddLine( sCurrentLine, iLineWidth ); if( iWordWidth > 0 ) iLineWidth = iWordWidth + //Add the width of a space m_pFont->GetLineWidthInSourcePixels( L" " ); sCurrentLine = sCurrentWord + " "; iWordWidth = 0; sCurrentWord = ""; iGlyphsSoFar++; } else { SimpleAddLine( sCurrentLine + sCurrentWord, iLineWidth + iWordWidth ); sCurrentLine = ""; iLineWidth = 0; sCurrentWord = ""; iWordWidth = 0; } break; default: if( iWordWidth + iCharWidth > iWrapWidthPixels && iLineWidth == 0 ) { SimpleAddLine( sCurrentWord, iWordWidth ); sCurrentWord = curCharStr; iWordWidth = iCharWidth; } else if( iWordWidth + iLineWidth + iCharWidth > iWrapWidthPixels ) { SimpleAddLine( sCurrentLine, iLineWidth ); sCurrentLine = ""; iLineWidth = 0; sCurrentWord += curCharStr; iWordWidth += iCharWidth; } else { sCurrentWord += curCharStr; iWordWidth += iCharWidth; } iGlyphsSoFar++; break; } } if( iWordWidth > 0 ) { sCurrentLine += sCurrentWord; iLineWidth += iWordWidth; } if( iLineWidth > 0 ) SimpleAddLine( sCurrentLine, iLineWidth ); BuildChars(); UpdateBaseZoom(); }