From faae661e9ef9f5538a43aed3270e97e0e28622a2 Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 21 May 2014 06:21:09 +0000 Subject: [PATCH] fixed up sort ordering to be more correct. drawstrings now tint the string, and should now work as expected with ^3 colours. tweaked qcc's utf-8 parsing. utf-8 chars are now valid in identifiers. invalid chars (like pesky nbsp) are more verbose, and can actually be found. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4667 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/m_master.c | 14 +++- engine/client/net_master.c | 2 +- engine/common/pr_bgcmd.c | 7 +- engine/gl/gl_font.c | 133 +++++++++++++++++++++++++------------ engine/qclib/cmdlib.h | 2 + engine/qclib/qcc_cmdlib.c | 116 ++++++++++++++++++++++++++++++-- engine/qclib/qcc_pr_lex.c | 114 ++++++++++++++++++++----------- engine/qclib/qccgui.c | 126 +++++++++++++++++++++++++++++------ 8 files changed, 402 insertions(+), 112 deletions(-) diff --git a/engine/client/m_master.c b/engine/client/m_master.c index 0b8de325..5f075743 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -138,7 +138,17 @@ static qboolean SL_TitlesKey (menucustom_t *ths, menu_t *menu, int key) if (sortkey == SLKEY_ADDRESS) return true; - Master_SetSortField(sortkey, Master_GetSortField()!=sortkey||!Master_GetSortDescending()); + switch(sortkey) + { + case SLKEY_NUMPLAYERS: + //favour descending order (low first) + Master_SetSortField(sortkey, Master_GetSortField()!=sortkey||!Master_GetSortDescending()); + break; + default: + //favour ascending order (low first) + Master_SetSortField(sortkey, Master_GetSortField()==sortkey&&!Master_GetSortDescending()); + break; + } return true; } @@ -679,7 +689,7 @@ void M_Menu_ServerList2_f(void) CalcFilters(menu); - Master_SetSortField(SLKEY_PING, true); + Master_SetSortField(SLKEY_PING, false); MasterInfo_Refresh(); } diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 2a94c4c4..1c0c3220 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -373,7 +373,7 @@ void Master_ShowServer(serverinfo_t *server) return; } - if (!decreasingorder) + if (decreasingorder) { for (i = 0; i < numvisibleservers; i++) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 18ec4417..eb3e5474 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -877,7 +877,12 @@ void QCBUILTIN PF_cvar_string (pubprogfuncs_t *prinst, struct globalvars_s *pr_g const char *str = PR_GetStringOfs(prinst, OFS_PARM0); cvar_t *cv = Cvar_Get(str, "", 0, "QC variables"); if (cv) - RETURN_CSTRING(cv->string); + { + if(cv->latched_string) + RETURN_CSTRING(cv->latched_string); + else + RETURN_CSTRING(cv->string); + } else G_INT(OFS_RETURN) = 0; } diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 80eb327d..e507fdc8 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -253,6 +253,7 @@ static texid_t font_texture; static int font_colourmask; static byte_vec4_t font_forecolour; static byte_vec4_t font_backcolour; +static vec4_t font_foretint; static struct font_s *curfont; static float curfont_scale[2]; @@ -1618,14 +1619,18 @@ void Font_LineDraw(int x, int y, conchar_t *start, conchar_t *end) correct usage of this function thus requires calling this with 1111 before Font_EndString*/ void Font_ForceColour(float r, float g, float b, float a) { + if (font_foretint[0] == r && font_foretint[1] == b && font_foretint[2] == b && font_foretint[3] == a) + return; + if (font_colourmask & CON_NONCLEARBG) Font_Flush(); font_colourmask = CON_WHITEMASK; - font_forecolour[0] = r*255; - font_forecolour[1] = g*255; - font_forecolour[2] = b*255; - font_forecolour[3] = a*255; + font_foretint[0] = r; + font_foretint[1] = g; + font_foretint[2] = b; + font_foretint[3] = a; + Vector4Scale(font_foretint, 255, font_forecolour); font_backcolour[3] = 0; @@ -1633,8 +1638,7 @@ void Font_ForceColour(float r, float g, float b, float a) } void Font_InvalidateColour(void) { - Font_Flush(); - font_colourmask = ~0; + Font_ForceColour(1,1,1,1); } //draw a character from the current font at a pixel location. @@ -1691,26 +1695,40 @@ int Font_DrawChar(int px, int py, unsigned int charcode) col = charcode & (CON_2NDCHARSETTEXT|CON_RICHFORECOLOUR|(0xfff<>CON_RICHRSHIFT)&0xf)*0x11; - font_forecolour[1] = ((col>>CON_RICHGSHIFT)&0xf)*0x11; - font_forecolour[2] = ((col>>CON_RICHBSHIFT)&0xf)*0x11; - font_forecolour[3] = 255; + rgba[0] = ((col>>CON_RICHRSHIFT)&0xf)*0x11; + rgba[1] = ((col>>CON_RICHGSHIFT)&0xf)*0x11; + rgba[2] = ((col>>CON_RICHBSHIFT)&0xf)*0x11; + rgba[3] = 255; font_backcolour[0] = 0; font_backcolour[1] = 0; font_backcolour[2] = 0; font_backcolour[3] = 0; - if (charcode & CON_2NDCHARSETTEXT) { - font_forecolour[0] = min(font_forecolour[0]*1.16, 255); - font_forecolour[1] *= 0.54; - font_forecolour[2] *= 0.41; + rgba[0] *= font->alttint[0]; + rgba[1] *= font->alttint[1]; + rgba[2] *= font->alttint[2]; } + else + { + rgba[0] *= font->tint[0]; + rgba[1] *= font->tint[1]; + rgba[2] *= font->tint[2]; + } + rgba[0] *= font_foretint[0]; + rgba[1] *= font_foretint[1]; + rgba[2] *= font_foretint[2]; + rgba[3] *= font_foretint[3]; + font_forecolour[0] = min(rgba[0], 255); + font_forecolour[1] = min(rgba[1], 255); + font_forecolour[2] = min(rgba[2], 255); + font_forecolour[3] = min(rgba[3], 255); } } else @@ -1718,15 +1736,16 @@ int Font_DrawChar(int px, int py, unsigned int charcode) col = charcode & (CON_2NDCHARSETTEXT|CON_NONCLEARBG|CON_BGMASK|CON_FGMASK|CON_HALFALPHA); if (col != font_colourmask) { + vec4_t rgba; if ((col ^ font_colourmask) & CON_NONCLEARBG) Font_Flush(); font_colourmask = col; col = (charcode&CON_FGMASK)>>CON_FGSHIFT; - font_forecolour[0] = consolecolours[col].fr*255; - font_forecolour[1] = consolecolours[col].fg*255; - font_forecolour[2] = consolecolours[col].fb*255; - font_forecolour[3] = (charcode & CON_HALFALPHA)?127:255; + rgba[0] = consolecolours[col].fr*255; + rgba[1] = consolecolours[col].fg*255; + rgba[2] = consolecolours[col].fb*255; + rgba[3] = (charcode & CON_HALFALPHA)?127:255; col = (charcode&CON_BGMASK)>>CON_BGSHIFT; font_backcolour[0] = consolecolours[col].fr*255; @@ -1736,16 +1755,24 @@ int Font_DrawChar(int px, int py, unsigned int charcode) if (charcode & CON_2NDCHARSETTEXT) { - font_forecolour[0] = min(font_forecolour[0]*font->alttint[0], 255); - font_forecolour[1] = min(font_forecolour[1]*font->alttint[1], 255); - font_forecolour[2] = min(font_forecolour[2]*font->alttint[2], 255); + rgba[0] *= font->alttint[0]; + rgba[1] *= font->alttint[1]; + rgba[2] *= font->alttint[2]; } else { - font_forecolour[0] = min(font_forecolour[0]*font->tint[0], 255); - font_forecolour[1] = min(font_forecolour[1]*font->tint[1], 255); - font_forecolour[2] = min(font_forecolour[2]*font->tint[2], 255); + rgba[0] *= font->tint[0]; + rgba[1] *= font->tint[1]; + rgba[2] *= font->tint[2]; } + rgba[0] *= font_foretint[0]; + rgba[1] *= font_foretint[1]; + rgba[2] *= font_foretint[2]; + rgba[3] *= font_foretint[3]; + font_forecolour[0] = min(rgba[0], 255); + font_forecolour[1] = min(rgba[1], 255); + font_forecolour[2] = min(rgba[2], 255); + font_forecolour[3] = min(rgba[3], 255); } } @@ -1873,14 +1900,15 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) col = charcode & (CON_2NDCHARSETTEXT|CON_RICHFORECOLOUR|(0xfff<>CON_RICHRSHIFT)&0xf)*0x11; - font_forecolour[1] = ((col>>CON_RICHGSHIFT)&0xf)*0x11; - font_forecolour[2] = ((col>>CON_RICHBSHIFT)&0xf)*0x11; - font_forecolour[3] = 255; + rgba[0] = ((col>>CON_RICHRSHIFT)&0xf)*0x11; + rgba[1] = ((col>>CON_RICHGSHIFT)&0xf)*0x11; + rgba[2] = ((col>>CON_RICHBSHIFT)&0xf)*0x11; + rgba[3] = 255; font_backcolour[0] = 0; font_backcolour[1] = 0; @@ -1889,10 +1917,24 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) if (charcode & CON_2NDCHARSETTEXT) { - font_forecolour[0] = min(font_forecolour[0]*1.16, 255); - font_forecolour[1] *= 0.54; - font_forecolour[2] *= 0.41; + rgba[0] *= font->alttint[0]; + rgba[1] *= font->alttint[1]; + rgba[2] *= font->alttint[2]; } + else + { + rgba[0] *= font->tint[0]; + rgba[1] *= font->tint[1]; + rgba[2] *= font->tint[2]; + } + rgba[0] *= font_foretint[0]; + rgba[1] *= font_foretint[1]; + rgba[2] *= font_foretint[2]; + rgba[3] *= font_foretint[3]; + font_forecolour[0] = min(rgba[0], 255); + font_forecolour[1] = min(rgba[1], 255); + font_forecolour[2] = min(rgba[2], 255); + font_forecolour[3] = min(rgba[3], 255); } } else @@ -1900,15 +1942,16 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) col = charcode & (CON_2NDCHARSETTEXT|CON_NONCLEARBG|CON_BGMASK|CON_FGMASK|CON_HALFALPHA); if (col != font_colourmask) { + vec4_t rgba; if (font_backcolour[3] != ((charcode & CON_NONCLEARBG)?127:0)) Font_Flush(); font_colourmask = col; col = (charcode&CON_FGMASK)>>CON_FGSHIFT; - font_forecolour[0] = consolecolours[col].fr*255; - font_forecolour[1] = consolecolours[col].fg*255; - font_forecolour[2] = consolecolours[col].fb*255; - font_forecolour[3] = (charcode & CON_HALFALPHA)?127:255; + rgba[0] = consolecolours[col].fr*255; + rgba[1] = consolecolours[col].fg*255; + rgba[2] = consolecolours[col].fb*255; + rgba[3] = (charcode & CON_HALFALPHA)?127:255; col = (charcode&CON_BGMASK)>>CON_BGSHIFT; font_backcolour[0] = consolecolours[col].fr*255; @@ -1918,16 +1961,24 @@ float Font_DrawScaleChar(float px, float py, unsigned int charcode) if (charcode & CON_2NDCHARSETTEXT) { - font_forecolour[0] = min(font_forecolour[0]*font->alttint[0], 255); - font_forecolour[1] = min(font_forecolour[1]*font->alttint[1], 255); - font_forecolour[2] = min(font_forecolour[2]*font->alttint[2], 255); + rgba[0] *= font->alttint[0]; + rgba[1] *= font->alttint[1]; + rgba[2] *= font->alttint[2]; } else { - font_forecolour[0] = min(font_forecolour[0]*font->tint[0], 255); - font_forecolour[1] = min(font_forecolour[1]*font->tint[1], 255); - font_forecolour[2] = min(font_forecolour[2]*font->tint[2], 255); + rgba[0] *= font->tint[0]; + rgba[1] *= font->tint[1]; + rgba[2] *= font->tint[2]; } + rgba[0] *= font_foretint[0]; + rgba[1] *= font_foretint[1]; + rgba[2] *= font_foretint[2]; + rgba[3] *= font_foretint[3]; + font_forecolour[0] = min(rgba[0], 255); + font_forecolour[1] = min(rgba[1], 255); + font_forecolour[2] = min(rgba[2], 255); + font_forecolour[3] = min(rgba[3], 255); } } diff --git a/engine/qclib/cmdlib.h b/engine/qclib/cmdlib.h index b15eaa2c..4e785909 100644 --- a/engine/qclib/cmdlib.h +++ b/engine/qclib/cmdlib.h @@ -95,6 +95,8 @@ long ParseNum (char *str); char *QCC_COM_Parse (const char *data); char *QCC_COM_Parse2 (char *data); +unsigned int utf8_check(const void *in, unsigned int *value); + extern char qcc_token[1024]; extern int qcc_eof; diff --git a/engine/qclib/qcc_cmdlib.c b/engine/qclib/qcc_cmdlib.c index 0d9e3a93..d909f4c8 100644 --- a/engine/qclib/qcc_cmdlib.c +++ b/engine/qclib/qcc_cmdlib.c @@ -874,9 +874,54 @@ enum UTF32LE, UTF32BE, }; + +//return 0 if the input is not valid utf-8. +unsigned int utf8_check(const void *in, unsigned int *value) +{ + //uc is the output unicode char + unsigned int uc = 0xfffdu; //replacement character + const unsigned char *str = in; + + if (!(*str & 0x80)) + { + *value = *str; + return 1; + } + else if ((*str & 0xe0) == 0xc0) + { + if ((str[1] & 0xc0) == 0x80) + { + *value = uc = ((str[0] & 0x1f)<<6) | (str[1] & 0x3f); + if (!uc || uc >= (1u<<7)) //allow modified utf-8 + return 2; + } + } + else if ((*str & 0xf0) == 0xe0) + { + if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80) + { + *value = uc = ((str[0] & 0x0f)<<12) | ((str[1] & 0x3f)<<6) | ((str[2] & 0x3f)<<0); + if (uc >= (1u<<11)) + return 3; + } + } + else if ((*str & 0xf8) == 0xf0) + { + if ((str[1] & 0xc0) == 0x80 && (str[2] & 0xc0) == 0x80 && (str[3] & 0xc0) == 0x80) + { + *value = uc = ((str[0] & 0x07)<<18) | ((str[1] & 0x3f)<<12) | ((str[2] & 0x3f)<<6) | ((str[3] & 0x3f)<<0); + if (uc >= (1u<<16)) //overlong + if (uc <= 0x10ffff) //aand we're not allowed to exceed utf-16 surrogates. + return 4; + } + } + *value = 0xFFFD; + return 0; +} + //read utf-16 chars and output the 'native' utf-8. //we don't expect essays written in code, so we don't need much actual support for utf-8. -static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, int *outlen) +static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, int *outlen, pbool usemalloc) { char *utf8, *start; unsigned int inc; @@ -905,7 +950,10 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, in return inputf; } chars = inbytes / w; - utf8 = start = qccHunkAlloc(chars * maxperchar + 2); + if (usemalloc) + utf8 = start = malloc(chars * maxperchar + 2); + else + utf8 = start = qccHunkAlloc(chars * maxperchar + 2); for (i = 0; i < chars; i++) { switch(type) @@ -981,6 +1029,62 @@ static char *decodeUTF(int type, unsigned char *inputf, unsigned int inbytes, in return start; } +//the gui is a windows program. +//this means that its fucked. +//on the plus side, its okay with a bom... +unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen) +{ + unsigned int code; + int l; + unsigned short *out, *outstart; + //sanitise the input. + if (len >= 4 && mem[0] == '\xff' && mem[1] == '\xfe' && mem[2] == '\x00' && mem[3] == '\x00') + mem = decodeUTF(UTF32LE, (unsigned char*)mem+4, len-4, &len, true); + else if (len >= 4 && mem[0] == '\x00' && mem[1] == '\x00' && mem[2] == '\xfe' && mem[3] == '\xff') + mem = decodeUTF(UTF32BE, (unsigned char*)mem+4, len-4, &len, true); + else if (len >= 2 && mem[0] == '\xff' && mem[1] == '\xfe') + { + //already utf8, just return it as-is + out = malloc(len+3); + memcpy(out, mem, len); + out[len/2] = 0; + return out; + //mem = decodeUTF(UTF16LE, (unsigned char*)mem+2, len-2, &len, false); + } + else if (len >= 2 && mem[0] == '\xfe' && mem[1] == '\xff') + mem = decodeUTF(UTF16BE, (unsigned char*)mem+2, len-2, &len, false); + //utf-8 BOM, for compat with broken text editors (like windows notepad). + else if (len >= 3 && mem[0] == '\xef' && mem[1] == '\xbb' && mem[2] == '\xbf') + { + mem += 3; + len -= 3; + } + + outstart = malloc(len*2+3); + out = outstart; + while(len) + { + l = utf8_check(mem, &code); + if (!l) + {l = 1; code = 0xe000|(unsigned char)*mem;}//fucked up. convert to 0xe000 private-use range. + len -= l; + mem += l; + + if (code > 0xffff) + { + code -= 0x10000; + *out++ = 0xd800u | ((code>>10) & 0x3ff); +// *out++ = 0xdc00u | ((code>>00) & 0x3ff); + } + else + *out++ = code; + } + if (outlen) + *outlen = out - outstart; + *out++ = 0; + return outstart; +} + long QCC_LoadFile (char *filename, void **bufferptr) { char *mem; @@ -1002,13 +1106,13 @@ long QCC_LoadFile (char *filename, void **bufferptr) externs->ReadFile(filename, mem, len+2); if (len >= 4 && mem[0] == '\xff' && mem[1] == '\xfe' && mem[2] == '\x00' && mem[3] == '\x00') - mem = decodeUTF(UTF32LE, (unsigned char*)mem+4, len-4, &len); + mem = decodeUTF(UTF32LE, (unsigned char*)mem+4, len-4, &len, false); else if (len >= 4 && mem[0] == '\x00' && mem[1] == '\x00' && mem[2] == '\xfe' && mem[3] == '\xff') - mem = decodeUTF(UTF32BE, (unsigned char*)mem+4, len-4, &len); + mem = decodeUTF(UTF32BE, (unsigned char*)mem+4, len-4, &len, false); else if (len >= 2 && mem[0] == '\xff' && mem[1] == '\xfe') - mem = decodeUTF(UTF16LE, (unsigned char*)mem+2, len-2, &len); + mem = decodeUTF(UTF16LE, (unsigned char*)mem+2, len-2, &len, false); else if (len >= 2 && mem[0] == '\xfe' && mem[1] == '\xff') - mem = decodeUTF(UTF16BE, (unsigned char*)mem+2, len-2, &len); + mem = decodeUTF(UTF16BE, (unsigned char*)mem+2, len-2, &len, false); //utf-8 BOM, for compat with broken text editors (like windows notepad). else if (len >= 3 && mem[0] == '\xef' && mem[1] == '\xbb' && mem[2] == '\xbf') { diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index fb3fe7b6..3e29b420 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -392,6 +392,12 @@ static void QCC_PR_SkipToEndOfLine(pbool errorifnonwhite) { handleccomments = false; pr_file_p += 2; + /*while(*pr_file_p) + { + if (*pr_file_p == '\n') + break; + pr_file_p++; + }*/ } else if (*pr_file_p == '\\' && pr_file_p[1] == '\r' && pr_file_p[2] == '\n') { /*windows endings*/ @@ -1329,6 +1335,7 @@ void QCC_PR_LexString (void) char *end, *cnst; int raw; char rawdelim[64]; + int code; int texttype; pbool first = true; @@ -1389,6 +1396,14 @@ void QCC_PR_LexString (void) if (!c) QCC_PR_ParseError (ERR_EOF, "EOF inside quote"); + if (!qccwarningaction[WARN_NOTUTF8] && c < 0 && utf8_check(&pr_token[c-1], &code)) + { + //convert 0xe000 private-use area to quake's charset (if they don't have the utf-8 warning enabled) + //note: this may have a small false-positive risk. + if (code >= 0xe000 && code <= 0xe0ff) + pr_file_p += utf8_check(&pr_token[c-1], &code)-1; + } + /* //these two conditions are generally part of the C preprocessor. if (c == '\\' && *pr_file_p == '\r' && pr_file_p[1] == '\n') { //dos format @@ -1651,42 +1666,15 @@ void QCC_PR_LexString (void) if (qccwarningaction[WARN_NOTUTF8]) { - len = 0; - //this doesn't do over-long checks. for (c = 0; pr_token[c]; c++) { - if (len) + len = utf8_check(&pr_token[c], &code); + if (!len) { - if ((pr_token[c] & 0xc0) != 0x80) - break; - len--; - } - else if (pr_token[c] & 0x80) - { - if (!(pr_token[c] & 0x40)) - { - //error. - len = 1; - break; - } - else if (!(pr_token[c] & 0x20)) - len = 2; - else if (!(pr_token[c] & 0x10)) - len = 3; - else if (!(pr_token[c] & 0x08)) - len = 4; - else if (!(pr_token[c] & 0x04)) - len = 5; - else if (!(pr_token[c] & 0x02)) - len = 6; - else if (!(pr_token[c] & 0x01)) - len = 7; - else - len = 8; + QCC_PR_ParseWarning(WARN_NOTUTF8, "String constant is not valid utf-8"); + break; } } - if (len) - QCC_PR_ParseWarning(WARN_NOTUTF8, "String constant is not valid utf-8"); } } #endif @@ -1955,15 +1943,43 @@ void QCC_PR_LexName (void) int len; len = 0; - c = *pr_file_p; do { - pr_token[len] = c; - len++; - pr_file_p++; + int b = utf8_check(pr_file_p, &c); + if (!b) + { + unsigned char lead = *pr_file_p++; + char *o; + while(*pr_file_p && !utf8_check(pr_file_p, &c)) + pr_file_p++; + o = pr_file_p; + while (qcc_iswhite(*pr_file_p)) + { + if (*pr_file_p == '\n') + break; + pr_file_p++; + } + if (*pr_file_p == '\n') + QCC_PR_ParseError(ERR_NOTANAME, "Invalid UTF-8 code sequence at end of line. Lead byte was %#2x", lead); + else + { + len = 0; + while (*pr_file_p && !qcc_iswhite(*pr_file_p)) + pr_token[len++] = *pr_file_p++; + pr_token[len++] = 0; + pr_file_p = o; + QCC_PR_ParseError(ERR_NOTANAME, "Invalid UTF-8 code sequence before %s. Lead byte was %#2x", pr_token, lead); + } + return; + } + while(b-->0) + { + pr_token[len] = *pr_file_p++; + len++; + } c = *pr_file_p; } while ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' - || (c >= '0' && c <= '9')); + || (c >= '0' && c <= '9') || c & 0x80); pr_token[len] = 0; pr_token_type = tt_name; @@ -1997,7 +2013,13 @@ void QCC_PR_LexPunctuation (void) } } - QCC_PR_ParseError (ERR_UNKNOWNPUCTUATION, "Unknown punctuation"); + if ((unsigned char)*pr_file_p == (unsigned char)0xa0) + QCC_PR_ParseWarning (ERR_UNKNOWNPUCTUATION, "Unknown punctuation: '\\x%x' - non-breaking space", (unsigned char)*pr_file_p); + else + QCC_PR_ParseWarning (ERR_UNKNOWNPUCTUATION, "Unknown punctuation: '\\x%x'", *pr_file_p); + pr_file_p++; + + QCC_PR_Lex(); } @@ -2159,7 +2181,7 @@ pbool QCC_PR_SimpleGetToken (void) } i = 0; - while ((c = *pr_file_p) && !qcc_iswhite(c) && c != ',' && c != ';' && c != ')' && c != '(' && c != ']') + while ((c = *pr_file_p) && !qcc_iswhite(c) && c != ',' && c != ';' && c != ')' && c != '(' && c != ']' && !(c == '/' && pr_file_p[1] == '/')) { if (i == sizeof(qcc_token)-1) QCC_Error (ERR_INTERNAL, "token exceeds %i chars", i); @@ -2908,6 +2930,20 @@ int QCC_PR_CheckCompConst(void) return true; } + if (!strncmp(pr_file_p, "__QCCVER__", 8)) + { + char retbuf[128]; + + time_t long_time; + time( &long_time ); + strftime( retbuf, sizeof(retbuf), + "\"%a %d %b %Y\"", localtime( &long_time )); + + pr_file_p += 10; + QCC_PR_IncludeChunkEx("FTEQCC "__DATE__","__TIME__"", true, NULL, NULL); + + return true; + } if (!strncmp(pr_file_p, "__FILE__", 8)) { char retbuf[256]; @@ -3110,7 +3146,7 @@ void QCC_PR_Lex (void) return; } - if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' ) + if ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c & 0x80)) { if (flag_hashonly || !QCC_PR_CheckCompConst()) //look for a macro. QCC_PR_LexName (); diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index e47c2a5e..d7647b7f 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -79,6 +79,80 @@ int PDECL QCC_FileSize (const char *fname) #include "../libs/zlib.h" #endif +pbool PDECL QCC_WriteFileW (const char *name, wchar_t *data, int chars) +{ + char *u8start = malloc(3+chars*4+1); + char *u8 = u8start; + int offset; + pbool result = false; + unsigned int inc; + FILE *f; + + //start with the bom + //lets just always write a BOM when the file contains something outside ascii. it'll just be more robust when microsoft refuse to use utf8 by default. + //its just much less likely to fuck up when people use notepad/wordpad. :s + inc = 0xfeff; + *u8++ = ((inc>>12) & 0xf) | 0xe0; + *u8++ = ((inc>>6) & 0x3f) | 0x80; + *u8++ = ((inc>>0) & 0x3f) | 0x80; + offset = u8-u8start; //assume its not needed. will set to 0 if it is. + + while(*data) + { + inc = *data++; + //handle surrogates + if (inc >= 0xd800u && inc < 0xdc00u) + { + unsigned int l = *data; + if (l >= 0xdc00u && l < 0xe000u) + { + data++; + inc = (((inc & 0x3ffu)<<10) | (l & 0x3ffu)) + 0x10000; + } + } + if (inc <= 127) + *u8++ = inc; + else + { + offset = 0; + if (inc <= 0x7ff) + { + *u8++ = ((inc>>6) & 0x1f) | 0xc0; + *u8++ = ((inc>>0) & 0x3f) | 0x80; + } + else if (inc <= 0xffff) + { + *u8++ = ((inc>>12) & 0xf) | 0xe0; + *u8++ = ((inc>>6) & 0x3f) | 0x80; + *u8++ = ((inc>>0) & 0x3f) | 0x80; + } + else if (inc <= 0x1fffff) + { + *u8++ = ((inc>>18) & 0x07) | 0xf0; + *u8++ = ((inc>>12) & 0x3f) | 0x80; + *u8++ = ((inc>> 6) & 0x3f) | 0x80; + *u8++ = ((inc>> 0) & 0x3f) | 0x80; + } + else + { + inc = 0xFFFD; + *u8++ = ((inc>>12) & 0xf) | 0xe0; + *u8++ = ((inc>>6) & 0x3f) | 0x80; + *u8++ = ((inc>>0) & 0x3f) | 0x80; + } + } + } + + f = fopen(name, "wb"); + if (f) + { + result = fwrite(u8start+offset, 1, u8-(u8start+offset), f) == (u8-(u8start+offset)); + fclose(f); + } + free(u8start); + return result; +} + pbool PDECL QCC_WriteFile (const char *name, void *data, int len) { long length; @@ -303,9 +377,9 @@ HWND CreateAnEditControl(HWND parent) if (!richedit) richedit = LoadLibrary("RICHED32.DLL"); - newc=CreateWindowEx(WS_EX_CLIENTEDGE, - richedit?RICHEDIT_CLASS:"EDIT", - "", + newc=CreateWindowExW(WS_EX_CLIENTEDGE, + richedit?RICHEDIT_CLASSW:L"EDIT", + L"", WS_CHILD /*| ES_READONLY*/ | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_LEFT | ES_WANTRETURN | ES_MULTILINE | ES_AUTOVSCROLL, @@ -1147,6 +1221,7 @@ int Rehighlight(editor_t *edit) } #endif +unsigned short *QCC_makeutf16(char *mem, unsigned int len, int *outlen); void EditorReload(editor_t *editor) { struct stat sbuf; @@ -1157,7 +1232,10 @@ void EditorReload(editor_t *editor) if (flen >= 0) { file = malloc(flen+1); + QCC_ReadFile(editor->filename, file, flen); + + file[flen] = 0; } else @@ -1171,14 +1249,16 @@ void EditorReload(editor_t *editor) if (file) { - if (!fl_autohighlight) + char msg[1024]; + wchar_t *ch = QCC_makeutf16(file, flen, NULL); + Edit_SetSel(editor->editpane,0,0); + SetWindowTextW(editor->editpane, ch); + /*if (errors) { - GUIPrint(editor->editpane, file); - } - else - { - GUIFormattingPrint(editor->editpane, file); - } + QC_snprintfz(msg, sizeof(msg), "%s contains encoding errors. Invalid bytes have been converted to the 0xe000 private use area.", editor->filename); + MessageBox(editor->editpane, msg, "Encoding errors.", MB_ICONWARNING); + }*/ + free(ch); free(file); } @@ -1321,16 +1401,16 @@ int EditorSave(editor_t *edit) char title[2048]; struct stat sbuf; int len; - char *file; - len = Edit_GetTextLength(edit->editpane); - file = malloc(len+1); + wchar_t *file; + len = GetWindowTextLengthW(edit->editpane); + file = malloc((len+1)*2); if (!file) { MessageBox(NULL, "Save failed - not enough mem", "Error", 0); return false; } - Edit_GetText(edit->editpane, file, len+1); - if (!QCC_WriteFile(edit->filename, file, len)) + GetWindowTextW(edit->editpane, file, len+1); + if (!QCC_WriteFileW(edit->filename, file, len)) { MessageBox(NULL, "Save failed\nCheck path and ReadOnly flags", "Failure", 0); return false; @@ -1361,8 +1441,10 @@ char *GUIReadFile(const char *fname, void *buffer, int blen) { if (e->window && !strcmp(e->filename, fname)) { - int elen = Edit_GetTextLength(e->editpane); - Edit_GetText(e->editpane, buffer, blen); +// int elen = GetWindowTextLengthW(e->editpane); + //our qcc itself is fine with utf-16, so long as it has a BOM. + *(short*)buffer = 0xfeff; + GetWindowTextW(e->editpane, (short*)buffer+1, blen); return buffer; } } @@ -1377,7 +1459,7 @@ int GUIFileSize(const char *fname) { if (e->window && !strcmp(e->filename, fname)) { - int len = Edit_GetTextLength(e->editpane); + int len = (GetWindowTextLengthW(e->editpane)+1)*2; return len; } } @@ -1639,7 +1721,7 @@ HWND optionsmenu; HWND hexen2item; HWND nokeywords_coexistitem; HWND autoprototype_item; -HWND autohighlight_item; +//HWND autohighlight_item; HWND extraparmsitem; #ifdef EMBEDDEBUG HWND w_enginebinary; @@ -1681,7 +1763,7 @@ static LRESULT CALLBACK OptionsWndProc(HWND hWnd,UINT message, else compiler_flag[i].flags &= ~FLAG_SETINGUI; } - fl_autohighlight = Button_GetCheck(autohighlight_item); + fl_autohighlight = false;//Button_GetCheck(autohighlight_item); Edit_GetText(extraparmsitem, parameters, sizeof(parameters)-1); #ifdef EMBEDDEBUG Edit_GetText(w_enginebinary, enginebinary, sizeof(enginebinary)-1); @@ -2086,7 +2168,7 @@ void OptionsDialog(void) else Button_SetCheck(wnd, 0); - autohighlight_item = wnd = CreateWindow("BUTTON","Syntax Highlighting", +/* autohighlight_item = wnd = CreateWindow("BUTTON","Syntax Highlighting", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 408,y,200-16,16, optionsmenu, @@ -2098,7 +2180,7 @@ void OptionsDialog(void) Button_SetCheck(wnd, 1); else Button_SetCheck(wnd, 0); - +*/ x = 408; my = y; for (i = 0; compiler_flag[i].enabled; i++)