]> git.pond.sub.org Git - empserver/blob - src/lib/subs/pr.c
0eee125eaf3a71992dfb91c113709042115892ef
[empserver] / src / lib / subs / pr.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2005, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  pr.c: Use to do output to a player
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1986, 1989 
32  *     Steve McClure, 1998-2000
33  */
34 /*
35  * The pr routine historically arranged for nonbuffered i/o
36  * because stdio didn't used to automatically flush stdout before
37  * it read something from stdin.  Now pr() prepends an "output id"
38  * in front of each line of text, informing the user interface
39  * what sort of item it is seeing; prompt, noecho prompt,
40  * more input data, etc.
41  */
42
43 #include <string.h>
44 #include <fcntl.h>
45 #include <ctype.h>
46 #include <stdarg.h>
47 #include "proto.h"
48 #include "misc.h"
49 #include "player.h"
50 #include "nat.h"
51 #include "empio.h"
52 #include "file.h"
53 #include "com.h"
54 #include "tel.h"
55 #include "server.h"
56 #include "prototypes.h"
57
58 static void outid(struct player *pl, int n);
59
60 /*VARARGS*/
61 void
62 pr(char *format, ...)
63 {
64     char buf[4096];
65     va_list ap;
66
67     va_start(ap, format);
68     (void)vsprintf(buf, format, ap);
69     va_end(ap);
70     if (player->flags & PF_UTF8)
71         upr_player(player, C_DATA, buf);
72     else
73         pr_player(player, C_DATA, buf);
74 }
75
76 void
77 uprnf(char *buf /* buf is message text */)
78 {
79     /*
80      * Translate to ASCII if the client is not in UTF mode
81      */
82     if (!(player->flags & PF_UTF8))
83         prtoascii(buf);
84
85     pr_player(player, C_DATA, buf);
86 }
87
88 /*VARARGS*/
89 void
90 pr_id(struct player *p, int id, s_char *format, ...)
91 {
92     s_char buf[4096];
93     va_list ap;
94
95     if (p->curid >= 0) {
96         io_puts(p->iop, "\n");
97         p->curid = -1;
98     }
99     va_start(ap, format);
100     (void)vsprintf(buf, format, ap);
101     va_end(ap);
102     pr_player(p, id, buf);
103 }
104
105 void
106 pr_flash(struct player *pl, char *format
107          /* format is message text */, ...)
108 {
109     char buf[4096]; /* buf is message text */
110     va_list ap;
111
112     if (pl->state != PS_PLAYING)
113         return;
114     va_start(ap, format);
115     (void)vsprintf(buf, format, ap);
116     va_end(ap);
117     /*
118      * Translate to ASCII if the client is not in UTF mode
119      */
120     if (!(pl->flags & PF_UTF8))
121         prtoascii(buf);
122     pr_player(pl, C_FLASH, buf);
123     io_output(pl->iop, IO_NOWAIT);
124 }
125
126 void
127 pr_inform(struct player *pl, s_char *format, ...)
128 {
129     s_char buf[4096];
130     va_list ap;
131
132     if (pl->state != PS_PLAYING)
133         return;
134     va_start(ap, format);
135     (void)vsprintf(buf, format, ap);
136     va_end(ap);
137     pr_player(pl, C_INFORM, buf);
138     io_output(pl->iop, IO_NOWAIT);
139 }
140
141 void
142 pr_wall(s_char *format, ...)
143 {
144     s_char buf[4096];
145     struct player *p;
146     va_list ap;
147
148     va_start(ap, format);
149     (void)vsprintf(buf, format, ap);
150     va_end(ap);
151     for (p = player_next(0); p; p = player_next(p)) {
152         if (p->state != PS_PLAYING)
153             continue;
154         pr_player(p, C_FLASH, buf);
155         io_output(p->iop, IO_NOWAIT);
156     }
157 }
158
159 void
160 pr_player(struct player *pl, int id, s_char *buf)
161 {
162     register s_char *p;
163     register s_char *bp;
164     register int len;
165
166     bp = buf;
167     while (*bp != '\0') {
168         if (pl->curid != -1 && pl->curid != id) {
169             io_puts(pl->iop, "\n");
170             pl->curid = -1;
171         }
172         if (pl->curid == -1)
173             outid(pl, id);
174         p = strchr(bp, '\n');
175         if (p != 0) {
176             len = (p - bp) + 1;
177             if (pl->command && (pl->command->c_flags & C_MOD))
178                 io_write(pl->iop, bp, len, IO_NOWAIT);
179             else
180                 io_write(pl->iop, bp, len, IO_WAIT);
181             bp += len;
182             pl->curid = -1;
183         } else {
184             len = io_puts(pl->iop, bp);
185             bp += len;
186         }
187     }
188 }
189
190 void
191 upr_player(struct player *pl, int id, char *buf
192                       /* buf is message text */)
193 {
194     register char *bp; /* bp is message text */
195     register int standout = 0;
196     char printbuf[2]; /* bp is message text */
197
198     printbuf[0] = '\0';
199     printbuf[1] = '\0';
200
201     bp = buf;
202     while (*bp != '\0') {
203         if (pl->curid != -1 && pl->curid != id) {
204             io_puts(pl->iop, "\n");
205             pl->curid = -1;
206         }
207         if (pl->curid == -1)
208             outid(pl, id);
209
210         if (*bp < 0) { /* looking for standout bit 0x80 */
211             if (standout == 0) {
212                 printbuf[0] = 0x0e;
213                 io_puts(pl->iop, printbuf);
214                 standout = 1;
215             }
216             *bp &= 0x7f;
217         } else {
218             if (standout == 1) {
219                 printbuf[0] = 0x0f;
220                 io_puts(pl->iop, printbuf);
221                 standout = 0;
222             }
223         }
224         if (*bp == '\n') {
225             if (pl->command && (pl->command->c_flags & C_MOD))
226                 io_write(pl->iop, bp, 1, IO_NOWAIT);
227             else
228                 io_write(pl->iop, bp, 1, IO_WAIT);
229             pl->curid = -1;
230         } else {
231             printbuf[0] = *bp;
232             io_puts(pl->iop, printbuf);
233         }
234         bp++;
235     }
236 }
237
238 /*
239  * highlighted characters have hex 80 or'ed in
240  * with them to designate their highlightedness
241  */
242 void
243 pr_hilite(s_char *buf)
244 {
245     register s_char *bp;
246     register s_char c;
247     s_char *p;
248
249     p = malloc(strlen(buf) + 1);
250     strcpy(p, buf);
251     for (bp = p; 0 != (c = *bp); bp++)
252         if (isprint(c))
253             *bp |= 0x80;
254     pr(p);
255     free(p);
256 }
257
258 /*
259  * output hex code + space
260  */
261 static void
262 outid(struct player *pl, int n)
263 {
264     s_char c;
265     s_char buf[3];
266
267     if (n > C_LAST) {
268         logerror("outid: %d not valid code\n", n);
269         return;
270     }
271     if (n >= 10)
272         c = 'a' - 10 + n;
273     else
274         c = '0' + n;
275     buf[0] = c;
276     buf[1] = ' ';
277     buf[2] = '\0';
278     io_puts(pl->iop, buf);
279     pl->curid = n;
280 }
281
282 void
283 prredir(s_char *redir)
284 {
285     pr_id(player, *redir == '>' ? C_REDIR : C_PIPE, "%s\n", redir);
286 }
287
288 void
289 prexec(s_char *file)
290 {
291     pr_id(player, C_EXECUTE, "%s\n", file);
292 }
293
294 void
295 prprompt(int min, int btu)
296 {
297     pr_id(player, C_PROMPT, "%d %d\n", min, btu);
298 }
299
300 int
301 prmptrd(char *prompt, char *str, int size)
302 {
303     int r;
304     char *cp;
305
306     pr_id(player, C_FLUSH, "%s\n", prompt);
307     if ((r = recvclient(str, size)) < 0)
308         return r;
309     time(&player->curup);
310     if (*str == 0)
311         return 1;
312     for(cp = str; 0 != *cp; ++cp) {
313         if ((*cp >= 0x0 && *cp < 0x20 && *cp != '\t') ||
314             *cp == 0x7f || *cp & 0x80)
315             *cp = '?';
316     }
317     return strlen(str);
318 }
319
320 int
321 uprmptrd(char *prompt, char *str /* str is message text */, int size)
322 {
323     int r;
324     char *cp; /* cp is message text */
325
326     pr_id(player, C_FLUSH, "%s\n", prompt);
327     if ((r = recvclient(str, size)) < 0)
328         return r;
329     time(&player->curup);
330     if (*str == 0)
331         return 1;
332     
333     for(cp = str; 0 != *cp; ++cp) {
334         if ((*cp >= 0x0 && *cp < 0x20 && *cp != '\t') ||
335             *cp == 0x7f)
336             *cp = '?';
337         else if (!(player->flags & PF_UTF8) && (*cp & 0x80))
338             *cp = '?';
339     }
340     return strlen(str);
341 }
342
343 void
344 prdate(void)
345 {
346     time_t now;
347
348     (void)time(&now);
349     pr(ctime(&now));
350 }
351
352 /*
353  * print x,y formatting as country
354  */
355 void
356 prxy(s_char *format, coord x, coord y, natid country)
357 {
358     s_char buf[255];
359     struct natstr *np;
360
361     np = getnatp(country);
362     sprintf(buf, format, xrel(np, x), yrel(np, y));
363     pr(buf);
364 }
365
366 /*VARARGS*/
367 void
368 PR(int cn, s_char *format, ...)
369 {
370     /* XXX should really do this on a per-nation basis */
371     static s_char longline[MAXNOC][512];
372     int newline;
373     va_list ap;
374     s_char buf[1024];
375
376     va_start(ap, format);
377     (void)vsprintf(buf, format, ap);
378     va_end(ap);
379     newline = strrchr(buf, '\n') ? 1 : 0;
380     strcat(longline[cn], buf);
381     if (newline) {
382         if (update_pending || (cn && cn != player->cnum))
383             typed_wu(0, cn, longline[cn], TEL_BULLETIN);
384         else
385             pr_player(player, C_DATA, longline[cn]);
386         longline[cn][0] = '\0';
387     }
388 }
389
390 void
391 PRdate(natid cn)
392 {
393     time_t now;
394
395     (void)time(&now);
396     PR(cn, ctime(&now));
397 }
398
399 void
400 pr_beep(void)
401 {
402     struct natstr *np = getnatp(player->cnum);
403
404     if (np->nat_flags & NF_BEEP)
405         pr("\07");
406 }
407
408 void
409 mpr(int cn, s_char *format, ...)
410 {
411     s_char buf[4096];
412     va_list ap;
413
414     va_start(ap, format);
415     (void)vsprintf(buf, format, ap);
416     va_end(ap);
417     if (cn) {
418         if (update_pending || cn != player->cnum)
419             typed_wu(0, cn, buf, TEL_BULLETIN);
420         else
421             pr_player(player, C_DATA, buf);
422     }
423 }
424
425 void
426 prtoascii(char *buf /* buf is message text */)
427 {
428     char *pbuf; /* pbuf is message text */
429
430     for(pbuf = buf; *pbuf != 0; pbuf++)
431         if ((*pbuf & 0xc0) == 0xc0)
432             *pbuf = '?';
433         else if (*pbuf & 0x80) {
434             memmove(pbuf,pbuf+1,strlen(pbuf)-1);
435             pbuf--;
436         }
437 }
438
439 /*
440  * Return byte-index of the N-th UTF-8 character in UTF-8 string S.
441  * If S doesn't have that many characters, return its length instead.
442  */
443 int
444 ufindpfx(char *s, int n)
445 {
446     int i = 0;
447
448     while (n && s[i])
449     {
450         if ((s[i++] & 0xc0) == 0xc0)
451             while ((s[i] & 0xc0) == 0x80)
452                 i++;
453         --n;
454     }
455     return i;
456 }