]> git.pond.sub.org Git - empserver/commitdiff
Support UTF-8 encoded Unicode for user communications.
authorRon Koenderink <rkoenderink@yahoo.ca>
Thu, 26 May 2005 01:58:48 +0000 (01:58 +0000)
committerRon Koenderink <rkoenderink@yahoo.ca>
Thu, 26 May 2005 01:58:48 +0000 (01:58 +0000)
(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.

14 files changed:
doc/unicode [new file with mode: 0644]
include/misc.h
include/nat.h
include/prototypes.h
info/Commands/toggle.t
src/lib/commands/flash.c
src/lib/commands/rea.c
src/lib/commands/togg.c
src/lib/gen/getstring.c
src/lib/gen/parse.c
src/lib/player/empdis.c
src/lib/player/player.c
src/lib/subs/getele.c
src/lib/subs/pr.c

diff --git a/doc/unicode b/doc/unicode
new file mode 100644 (file)
index 0000000..3ebaf30
--- /dev/null
@@ -0,0 +1,102 @@
+Unicode changes:
+
+1. toggle UTF-8
+
+   Add utf8 as a toggle option and store in the nat_flags field in
+   nation structure.  In the future, this should be a login option
+   rather than a country toggle once the login options are added.
+
+2. flash and wall
+
+   a. Message as command argument
+
+      Interpret raw command line as message text rather than normal
+      text.
+
+   b. Multi-line mode
+
+      Read message lines as message text rather than normal text.
+
+   c. Break long lines
+
+      Count the charactes using utf8 format.  This works for both ASCII
+      and UTF8 formatted strings.
+
+   d. Print lines
+
+      Print as message text rather than normal text.
+
+3. Telexes and telex-like things
+
+   a. read and wire, MOTD and gamedown message
+
+      Print as message text rather than normal text.
+
+   c. tele, anno, pray, turn.
+
+      Read as message text rather than normal text.
+
+4. Input filtering
+
+   a. Parsing commands (normal text)
+
+      Ignore control and non-ASCII characters when copying argument
+      strings.
+
+   b. Reading normal text command arguments
+
+      Replace control and non-ASCII characters, except for tab with
+      "?'.
+
+   c. Reading message text command arguments
+
+      Support message text arguments, used by 3a. and 2b.  Replace
+      control and, if NF_UTF8 is off, non-ASCII characters.
+
+5. Output filtering
+
+   Output filtering asssumes that there are no control characters or
+   invalid characters in the output messages.  The control characters
+   and invalid characters are filtered out during input filtering or
+   that the server will not generate control characters or invalid
+   characters.
+
+   a. Printing normal text
+
+      When NF_UTF8 is on, highlighted text is printed using SO/SI.
+
+   b. Printing message text
+
+      When NF_UTF8 is off, replace UTF8 charactes with '?'.
+
+
+Definitions:
+
+1. Normal Text
+       For normal text, the following ASCII characters are valid:
+       CR, LF and 0x20-0x7e.  Normally, LF is an termination action
+       event.  Normally, CR is not used except by the server.
+       Normal Text does not support UTF8 characters.  In normal
+       text, the 8th bit is used a highlight bit.  If the client
+       has the utf8 nation flag set, the standout bit is removed
+       and the highlight block is prefixed with SO (ASCII standout)
+       and suffixed with SI (ASCII standin).
+       
+2. Message Text
+       For message text, the following ASCII characters are valid:
+       Tab, CR, LF and 0x020-0x7e.  Normally, LF is an termination
+       action event.   Normally, CR is not used except by the server.
+       Message text also supports UTF8 characters if the utf8 nation
+       flag is turn on otherwise only the ASCII characters are
+       supported.
+
+
+Notes:
+
+1. Strings that considered message text are commented.
+
+2. Both Normal and Message text are char strings are in the server.
+       Care needs to be taken as some compiler consider char
+       signed and other default to unsigned char.
+
+3. Unicode functions are prefixed with u.
index ed9f24b1843b42dfe319189d957deb4890154309..a6d4e2d25b2654802456640aaa3a8cfe432210c4 100644 (file)
@@ -144,6 +144,9 @@ extern s_char *iesplur(int n);
 extern s_char *plur(int n, s_char *no, s_char *yes);
 extern char *getstarg(char *input, char *prompt, char buf[]);
 extern char *getstring(char *prompt, char buf[]);
 extern s_char *plur(int n, s_char *no, s_char *yes);
 extern char *getstarg(char *input, char *prompt, char buf[]);
 extern char *getstring(char *prompt, char buf[]);
+extern char *ugetstring(char *prompt, char buf[]
+                       /* buf is message text */);
+             
 extern s_char *prbuf(s_char *format, ...)
     ATTRIBUTE((format (printf, 1, 2)));
 
 extern s_char *prbuf(s_char *format, ...)
     ATTRIBUTE((format (printf, 1, 2)));
 
index 2d63877765f1610299571e4a5f86cec896fb8f2d..72663f899a65aaa15c6707931ef1852207be4abc 100644 (file)
@@ -172,5 +172,7 @@ extern void agecontact(struct natstr *np);
 #define NF_SONAR       bit(4)  /* Turn auto-sonar on */
 #define NF_TECHLISTS    bit(5) /* Sort lists by tech not type */
 #define NF_SACKED       bit(6) /* Capital was sacked, and hasn't been reset yet */
 #define NF_SONAR       bit(4)  /* Turn auto-sonar on */
 #define NF_TECHLISTS    bit(5) /* Sort lists by tech not type */
 #define NF_SACKED       bit(6) /* Capital was sacked, and hasn't been reset yet */
+#define NF_UTF8         bit(7) /* Whether the client accepts UTF-8 (true) or
+                                   ASCII only (false) */
 
 #endif /* _NAT_H_ */
 
 #endif /* _NAT_H_ */
index 78718aff0d74fd1b9a943ad5293351881593f2bb..74ae8c5e3918b779c4644949c0004a0725b7012c 100644 (file)
@@ -63,7 +63,8 @@ extern void finish_server(void);
  */
 extern int check_market(void);
 extern void set_coastal(struct sctstr *);
  */
 extern int check_market(void);
 extern void set_coastal(struct sctstr *);
-extern int sendmessage(struct natstr *, struct natstr *, char *, int);
+extern int sendmessage(struct natstr *, struct natstr *, char *message
+                      /* message is message text */, int);
 extern void gift(int, int, s_char *, int, s_char *);
 extern int display_mark(i_type, int);
 extern int want_to_abandon(struct sctstr *, i_type, int, struct lndstr *);
 extern void gift(int, int, s_char *, int, s_char *);
 extern int display_mark(i_type, int);
 extern int want_to_abandon(struct sctstr *, i_type, int, struct lndstr *);
@@ -484,7 +485,7 @@ extern void emp_setbit(int, int, u_char *);
 extern void emp_setbitmap(int, int, u_char *, int *);
 extern void bitinit2(struct nstr_sect *, u_char *, int);
 /* getele.c */
 extern void emp_setbitmap(int, int, u_char *, int *);
 extern void bitinit2(struct nstr_sect *, u_char *, int);
 /* getele.c */
-extern int getele(s_char *, s_char *);
+extern int getele(char *, char *);
 /* land.c */
 extern s_char *prland(struct lndstr *);
 extern int lnd_postread(int, s_char *);
 /* land.c */
 extern s_char *prland(struct lndstr *);
 extern int lnd_postread(int, s_char *);
@@ -591,29 +592,35 @@ extern int pln_damage(struct plnstr *, coord, coord, s_char, int *, int);
 extern int pln_identchance(struct plnstr *, int, int);
 extern void pln_set_tech(struct plnstr *, int);
 /* pr.c */
 extern int pln_identchance(struct plnstr *, int, int);
 extern void pln_set_tech(struct plnstr *, int);
 /* pr.c */
-extern void pr(s_char *, ...) ATTRIBUTE((format (printf, 1, 2)));
-extern void prnf(s_char *buf);
+extern void pr(char *, ...) ATTRIBUTE((format (printf, 1, 2)));
+extern void uprnf(char *buf /* buf is message text */);
 extern void pr_id(struct player *, int, s_char *, ...)
                ATTRIBUTE((format (printf, 3, 4)));
 extern void pr_id(struct player *, int, s_char *, ...)
                ATTRIBUTE((format (printf, 3, 4)));
-extern void pr_flash(struct player *, s_char *, ...)
+extern void pr_flash(struct player *, char *format
+                    /* format is message text */, ...)
                ATTRIBUTE((format (printf, 2, 3)));
 extern void pr_inform(struct player *, s_char *, ...)
                ATTRIBUTE((format (printf, 2, 3)));
 extern void pr_wall(s_char *, ...)
                ATTRIBUTE((format (printf, 1, 2)));
 extern void pr_player(struct player *pl, int id, s_char *buf);
                ATTRIBUTE((format (printf, 2, 3)));
 extern void pr_inform(struct player *, s_char *, ...)
                ATTRIBUTE((format (printf, 2, 3)));
 extern void pr_wall(s_char *, ...)
                ATTRIBUTE((format (printf, 1, 2)));
 extern void pr_player(struct player *pl, int id, s_char *buf);
+extern void upr_player(struct player *pl, int id, char *buf
+                                 /* buf is message text */);
 extern void pr_hilite(s_char *buf);
 extern void prredir(s_char *redir);
 extern void prexec(s_char *file);
 extern void prprompt(int min, int btu);
 extern void showvers(int vers);
 extern void pr_hilite(s_char *buf);
 extern void prredir(s_char *redir);
 extern void prexec(s_char *file);
 extern void prprompt(int min, int btu);
 extern void showvers(int vers);
-extern int prmptrd(s_char *prompt, s_char *str, int size);
+extern int prmptrd(char *prompt, char *str, int size);
+extern int uprmptrd(char *prompt, char *str /* str is message text */,
+                   int size);
 extern void prdate(void);
 extern void prxy(s_char *format, coord x, coord y, natid country);
 extern void PR(int, s_char *, ...) ATTRIBUTE((format (printf, 2, 3)));
 extern void PRdate(natid cn);
 extern void pr_beep(void);
 extern void mpr(int, s_char *, ...) ATTRIBUTE((format (printf, 2, 3)));
 extern void prdate(void);
 extern void prxy(s_char *format, coord x, coord y, natid country);
 extern void PR(int, s_char *, ...) ATTRIBUTE((format (printf, 2, 3)));
 extern void PRdate(natid cn);
 extern void pr_beep(void);
 extern void mpr(int, s_char *, ...) ATTRIBUTE((format (printf, 2, 3)));
+extern void prtoascii(char *buf /* buf is message text */);
 
 /* radmap.c */
 extern int deltx(struct range *, coord);
 
 /* radmap.c */
 extern int deltx(struct range *, coord);
index 616bc649d4a0bf2d2d8ac7e172d028708783d878..594afcecaa873c10df46bb199147f34579c8f54c 100644 (file)
@@ -1,7 +1,7 @@
 .TH Command TOGGLE
 .NA toggle "Toggle client flags"
 .LV Expert
 .TH Command TOGGLE
 .NA toggle "Toggle client flags"
 .LV Expert
-.SY "toggle [inform|flash|beep|coastwatch|sonar|techlists] [on|off]"
+.SY "toggle [inform|flash|beep|coastwatch|sonar|techlists|utf8] [on|off]"
 You use the toggle command to set various user-interface flags for
 your country.  The server will remember which flags you have set
 between sessions.  If you do not specify the second argument ("on" or
 You use the toggle command to set various user-interface flags for
 your country.  The server will remember which flags you have set
 between sessions.  If you do not specify the second argument ("on" or
@@ -39,6 +39,19 @@ Will toggle the "techlists" flag (default off) for your country.  When
 techlists is on, when you do a "show" command, the lists shows will be
 in order of tech instead of grouping order.
 .s1
 techlists is on, when you do a "show" command, the lists shows will be
 in order of tech instead of grouping order.
 .s1
+.EX "toggle utf8"
+Will toggle the "utf8" flag (default off) for your country.
+When utf8 is on, you can use multiple langauges in your user communication.
+To use this feature, the client must support the unicode character set
+and must encode unicode characters using the UTF8 format
+when sending the characters to the server and must decode
+the UTF8 characters into
+unicode characters when receiving characters from the server.
+Also both the sending and receiving clients must support
+unicode in order to communicate using unicode characters.
+This feature applies to the follow commands:
+wire, read, announcement, flash, telegram and turn.
+.s1
 .EX "toggle"
 Will list all your flags and show whether they are on or off.
 .s1
 .EX "toggle"
 Will list all your flags and show whether they are on or off.
 .s1
index aad0d19b4a1a3c3d397f99e40aeb3327862a18bb..46bd6f8ae6996d48861a28b583e0ca1ae1c81a0c 100644 (file)
 #include "file.h"
 #include "commands.h"
 
 #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;
 int
 flash(void)
 {
     struct natstr *us;
     struct natstr *to;
-    s_char buf[1024];
+    char buf[1024]; /* buf is message text */
     int tocn;
     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)
 
     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 = &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);
        sendmessage(us, to, buf, 1);
     } else {
        sendmessage(us, to, "...", 1);
-       while (getstring("> ", buf)) {
+       while (ugetstring("> ", buf)) {
            if (*buf == '.')
                break;
            sendmessage(us, to, buf, 0);
            if (*buf == '.')
                break;
            sendmessage(us, to, buf, 0);
@@ -94,17 +104,24 @@ int
 wall(void)
 {
     struct natstr *us;
 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);
 
     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);
        sendmessage(us, 0, buf, 1);
     } else {
        sendmessage(us, 0, "...", 1);
-       while (getstring("> ", buf)) {
+       while (ugetstring("> ", buf)) {
            if (*buf == '.')
                break;
            sendmessage(us, 0, buf, 0);
            if (*buf == '.')
                break;
            sendmessage(us, 0, buf, 0);
@@ -115,29 +132,22 @@ wall(void)
 }
 
 int
 }
 
 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;
 {
     struct player *other;
     struct tm *tm;
-    char *p;
-    char c;
     time_t now;
     int sent = 0;
     struct natstr *wto;
     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)) {
     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);
        }
     }
                pr("%s is not accepting flashes\n", to->nat_cnam);
        }
     }
+    if (c) {
+       message[pos] = c;
+       sendmessage(us, to, &message[pos], 0);
+    }
     return 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;
+}
index e319eb78816b646566d674d9b5e10e0a1e61d1dd..b015d509eeebb3358d0a2c5eb35110522d19964a 100644 (file)
@@ -63,7 +63,7 @@ rea(void)
     int teles;
     int size;
     unsigned int nbytes;
     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;
     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)
            (void)fread(buf, sizeof(s_char), nbytes, telfp);
            buf[nbytes] = 0;
            if (readit)
-               prnf(buf);
+               uprnf(buf);
            tgm.tel_length -= nbytes;
        }
     }
            tgm.tel_length -= nbytes;
        }
     }
index ab5a0ec5d66df0213be0674b3be918bf6677c23e..7230db929c54192e932c86583a06060ddba1bcea 100644 (file)
@@ -73,6 +73,10 @@ togg(void)
            name = "techlists";
            flag = NF_TECHLISTS;
            break;
            name = "techlists";
            flag = NF_TECHLISTS;
            break;
+       case 'u':
+           name = "UTF-8";
+           flag = NF_UTF8;
+           break;
        default:
            return RET_SYN;
        }
        default:
            return RET_SYN;
        }
@@ -116,6 +120,10 @@ togg(void)
            pr("techlists flag on\n");
        else
            pr("techlists flag off\n");
            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;
     }
 
     return RET_OK;
index c7077311b07237e9f95e86c4adc09ed11d728c7b..0938cddfc223e3f395bc926292608b0b1002e309 100644 (file)
@@ -47,3 +47,16 @@ getstring(char *prompt, char *buf)
        return 0;
     return 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;
+}
index 5ae248c1774c76cfdd8adfe3d6c5ab677693f3b4..814a2b7f865ad582c397fab5acde08adf8e5398e 100644 (file)
@@ -79,7 +79,10 @@ parse(register s_char *buf, s_char **argpp, s_char **condp, s_char *space,
                quoted = !quoted;
                buf++;
            } else {
                quoted = !quoted;
                buf++;
            } else {
-               *bp1++ = *buf++;
+               if (*buf >= 0x20 && *buf <= 0x7e)
+                   *bp1++ = *buf++;
+               else
+                   buf++;
            }
        }
        *bp1++ = 0;
            }
        }
        *bp1++ = 0;
index 972f58417d216fadba47b320987e1a1ba54f67cb..831710a93d30ac2502a3b21fa603a5c024a07d02 100644 (file)
@@ -154,7 +154,7 @@ gamedown(void)
 {
     FILE *down_fp;
     struct telstr tgm;
 {
     FILE *down_fp;
     struct telstr tgm;
-    s_char buf[MAXTELSIZE];
+    s_char buf[MAXTELSIZE]; /* buf is message text */
 
     if (player->god)
        return 0;
 
     if (player->god)
        return 0;
@@ -176,7 +176,7 @@ gamedown(void)
        return 1;
     }
     buf[tgm.tel_length] = 0;
        return 1;
     }
     buf[tgm.tel_length] = 0;
-    prnf(buf);
+    uprnf(buf);
     pr("\nThe game is down\n");
     fclose(down_fp);
     return 1;
     pr("\nThe game is down\n");
     fclose(down_fp);
     return 1;
index d41cbe7cd33dd2e7370a72992eaa8a4ae0a73955..a59873cc43efeb154dbe25ca9e85ab8ac4ed9f7b 100644 (file)
@@ -374,7 +374,7 @@ show_motd(void)
        return RET_FAIL;
     }
     buf[tgm.tel_length] = 0;
        return RET_FAIL;
     }
     buf[tgm.tel_length] = 0;
-    prnf(buf);
+    uprnf(buf);
     fclose(motd_fp);
     return RET_OK;
 }
     fclose(motd_fp);
     return RET_OK;
 }
index 0ac3d6c39cb5032c014cdc8a98d07a5266f0c5f1..8c8785ad58025d78d70fd0525969a97446c1b1f2 100644 (file)
 static int tilde_escape(s_char *s, s_char c);
 
 int
 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 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");
 
     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;
     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;
            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;
        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;
 }
 
     return len;
 }
 
index e57c1b3a8b2470cd5a6a338bce9756d50f35d52a..34085228094e481230446da46fda91dc14a31165 100644 (file)
@@ -59,20 +59,32 @@ static void outid(struct player *pl, int n);
 
 /*VARARGS*/
 void
 
 /*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);
     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
 }
 
 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);
 }
 
     pr_player(player, C_DATA, buf);
 }
 
@@ -94,9 +106,11 @@ pr_id(struct player *p, int id, s_char *format, ...)
 }
 
 void
 }
 
 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)
     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);
     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);
 }
     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;
        }
            io_puts(pl->iop, "\n");
            pl->curid = -1;
        }
-       if (pl->curid == -1) {
+       if (pl->curid == -1)
            outid(pl, id);
            outid(pl, id);
-       }
        p = strchr(bp, '\n');
        if (p != 0) {
            len = (p - bp) + 1;
        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
 /*
  * highlighted characters have hex 80 or'ed in
  * with them to designate their highlightedness
@@ -242,9 +308,31 @@ showvers(int vers)
 }
 
 int
 }
 
 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)
+       return r;
+    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;
 {
     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)
 
     pr_id(player, C_FLUSH, "%s\n", prompt);
     if ((r = recvclient(str, size)) < 0)
@@ -252,6 +340,14 @@ prmptrd(s_char *prompt, s_char *str, int size)
     time(&player->curup);
     if (*str == 0)
        return 1;
     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);
 }
 
     return strlen(str);
 }
 
@@ -336,3 +432,17 @@ mpr(int cn, s_char *format, ...)
            pr_player(player, C_DATA, buf);
     }
 }
            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--;
+       }
+}