Support UTF-8 encoded Unicode for user communications.

(NF_UTF8, togg): New client flag.
(flash, wall): User text input filtering.
(parse, prmptrd): Normal text input filtering.
(uprmptrd, ugetstring): New, to get user text.
(getele, flash, wall): Use them.
(getele): No need to filter out funny characters; input filtering
takes care of them.
(sendmessage, ufindbreak): Work on user text.
(uprnf): New, to print user text.
(rea, gamedown, show_motd): Use it.
(prnf): Unused, remove.
(pr, upr_player): Normal text output filtering (with highlighting).
(pr_flash): User text output filtering.
This commit is contained in:
Ron Koenderink 2005-05-26 01:58:48 +00:00
parent 2508364945
commit 2cc44bb182
14 changed files with 343 additions and 56 deletions

View file

@ -39,14 +39,17 @@
#include "file.h"
#include "commands.h"
static int ufindbreak(char *message /* message is message text */,
int num_chars);
int
flash(void)
{
struct natstr *us;
struct natstr *to;
s_char buf[1024];
char buf[1024]; /* buf is message text */
int tocn;
s_char *sp;
char *sp; /* sp is message text */
us = getnatp(player->cnum);
if ((tocn = natarg(player->argp[1], "to which country? ")) < 0)
@ -77,10 +80,17 @@ flash(void)
for (sp = &player->combuf[0]; *sp && *sp != ' '; ++sp) ;
for (++sp; *sp && *sp != ' '; ++sp) ;
sprintf(buf, ":%s", sp);
for(sp = buf; 0 != *sp; ++sp) {
if ((*sp >= 0x0 && *sp < 0x20 && *sp != '\t') ||
*sp == 0x7f)
*sp = '?';
else if (!(us->nat_flags & NF_UTF8) && (*sp & 0x80))
*sp = '?';
}
sendmessage(us, to, buf, 1);
} else {
sendmessage(us, to, "...", 1);
while (getstring("> ", buf)) {
while (ugetstring("> ", buf)) {
if (*buf == '.')
break;
sendmessage(us, to, buf, 0);
@ -94,17 +104,24 @@ int
wall(void)
{
struct natstr *us;
s_char buf[1024];
s_char *sp;
char buf[1024]; /* buf is message text */
char *sp; /* sp is message text */
us = getnatp(player->cnum);
if (player->argp[1]) {
for (sp = &player->combuf[0]; *sp && *sp != ' '; ++sp) ;
sprintf(buf, ":%s", sp);
for(sp = buf; 0 != *sp; ++sp) {
if ((*sp >= 0x0 && *sp < 0x20 && *sp != '\t') ||
*sp == 0x7f)
*sp = '?';
else if (!(us->nat_flags & NF_UTF8) && (*sp & 0x80))
*sp = '?';
}
sendmessage(us, 0, buf, 1);
} else {
sendmessage(us, 0, "...", 1);
while (getstring("> ", buf)) {
while (ugetstring("> ", buf)) {
if (*buf == '.')
break;
sendmessage(us, 0, buf, 0);
@ -115,29 +132,22 @@ wall(void)
}
int
sendmessage(struct natstr *us, struct natstr *to, char *message,
int oneshot)
sendmessage(struct natstr *us, struct natstr *to, char *message
/* message is message text */, int oneshot)
{
struct player *other;
struct tm *tm;
char *p;
char c;
time_t now;
int sent = 0;
struct natstr *wto;
char c; /* c is message text */
int pos;
for (p = message; 0 != (c = *p); p++) {
if (!isprint(c))
*p = '*';
}
if (strlen(message) > 60) {
s_char c = message[60];
message[60] = '\0';
sendmessage(us, to, message, oneshot);
message[60] = c;
sendmessage(us, to, &message[60], 0);
return 0;
}
pos = ufindbreak(message, 60);
c = message[pos];
if (c)
message[pos] = '\0';
time(&now);
tm = localtime(&now);
for (other = player_next(0); other != 0; other = player_next(other)) {
@ -188,5 +198,28 @@ sendmessage(struct natstr *us, struct natstr *to, char *message,
pr("%s is not accepting flashes\n", to->nat_cnam);
}
}
if (c) {
message[pos] = c;
sendmessage(us, to, &message[pos], 0);
}
return 0;
}
/*
* Return byte-index of the N-th UTF-8 character in UTF-8 string S.
* If S doesn't have that many characters, return its length instead.
*/
int
ufindbreak(char *s /* s is message text */, int n)
{
int i = 0;
while (n && s[i])
{
if ((s[i++] & 0xc0) == 0xc0)
while ((s[i] & 0xc0) == 0x80)
i++;
--n;
}
return i;
}

View file

@ -63,7 +63,7 @@ rea(void)
int teles;
int size;
unsigned int nbytes;
s_char buf[4096];
s_char buf[4096]; /* buf is message text */
int lasttype;
int lastcnum;
time_t lastdate;
@ -168,7 +168,7 @@ rea(void)
(void)fread(buf, sizeof(s_char), nbytes, telfp);
buf[nbytes] = 0;
if (readit)
prnf(buf);
uprnf(buf);
tgm.tel_length -= nbytes;
}
}

View file

@ -73,6 +73,10 @@ togg(void)
name = "techlists";
flag = NF_TECHLISTS;
break;
case 'u':
name = "UTF-8";
flag = NF_UTF8;
break;
default:
return RET_SYN;
}
@ -116,6 +120,10 @@ togg(void)
pr("techlists flag on\n");
else
pr("techlists flag off\n");
if (np->nat_flags & NF_UTF8)
pr("UTF-8 flag on\n");
else
pr("UTF-8 flag off\n");
}
return RET_OK;

View file

@ -47,3 +47,16 @@ getstring(char *prompt, char *buf)
return 0;
return buf;
}
/*
* Print sub-prompt PROMPT, receive a line of UTF8 input into BUF[1024].
* Return BUF on success, else NULL.
*/
char *
ugetstring(char *prompt, char *buf /* buf is message text */)
{
*buf = '\0';
if (uprmptrd(prompt, buf, 1024) < 0)
return 0;
return buf;
}

View file

@ -79,7 +79,10 @@ parse(register s_char *buf, s_char **argpp, s_char **condp, s_char *space,
quoted = !quoted;
buf++;
} else {
*bp1++ = *buf++;
if (*buf >= 0x20 && *buf <= 0x7e)
*bp1++ = *buf++;
else
buf++;
}
}
*bp1++ = 0;

View file

@ -154,7 +154,7 @@ gamedown(void)
{
FILE *down_fp;
struct telstr tgm;
s_char buf[MAXTELSIZE];
s_char buf[MAXTELSIZE]; /* buf is message text */
if (player->god)
return 0;
@ -176,7 +176,7 @@ gamedown(void)
return 1;
}
buf[tgm.tel_length] = 0;
prnf(buf);
uprnf(buf);
pr("\nThe game is down\n");
fclose(down_fp);
return 1;

View file

@ -374,7 +374,7 @@ show_motd(void)
return RET_FAIL;
}
buf[tgm.tel_length] = 0;
prnf(buf);
uprnf(buf);
fclose(motd_fp);
return RET_OK;
}

View file

@ -40,13 +40,12 @@
static int tilde_escape(s_char *s, s_char c);
int
getele(s_char *nation, s_char *buf)
getele(char *nation, char *buf /* buf is message text */)
{
register s_char *bp;
register char *bp;
register int len;
register int c;
s_char buffer[MAXTELSIZE + 2];
s_char left[MAXTELSIZE + 2];
char buffer[MAXTELSIZE + 2]; /* buf is message text */
char left[MAXTELSIZE + 2]; /* buf is message text */
pr("Enter telegram for %s\n", nation);
pr("undo last line with ~u, print with ~p, abort with ~q, end with ^D or .\n");
@ -54,7 +53,7 @@ getele(s_char *nation, s_char *buf)
while (!player->aborted) {
sprintf(left, "%4d left: ", (int)(buf + MAXTELSIZE - bp));
buffer[0] = 0;
if (prmptrd(left, buffer, MAXTELSIZE - 2) <= 0)
if (uprmptrd(left, buffer, MAXTELSIZE - 2) <= 0)
break;
if (tilde_escape(buffer, 'q'))
return -1;
@ -96,12 +95,6 @@ getele(s_char *nation, s_char *buf)
return -1;
len = bp - buf;
buf[len] = 0;
/* Get rid of non-ASCII and control characters. */
for (bp = buf; 0 != (c = *bp); bp++) {
if (isascii(c) && (isprint(c) || isspace(c)))
continue;
*bp = '?';
}
return len;
}

View file

@ -59,20 +59,32 @@ static void outid(struct player *pl, int n);
/*VARARGS*/
void
pr(s_char *format, ...)
pr(char *format, ...)
{
s_char buf[4096];
struct natstr *np = getnatp(player->cnum);
char buf[4096];
va_list ap;
va_start(ap, format);
(void)vsprintf(buf, format, ap);
va_end(ap);
pr_player(player, C_DATA, buf);
if (np->nat_flags & NF_UTF8)
upr_player(player, C_DATA, buf);
else
pr_player(player, C_DATA, buf);
}
void
prnf(s_char *buf)
uprnf(char *buf /* buf is message text */)
{
struct natstr *np = getnatp(player->cnum);
/*
* Translate to ASCII if the client is not in UTF mode
*/
if (!(np->nat_flags & NF_UTF8))
prtoascii(buf);
pr_player(player, C_DATA, buf);
}
@ -94,9 +106,11 @@ pr_id(struct player *p, int id, s_char *format, ...)
}
void
pr_flash(struct player *pl, s_char *format, ...)
pr_flash(struct player *pl, char *format
/* format is message text */, ...)
{
s_char buf[4096];
struct natstr *np = getnatp(pl->cnum);
char buf[4096]; /* buf is message text */
va_list ap;
if (pl->state != PS_PLAYING)
@ -104,6 +118,11 @@ pr_flash(struct player *pl, s_char *format, ...)
va_start(ap, format);
(void)vsprintf(buf, format, ap);
va_end(ap);
/*
* Translate to ASCII if the client is not in UTF mode
*/
if (!(np->nat_flags & NF_UTF8))
prtoascii(buf);
pr_player(pl, C_FLASH, buf);
io_output(pl->iop, IO_NOWAIT);
}
@ -154,9 +173,8 @@ pr_player(struct player *pl, int id, s_char *buf)
io_puts(pl->iop, "\n");
pl->curid = -1;
}
if (pl->curid == -1) {
if (pl->curid == -1)
outid(pl, id);
}
p = strchr(bp, '\n');
if (p != 0) {
len = (p - bp) + 1;
@ -173,6 +191,54 @@ pr_player(struct player *pl, int id, s_char *buf)
}
}
void
upr_player(struct player *pl, int id, char *buf
/* buf is message text */)
{
register char *bp; /* bp is message text */
register int standout = 0;
char printbuf[2]; /* bp is message text */
printbuf[0] = '\0';
printbuf[1] = '\0';
bp = buf;
while (*bp != '\0') {
if (pl->curid != -1 && pl->curid != id) {
io_puts(pl->iop, "\n");
pl->curid = -1;
}
if (pl->curid == -1)
outid(pl, id);
if (*bp < 0) { /* looking for standout bit 0x80 */
if (standout == 0) {
printbuf[0] = 0x0e;
io_puts(pl->iop, printbuf);
standout = 1;
}
*bp &= 0x7f;
} else {
if (standout == 1) {
printbuf[0] = 0x0f;
io_puts(pl->iop, printbuf);
standout = 0;
}
}
if (*bp == '\n') {
if (pl->command && (pl->command->c_flags & C_MOD))
io_write(pl->iop, bp, 1, IO_NOWAIT);
else
io_write(pl->iop, bp, 1, IO_WAIT);
pl->curid = -1;
} else {
printbuf[0] = *bp;
io_puts(pl->iop, printbuf);
}
bp++;
}
}
/*
* highlighted characters have hex 80 or'ed in
* with them to designate their highlightedness
@ -242,9 +308,10 @@ showvers(int vers)
}
int
prmptrd(s_char *prompt, s_char *str, int size)
prmptrd(char *prompt, char *str, int size)
{
int r;
char *cp;
pr_id(player, C_FLUSH, "%s\n", prompt);
if ((r = recvclient(str, size)) < 0)
@ -252,6 +319,35 @@ prmptrd(s_char *prompt, s_char *str, int size)
time(&player->curup);
if (*str == 0)
return 1;
for(cp = str; 0 != *cp; ++cp) {
if ((*cp >= 0x0 && *cp < 0x20 && *cp != '\t') ||
*cp == 0x7f || *cp & 0x80)
*cp = '?';
}
return strlen(str);
}
int
uprmptrd(char *prompt, char *str /* str is message text */, int size)
{
int r;
char *cp; /* cp is message text */
struct natstr *np = getnatp(player->cnum);
pr_id(player, C_FLUSH, "%s\n", prompt);
if ((r = recvclient(str, size)) < 0)
return r;
time(&player->curup);
if (*str == 0)
return 1;
for(cp = (unsigned char *)str; 0 != *cp; ++cp) {
if ((*cp >= 0x0 && *cp < 0x20 && *cp != '\t') ||
*cp == 0x7f)
*cp = '?';
else if (!(np->nat_flags & NF_UTF8) && (*cp & 0x80))
*cp = '?';
}
return strlen(str);
}
@ -336,3 +432,17 @@ mpr(int cn, s_char *format, ...)
pr_player(player, C_DATA, buf);
}
}
void
prtoascii(char *buf /* buf is message text */)
{
char *pbuf; /* pbuf is message text */
for(pbuf = buf; *pbuf != 0; pbuf++)
if ((*pbuf & 0xc0) == 0xc0)
*pbuf = '?';
else if (*pbuf & 0x80) {
memmove(pbuf,pbuf+1,strlen(pbuf)-1);
pbuf--;
}
}