/* This module handles all the Input/Output of the system */ #include <unistd.h> #include <stdlib.h> #include <strings.h> #include "kernel.h" #include "sflags.h" #include "pflags.h" #include "lflags.h" #include "bprintf.h" #include "mud.h" #include "mobile.h" #include "exit.h" #include "log.h" #include "rooms.h" #include "parse.h" #ifdef VARGS #include <stdarg.h> #endif static void kiputs (char *s, FILE * file); static void dcprnt (char *ct, FILE * file); /* * ** Output Functions * ** */ #define SYSBUFSIZE 4096 #define MAX_ARGS 2 #define prnt(x, f) if ((x).nest) dcprnt((x).str, f); else kiputs((x).str, f); static char *bufptr, *sysbuf; static int buflen; static int snooplev = 0; static Boolean new_line = True; /* True when next char is first in a line */ struct arg { char *str; int nest; }; static void pansi (struct arg[], FILE *); static void pcls (struct arg[], FILE *); static void ppnblind (struct arg[], FILE *); static void pfilter (struct arg[], FILE *); static void pryou (struct arg[], FILE *); static void pryour (struct arg[], FILE *); static void ppndeaf (struct arg[], FILE *); static void pndark (struct arg[], FILE *); static void pndeaf (struct arg[], FILE *); static void pfile (struct arg[], FILE *); static void prname (struct arg[], FILE *); static void pcansee (struct arg[], FILE *); struct _code { char name; int args; void (*func) (struct arg[], FILE *); }; static struct _code codes[] = { {'A', 1, pansi}, {'C', 0, pcls}, {'D', 1, ppnblind}, {'F', 1, pfilter}, {'N', 1, pryou}, {'P', 1, ppndeaf}, {'c', 1, pndark}, {'d', 1, pndeaf}, {'f', 1, pfile}, {'n', 1, pryour}, {'p', 1, prname}, {'s', 2, pcansee}}; #define NUM_CODES (sizeof codes / sizeof(struct _code)) static void start_line (FILE * file) { char snoop_prompt[40]; int i; fix_color (snoop_prompt, "\r&+BO&+W> &*"); if (new_line && snooplev > 0) { for (i = 0; i < snooplev; i++) { fprintf (file, "%s", snoop_prompt); } } } static void kiputs (char *s, FILE * file) { char *t, buff[32768], buff2[65536], cbuff[65536]; if (strchr (s, '@') != NULL && strlen (s) <= 32768) { strcpy (buff, s); special_codes (cbuff, buff); s = cbuff; } if (strchr (s, '&') != NULL && strlen (s) <= 32768) { strcpy (buff, s); fix_color (buff2, buff); } else strcpy (buff2, s); s = buff2; start_line (file); while ((t = (char *) strchr (s, '\n')) != NULL) { *t = '\0'; fputs (s, file); if (ststflg (mynum, SFL_COLOR)) fputs ("\033[40m\033[0m", file); fputs ("\n\r", file); *t = '\n'; new_line = True; start_line (file); s = t + 1; } if (*s != '\0') { fputs (s, file); new_line = False; } } static void makebfr () { if ((bufptr = sysbuf = NEW (char, SYSBUFSIZE + BUFSIZ)) == NULL) { mudlog ("ERROR: Out of Memory"); __exit (1); } sysbuf[0] = 0; buflen = 0; } static int _code_cmp (const void *c, const void *code) { return (*((const char *) c) - ((const struct _code *) code)->name); } static int tocontinue (char **ct) { register char *s = *ct; register int n = 1; register int nest = 0; struct _code *code; for (; n; s++) { switch (*s) { case '\002': case '\003': --n; break; case '\001': if (*++s != '\001') { code = (struct _code *) bsearch (s, (char *) codes, NUM_CODES, sizeof (struct _code), _code_cmp); if (code == NULL) { mudlog ("ERROR: tocontinue(): Unknown control code %3o", 0377 & *s); __exit (2); } n += code->args; nest = 1; } break; case '\0': mudlog ("ERROR: tocontinue(): Buffer overrun\n"); mudlog ("-----: txt: %s", *ct); __exit (2); break; } } *ct = s; return (nest); } static void dcprnt (char *ct, FILE * file) { char *str; char bk[100]; struct arg args[MAX_ARGS + 1]; struct _code *code; int n; while (*(str = ct)) { if ((ct = strchr (str, '\001')) == NULL) { kiputs (str, file); break; } *ct = '\0'; kiputs (str, file); *ct++ = '\001'; if (*ct == '\001') { kiputs ("\001", file); ct++; } else { code = (struct _code *) bsearch ((char *) ct, (char *) codes, NUM_CODES, sizeof (struct _code), _code_cmp); if (code == NULL) { mudlog ("ERROR: dcprnt(): Unknown control code %c (%3o) \n", *ct, 0377 & *ct); mudlog ("-----: ct[0..19] = \"%s\".", mk_string (bk, ct, 20, -1)); __exit (2); } else { args[0].str = ++ct; for (n = 1; n <= code->args; n++) { args[n - 1].nest = tocontinue (&ct); ct[-1] = '\0'; args[n].str = ct; } code->func (args, file); for (n = 1; n <= code->args; n++) args[n].str[-1] = '\003'; } } } } static void pfilter (struct arg *args, FILE * file) { FILE *a; char x[BUFSIZ]; if ((a = popen (args[0].str, "r")) == NULL) mudlog ("ERROR: [Cannot find filter ->%s]\n", args[0].str); else { while (fgets (x, sizeof x, a)) kiputs (x, file); pclose (a); } } static void pfile (struct arg *args, FILE * file) { FILE *a; char x[BUFSIZ]; if ((a = fopen (args[0].str, "r")) == NULL) mudlog ("ERROR: [Cannot find file ->%s]\n", args[0].str); else { while (fgets (x, sizeof (x), a)) kiputs (x, file); fclose (a); } } static void pndeaf (struct arg *args, FILE * file) { if (!ststflg (mynum, SFL_DEAF)) { prnt (args[0], file); } } static void pcls (struct arg *args, FILE * file) { bprintf ("\033[2J\033[H"); } static void pcansee (struct arg *args, FILE * file) { int a; a = fpbns (args[0].str); if (seeplayer (a) && (a != -1)) { prnt (args[1], file); } } static void prname (struct arg *args, FILE * file) { kiputs (seeplayer (fpbns (args[0].str)) ? args[0].str : "Someone", file); } static void pryou (struct arg *args, FILE * file) { kiputs ((fpbns (args[0].str) == mynum) ? "you" : args[0].str, file); } /* * Prints "your" if player is the receiver, otherwise prints the * possessive form of the receiver's name */ static void pryour (struct arg *args, FILE * file) { if (fpbns (args[0].str) == mynum) kiputs ("your", file); else { kiputs (args[0].str, file); kiputs ("'s", file); } } static void pndark (struct arg *args, FILE * file) { if ((!isdark ()) && (!ststflg (mynum, SFL_BLIND))) { prnt (args[0], file); } } static void pansi (struct arg *args, FILE * file) { if (cur_player->iamon && ststflg (mynum, SFL_COLOR)) { prnt (args[0], file); } } static void ppndeaf (struct arg *args, FILE * file) { if (!ststflg (mynum, SFL_DEAF)) prname (args, file); } static void ppnblind (struct arg *args, FILE * file) { if (!ststflg (mynum, SFL_BLIND)) prname (args, file); } void print_buf (char *b, Boolean notself) { int plr; int ct = 0; int me = real_mynum; Boolean n1, n2; if (cur_player->in_pbfr) return; cur_player->in_pbfr = True; n1 = new_line; if (!notself) dcprnt (b, cur_player->stream); n2 = new_line; if (cur_player->iamon && ploc (mynum) < 0 && !EMPTY (pname (mynum)) && cur_player->snooped > 0) { ++snooplev; for (plr = 0; plr < max_players; plr++) { if (!is_in_game (plr)) continue; if (players[plr].snooptarget == me) { ++ct; xsetup_globals (plr); new_line = n1; print_buf (b, False); fflush (cur_player->stream); } } xsetup_globals (me); new_line = n2; --snooplev; if (ct != cur_player->snooped) { mudlog ("ERROR: Internal error, snooped = %d, ct = %d, check print_buf", cur_player->snooped, ct); } } cur_player->in_pbfr = False; } void pbfr (void) { if (sysbuf == NULL) { makebfr (); } if (buflen > 0 && cur_player != NULL && cur_player->stream != NULL) { print_buf (sysbuf, False); sysbuf[0] = 0; /* clear buffer */ bufptr = sysbuf; buflen = 0; new_line = True; } } void bflush (void) { if (cur_player != NULL && cur_player->stream != NULL) { pbfr (); fflush (cur_player->stream); } } void snoopcom (void) { Boolean stop_snoop = False; int plr; if (!ptstflg (mynum, PFL_SNOOP)) { erreval (); return; } if (cur_player->snooptarget >= 0) { bprintf ("Stopped snooping on %s.\n", pname (cur_player->snooptarget)); snoop_off (mynum); stop_snoop = True; } if ((plr = pl1) < 0) { if (!stop_snoop) bprintf ("Snoop Who?\n"); return; } else if (plr >= max_players) { bprintf ("You can't snoop %s!\n", pname (plr)); return; } else if (plr == mynum) { bprintf ("You can't snoop yourself!\n"); return; } if (!do_okay (mynum, plr, PFL_NOSNOOP)) { bprintf ("Your magical vision is obscured.\n"); return; } /* Is this a PRIVATE room? If so don't let them snoop. */ if (ltstflg (ploc (plr), LFL_PRIVATE) && plev (mynum) < LVL_ARCHWIZARD) { bprintf ("I'm sorry, %s, but the room is private.\n", psex (mynum) ? "Madam" : "Sir"); return; } cur_player->snooptarget = plr; ++(players[plr].snooped); /* One more to snoop him */ bprintf ("Started to snoop on %s.\n", pname (plr)); } /* Make player no longer snoop his target */ void snoop_off (int plr) { int target; if ((target = players[plr].snooptarget) >= 0) { players[plr].snooptarget = -1; /* One less to snoop him: */ if (--players[target].snooped < 0) players[target].snooped = 0; } } #ifdef VARGS void bprintf (char *format,...) { va_list pvar; register int len; if (!sysbuf) makebfr (); if (cur_player == NULL) { return; va_start (pvar, format); vprintf (format, pvar); va_end (pvar); } else if (cur_player->stream == NULL) { return; } else { va_start (pvar, format); vsprintf (bufptr, format, pvar); len = strlen (bufptr); buflen += len; va_end (pvar); if (buflen >= SYSBUFSIZE) pbfr (); else bufptr += len; } } #else void bprintf (char *format, char *a1, char *a2, char *a3, char *a4, char *a5, char *a6, char *a7, char *a8, char *a9) { register int len; if (!sysbuf) makebfr (); if (cur_player == NULL) { printf (format, a1, a2, a3, a4, a5, a6, a7, a8, a9); } else { sprintf (bufptr, format, a1, a2, a3, a4, a5, a6, a7, a8, a9); len = strlen (bufptr); buflen += len; if (buflen >= SYSBUFSIZE) pbfr (); else bufptr += len; } } #endif /**************************************************************** * iDiRT Color Parser * * * * Handles color parsing of output/input to the game. * * * * Written by ErIC for Northern Lights, 1993 * * [Changes by Illusion] * * * * This parser handles screen clearing codes and newline codes. * * (Illusion, 1995) * * * * Blinking Characters Added * * (Illusion, April 27, 1995) * ****************************************************************/ #define colorcode(x) ( (x>=64 && x<=127) ? color_table[x-64] : 0 ) char color_table[] = { /* Not beautiful, but efficient :) */ 0, 0, '4', '6', 0, 0, 0, '2', 0, 0, 0, 0, '0', '5', 0, 0, 0, 0, '1', 0, 0, 0, 0, '7', 0, '3', 0, 0, 0, 0, 0, 0, 0, 0, '4', '6', 0, 0, 0, '2', 0, 0, 0, 0, '0', '5', 0, 0, 0, 0, '1', 0, 0, 0, 0, '7', 0, '3', 0, 0, 0, 0, 0, 0, }; void fix_color (char *dests, char *srcs) { unsigned char *dest = (unsigned char *) dests; unsigned char *src = (unsigned char *) srcs; while (*src != 0) { if (*src != '&') { *dest++ = *src++; } else { switch (*(src + 1)) { case '&': src += 2; *dest++ = '&'; continue; case '+': if (colorcode (*(src + 2))) { if (ststflg (mynum, SFL_COLOR)) { strcpy ((char *) dest, "\033[1;30m"); dest[5] = colorcode (*(src + 2)); if (*(src + 2) >= 96) dest[2] = '0'; dest += 7; } src += 3; continue; } else { *dest++ = *src++; continue; } case '-': if (colorcode (*(src + 2))) { if (ststflg (mynum, SFL_COLOR)) { strcpy ((char *) dest, "\033[1;40m"); dest[5] = colorcode (*(src + 2)); if (*(src + 2) >= 96) dest[2] = '0'; dest += 7; } src += 3; continue; } else { *dest++ = *src++; continue; } case '=': if (colorcode (*(src + 2)) && colorcode (*(src + 3))) { if (ststflg (mynum, SFL_COLOR)) { strcpy ((char *) dest, "\033[1;40;30m"); dest[5] = colorcode (*(src + 3)); dest[8] = colorcode (*(src + 2)); if (*(src + 2) >= 96) dest[2] = '0'; dest += 10; } src += 4; continue; } else { *dest++ = *src++; continue; } case '*': if (ststflg (mynum, SFL_COLOR)) { strcpy ((char *) dest, "\033[40m\033[0m"); dest += strlen ((char *) dest); } src += 2; continue; /* Blinking */ case 'B': if (ststflg (mynum, SFL_COLOR)) { if (ststflg (mynum, SFL_NOBLINK)) strcpy ((char *) dest, ""); else strcpy ((char *) dest, "\033[5m"); dest += strlen ((char *) dest); } src += 2; continue; /* Carriage return for titles */ case '>': strcpy ((char *) dest, "\r\n "); dest += strlen ((char *) dest); src += 2; continue; /* Carriage return */ case '/': strcpy ((char *) dest, "\r\n"); dest += strlen ((char *) dest); src += 2; continue; /* Beep */ case '#': if (ststflg (mynum, SFL_NOBEEP)) strcpy ((char *) dest, ""); else strcpy ((char *) dest, "\a"); dest += strlen ((char *) dest); src += 2; continue; default: *dest++ = *src++; continue; } } } *dest = 0; } void strip_color (char *dests, char *srcs) { unsigned char *dest = (unsigned char *) dests; unsigned char *src = (unsigned char *) srcs; while (*src != 0) { if (*src != '&') { *dest++ = *src++; } else { switch (*(src + 1)) { case '&': src += 2; *dest++ = '&'; continue; case '+': if (colorcode (*(src + 2))) { src += 3; continue; } else { *dest++ = *src++; continue; } case '-': if (colorcode (*(src + 2))) { src += 3; continue; } else { *dest++ = *src++; continue; } case '=': if (colorcode (*(src + 2)) && colorcode (*(src + 3))) { src += 4; continue; } else { *dest++ = *src++; continue; } case '*': src += 2; continue; case 'B': src += 2; continue; case '#': src += 2; continue; default: *dest++ = *src++; continue; } } } *dest = 0; } /* Checks for special codes in output * 1995, Illusion */ void special_codes (char *dests, char *srcs) { unsigned char *dest = (unsigned char *) dests; unsigned char *src = (unsigned char *) srcs; int ct; while (*src != 0) { if (*src != '@') { *dest++ = *src++; } else { switch (*(src + 1)) { case '@': src += 2; *dest++ = '@'; continue; /* Display Version Number */ case 'V': strcpy ((char *) dest, _VERSION_); dest += strlen ((char *) dest); src += 2; continue; /* Clear screen */ case 'C': strcpy ((char *) dest, "\033[2J\033[H"); dest += strlen ((char *) dest); src += 2; continue; /* Display a File */ case 'F': ct = 0; default: *dest++ = *src++; continue; } } } *dest = 0; } /**************************************** * File Pager * * 1995, Illusion * ****************************************/ void file_pager (char filename[512]) { FILE *file; if (!ppager (mynum)) { bprintf ("\001f%s\003", filename); return; } if ((file = fopen (filename, "r")) == NULL) { bprintf ("&+RError reading file: &+Y%s\n", filename); mudlog ("ERROR: Cannot read file: %s", filename); return; } cur_player->pager.old_handler = (INP_HANDLER *) cur_player->inp_handler->inp_handler; cur_player->inpager = True; cur_player->pager.file = file; pager (NULL); return; } void quit_pager (void) { cur_player->inpager = False; replace_input_handler ((void *) cur_player->pager.old_handler); fclose (cur_player->pager.file); bprintf ("\n%s", cur_player->cprompt); if (cur_player->inmailer) bprintf ("%s", cur_player->cprompt); return; } void pager (char *c) { char pageprompt[] = "&+W(&*Press &+W[&+CReturn&+W] &*to continue, " "&+W'&+CQ&+W' &*to quit, &+W'&+C!<command>&+W' " "&*to use a MUD command&+W)&*"; char ch[255]; int ct; int len = ppager (mynum); if (c == NULL) { for (ct = 0; ct != len; ct++) { if (feof (cur_player->pager.file)) { quit_pager (); return; } ch[0] = '\0'; fgets (ch, 250, cur_player->pager.file); bprintf ("%s", ch); } bprintf ("%s", pageprompt); replace_input_handler (pager); } else { if (c[0] == 'q' || c[0] == 'Q' || feof (cur_player->pager.file)) { quit_pager (); return; } if (c[0] == '!') { gamecom (&c[1], False); bprintf ("%s", pageprompt); return; } for (ct = 0; ct != len; ct++) { if (feof (cur_player->pager.file)) { quit_pager (); return; } ch[0] = '\0'; fgets (ch, 250, cur_player->pager.file); bprintf ("%s", ch); } bprintf ("%s", pageprompt); return; } }