#define WRITER_C #include "kernel.h" #include <stdlib.h> #include "config.h" #include "writer.h" #include "bprintf.h" #include "mud.h" #include "parse.h" typedef struct _wr_line { struct _wr_line *next; char *s; } WrLine; typedef struct { void *previous; char *prevprompt; void (*exit_handler) (void *w, void *arg, int arglen); void (*old_inp_h) (char *str); char *prompt; void *arg; int arglen; int flags; int max_lines; int num_lines; WrLine *first, *last; } WrHead; static void write_handler (char *line); void start_writer (char *h, char *p, void *arg, int arglen, void handler (void *x, void *arg, int arglen), int flags, int max_lines) { WrHead *w; if (handler == NULL || h == NULL || p == NULL || max_lines <= 0) return; w = NEW (WrHead, 1); w->previous = cur_player->writer; w->prevprompt = COPY (cur_player->prompt); w->exit_handler = handler; w->old_inp_h = cur_player->inp_handler->inp_handler; w->prompt = COPY (p); w->arg = BCOPY (arg, arglen); w->arglen = arglen; w->flags = flags; w->max_lines = max_lines; w->num_lines = 0; w->first = NULL; w->last = NULL; cur_player->writer = w; strcpy (cur_player->prompt, p); bprintf ("%s\n\n", h); write_handler (NULL); } static void write_handler (char *line) { WrHead *w = (WrHead *) cur_player->writer; WrLine *l; int k; if ((k = (w->flags & WR_CMDCH)) == 0) k = '*'; if (line == NULL) { replace_input_handler (write_handler); } else if (*line == k) { if (line[1] == k && line[2] == '\0') { /* Exit writer. */ replace_input_handler (w->old_inp_h); /* Back to old handler */ free (w->prompt); /* Don't need the prompt any more */ if (w->first == NULL) { /* Let it point to text instead */ w->prompt = NULL; } else { w->prompt = w->first->s; } cur_player->writer = w->previous; strcpy (cur_player->prompt, w->prevprompt); free (w->prevprompt); /* Don't need max lines anymore, use it for unget buffer */ w->max_lines = EOF; w->exit_handler (w, w->arg, w->arglen); bprintf ("\r%s", cur_player->prompt); return; /* Don't increment num_lines. */ } else if ((w->flags & WR_CMD) != 0) { Game_Com (line + 1, True); } else { bprintf ("You cannot execute any commands now.\n"); } } else if (w->num_lines == w->max_lines) { bprintf ("You cannot type in more lines.\n"); } else { l = NEW (WrLine, 1); l->s = COPY (line); l->next = NULL; if (w->first == NULL) { /* First line. */ w->first = w->last = l; } else { w->last->next = l; w->last = l; } ++w->num_lines; } bprintf ("\r%s", cur_player->prompt); } int wnum_lines (void *x) { WrHead *w = x; return w == 0 ? 0 : w->num_lines; } int wnum_chars (void *x) { WrHead *w = x; WrLine *n; int k = 0; if (w == 0) return 0; for (n = w->first; n != 0; n = n->next) k += strlen (n->s); return k; } int wgetc (void *x) { WrHead *w = x; WrLine *l; WrLine *n; int k; if (w == NULL) return EOF; if ((k = w->max_lines) != EOF) { w->max_lines = EOF; return k; /* return unget character */ } if (w->prompt == NULL) { free (w->arg); free (w); return EOF; } if ((k = *w->prompt++) == '\0') { /* End of this line, kill it and return '\n' */ l = w->first; if ((n = w->first = l->next) == NULL) { w->prompt = NULL; } else { w->prompt = n->s; } w->num_lines--; free (l->s); free (l); return '\n'; } else { return k; } } int wungetc (int c, void *x) { WrHead *w; WrLine *l; if ((w = x) == NULL) return EOF; if (c == EOF) { while ((l = w->first) != NULL) { w->first = l->next; free (l->s); free (l); } w->prompt = NULL; w->num_lines = 0; return EOF; } if ((l = w->first) != NULL && w->prompt > l->s) { *--(w->prompt) = c; return c; } /* Try to put it into max_lines */ if (w->max_lines != EOF) return EOF; /* Unable to push character back */ w->max_lines = c; return c; } char *wgets (char *buf, int buflen, void *w) { int i, k; char *s = buf; for (i = 1; i < buflen; i++) { if ((k = wgetc (w)) == EOF) { *s = 0; return NULL; } if ((*s++ = k) == '\n') break; } *s = 0; return buf; } void terminate_writer (void *w) { if (w != NULL) { (void) wungetc (EOF, w); (void) wgetc (w); } } void terminate_all_writers (int plx) { WrHead *w; WrHead *x; if (plx >= 0 && plx < max_players) { w = players[plx].writer; while ((x = w) != NULL) { w = w->previous; terminate_writer (x); } } }