/* * editor.c */ #include <memory.h> #include <stdlib.h> #include "config.h" #include "player.h" #include "fix.h" /* externs */ extern struct command editor_list[]; extern char *end_string(); /* interns */ void editor_main(); /* print out some stats */ void edit_stats(player * p, char *str) { int words = 0, lines = 0, blip = 0; char *scan, *oldstack; oldstack = stack; for (scan = p->edit_info->buffer; *scan; scan++) { switch (*scan) { case ' ': if (blip) words++; blip = 0; break; case '\n': if (blip) words++; blip = 0; lines++; break; default: blip = 1; } } sprintf(oldstack, " Used %d bytes out of %d, in %d lines and %d words.\n", p->edit_info->size, p->edit_info->max_size, lines, words); stack = end_string(stack); tell_player(p, oldstack); stack = oldstack; } /* view the entire buffer */ void edit_view(player * p, char *str) { tell_player(p, p->edit_info->buffer); } /* insert a line into the buffer */ void insert_line(player * p, char *str) { ed_info *e; int len; char *from, *to, *oldstack; e = p->edit_info; oldstack = stack; sprintf(stack, "%s\n", str); len = strlen(oldstack); if ((len + e->size) >= (e->max_size)) { tell_player(p, " Line too long to fit into buffer.\n"); return; } from = e->buffer + e->size; to = from + len; while (from != e->current) *(--to) = *(--from); *(--to) = *(--from); e->size += len; for (; len; len--) *(e->current)++ = *stack++; *stack++ = 0; tell_player(p, oldstack); stack = oldstack; } /* save and restore important flags that the editor changes */ void save_flags(player * p) { if (!p->edit_info) return; p->edit_info->flag_copy = p->flags; p->edit_info->sflag_copy = p->saved_flags; p->edit_info->input_copy = p->input_to_fn; p->flags &= ~PROMPT; if (p->saved_flags & QUIET_EDIT) p->saved_flags |= BLOCK_TELLS | BLOCK_SHOUT; p->input_to_fn = editor_main; } void restore_flags(player * p) { if (!p->edit_info) return; p->flags = p->edit_info->flag_copy; p->saved_flags = p->edit_info->sflag_copy; p->input_to_fn = p->edit_info->input_copy; } /* the main editor function */ void editor_main(player * p, char *str) { if (!p->edit_info) { log("error", "Editor called with no edit_info"); return; } if (*str == '/') { restore_flags(p); match_commands(p, str + 1); save_flags(p); return; } if (*str == '.') { sub_command(p, str + 1, editor_list); if (p->edit_info) do_prompt(p, "+"); return; } insert_line(p, str); do_prompt(p, "+"); } /* fire editor up */ void start_edit(player * p, int max_size, void *finish_func, void *quit_func, char *current) { ed_info *e; int old_length; if (p->edit_info) return; e = (ed_info *) MALLOC(sizeof(ed_info)); memset(e, 0, sizeof(ed_info)); p->edit_info = e; e->buffer = (char *) MALLOC(max_size); memset(e->buffer, 0, max_size); e->max_size = max_size; e->finish_func = finish_func; e->quit_func = quit_func; if (current) { old_length = strlen(current); memcpy(e->buffer, current, old_length); e->size = old_length + 1; } else e->size = 1; e->current = e->buffer + e->size - 1; p->flags |= DONT_CHECK_PIPE; save_flags(p); tell_player(p, " Entering editor ... Use /help editor for help.\n" " /<command> for general commands, .<command> for editor " "commands\n" " Use '.end' to finish and keep edit\n"); if (p->saved_flags & QUIET_EDIT) tell_player(p, " Blocking shouts and tells whilst in editor.\n"); edit_view(p, 0); edit_stats(p, 0); do_prompt(p, "+"); } /* tie up any loose ends */ void finish_edit(player * p) { if (!(p->edit_info)) return; restore_flags(p); if (p->edit_info->buffer) FREE(p->edit_info->buffer); FREE(p->edit_info); p->edit_info = 0; p->flags &= ~DONT_CHECK_PIPE; } /* editor functions */ /* finish editing without changes */ void edit_quit(player * p, char *str) { void (*fn) (); fn = p->edit_info->quit_func; (*fn) (p); finish_edit(p); } /* finish editing with changes */ void edit_end(player * p, char *str) { void (*fn) (); fn = p->edit_info->finish_func; (*fn) (p); finish_edit(p); } /* clean the buffer completely */ void edit_wipe(player * p, char *str) { ed_info *e; e = p->edit_info; memset(e->buffer, 0, e->size); e->size = 1; e->current = e->buffer; tell_player(p, " Edit buffer completely wiped ...\n"); } /* view the current line */ void edit_view_line(player * p, char *str) { char *scan, *oldstack; oldstack = stack; scan = p->edit_info->current; while (*scan && *scan != '\n') *stack++ = *scan++; *stack++ = '\n'; *stack++ = 0; tell_player(p, oldstack); stack = oldstack; } /* move back up a line */ void edit_back_line(player * p, char *str) { char *c; ed_info *e; e = p->edit_info; c = e->current; if (c == e->buffer) { tell_player(p, " Can't go back any more, top of buffer.\n"); return; } /* c -= 2;*/ c--; while (c >= e->buffer && *c != '\n') c--; if (c == e->buffer) tell_player(p, " Reached top of buffer.\n"); else c++; e->current = c; edit_view_line(p, 0); } /* move forward a line */ void edit_forward_line(player * p, char *str) { char *c; ed_info *e; e = p->edit_info; c = e->current; if (!*c) { tell_player(p, " Can't go forward, bottom of buffer.\n"); return; } while (*c && *c != '\n') c++; if (*c) c++; e->current = c; if (!*c) tell_player(p, " Reached bottom of buffer.\n"); else edit_view_line(p, 0); } /* print out available commands */ void edit_view_commands(player * p, char *str) { view_sub_commands(p, editor_list); } /* move to bottom of buffer */ void edit_goto_top(player * p, char *str) { p->edit_info->current = p->edit_info->buffer; tell_player(p, " Top of buffer.\n"); } /* move to top of buffer */ void edit_goto_bottom(player * p, char *str) { p->edit_info->current = p->edit_info->buffer + p->edit_info->size - 1; tell_player(p, " Bottom of buffer.\n"); } /* delete the current line */ void edit_delete_line(player * p, char *str) { ed_info *e; char *sl, *el; e = p->edit_info; sl = e->current; if (!*sl) { tell_player(p, " End of buffer, no line to delete.\n"); return; } for (el = sl; (*el && *el != '\n'); el++) e->size--; if (*el) { el++; e->size--; } while (*el) *sl++ = *el++; while (sl != el) *sl++ = 0; tell_player(p, " Line deleted.\n"); } /* go to a specific line */ void edit_goto_line(player * p, char *str) { char *scan; int line = 0; line = atoi(str); if (line < 1) { tell_player(p, " Argument is a number greater than zero.\n"); return; } for (line--, scan = p->edit_info->buffer; (*scan && line); scan++) if (*scan == '\n') line--; if (!*scan) { tell_player(p, " Not that many lines.\n"); return; } p->edit_info->current = scan; edit_view_line(p, 0); } /* toggle whether someone goes into quiet mode on edit */ void toggle_quiet_edit(player * p, char *str) { restore_flags(p); if (!strcasecmp("off", str)) p->saved_flags &= ~QUIET_EDIT; else if (!strcasecmp("on", str)) p->saved_flags |= QUIET_EDIT; else p->saved_flags ^= QUIET_EDIT; if (p->saved_flags & QUIET_EDIT) tell_player(p, " You will block tells and shouts upon editing.\n"); else tell_player(p, " You won't block shouts and tells on editing.\n"); save_flags(p); } /* the dreaded pager B-) */ int draw_page(player * p, char *text) { int end_line = 0, n; ed_info *e; char *oldstack; oldstack = stack; for (n = TERM_LINES + 1; n; n--, end_line++) { while (*text && *text != '\n') *stack++ = *text++; if (!*text) break; *stack++ = *text++; } *stack++ = 0; tell_player(p, oldstack); if (*text && p->edit_info) { e = p->edit_info; end_line += e->size; sprintf(oldstack, "(Pager: lines %d to %d, from a total %d) Type n for next page: " "\n",e->size, end_line, e->max_size); stack = end_string(oldstack); do_prompt(p, oldstack); } stack = oldstack; return *text; } void quit_pager(player * p, ed_info * e) { p->input_to_fn = e->input_copy; p->flags = e->flag_copy; if (e->buffer) FREE(e->buffer); FREE(e); p->edit_info = 0; } void back_page(player * p, ed_info * e) { char *scan; int n; scan = e->current; for (n = TERM_LINES + 1; n; n--) { while (scan != e->buffer && *scan != '\n') scan--; if (scan == e->buffer) break; e->size--; scan--; } e->current = scan; } void forward_page(player * p, ed_info * e) { char *scan; int n; scan = e->current; for (n = TERM_LINES + 1; n; n--) { while (*scan && *scan != '\n') scan++; if (!*scan) break; e->size++; scan++; } e->current = scan; } void pager_fn(player * p, char *str) { ed_info *e; e = p->edit_info; switch (tolower(*str)) { case 'b': back_page(p, e); break; case 'p': back_page(p, e); break; case 0: forward_page(p, e); break; case 'f': forward_page(p, e); break; case 'n': forward_page(p, e); break; case 't': e->current = e->buffer; e->size = 0; draw_page(p, e->current); break; case 'q': quit_pager(p, e); return; } if (!draw_page(p, e->current)) quit_pager(p, e); } void pager(player * p, char *text, int page) { ed_info *e; int length = 0, lines = 0; char *scan; if (p->saved_flags & NO_PAGER && !page) { tell_player(p, text); return; } if (p->edit_info) { tell_player(p, " Eeek, can't enter pager right now.\n"); return; } for (scan = text; *scan; scan++, length++) { if (*scan == '\n') { lines++; } length++; } if (lines > (TERM_LINES + 1)) { e = (ed_info *) MALLOC(sizeof(ed_info)); memset(e, 0, sizeof(ed_info)); p->edit_info = e; e->buffer = (char *) MALLOC(length); memcpy(e->buffer, text, length); e->current = e->buffer; e->max_size = lines; e->size = 0; e->input_copy = p->input_to_fn; e->flag_copy = p->flags; p->input_to_fn = pager_fn; p->flags &= ~PROMPT; } draw_page(p, text); }