/* * 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(), *next_space(); extern int strnomatch(char *, char *, int); /* 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->system_flags; p->edit_info->tflag_copy = p->tag_flags; p->edit_info->cflag_copy = p->custom_flags; p->edit_info->mflag_copy = p->misc_flags; p->edit_info->input_copy = p->input_to_fn; p->flags &= ~PROMPT; if (p->custom_flags & QUIET_EDIT) p->tag_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->system_flags = p->edit_info->sflag_copy; p->tag_flags = p->edit_info->tflag_copy; p->custom_flags = p->edit_info->cflag_copy; p->misc_flags = p->edit_info->mflag_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->custom_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; 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; int do_list = 1, i; if (*str) do_list = atoi(str); if (do_list < 0) { tell_player(p, " Format: .del <num lines - default is 1>\n"); return; } for (i = 0; i < do_list; i++) { 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; } if (i > 1) tell_player(p, " Lines deleted.\n"); else 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->custom_flags &= ~QUIET_EDIT; else if (!strcasecmp("on", str)) p->custom_flags |= QUIET_EDIT; else p->custom_flags ^= QUIET_EDIT; if (p->custom_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; float pdone; 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; pdone = ((float) end_line / (float) e->max_size) * 100; sprintf(oldstack, "[Pager: %d-%d (%d) [%.0f%%] Tap <return> to continue, or q to quit]" "\n",e->size, end_line, e->max_size, pdone); 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->custom_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); } void editor_search_string(player * p, char *str) { ed_info *e; char *this_line, *this_word; int x = 0; char *oldstack; if (!*str) { tell_player(p, " Format: .s <search string>\n"); return; } e = p->edit_info; this_line = e->current; for (this_word = e->current; *this_word && !x; this_word++) { if (*this_word == '\n') this_line = this_word + 1; if (!((isspace(*(this_word-1)) && !(isspace(*this_word))))) ; else if (!strnomatch(str,this_word, 1)) x = 1; } if (!x) { tell_player(p, " String not found before end of buffer reached.\n"); return; } else { p->edit_info->current = this_line; edit_view_line(p, 0); } } int countquote(char *str) { int cnt = 0; while (*str) { if (*str == '\"') cnt++; str++; } return cnt; } void edit_search_and_replace(player * p, char *str) { ed_info *e; char buff[10000], search[50], replace[50], *holder, *oldstack; int b = 0, cnt = 0, s=0, r=0; if (countquote(str) != 4) { tell_player(p, " Format: .sr \"search\" \"replace\"\n"); return; } for (b=0; b < 10000; b++) buff[b] = 0; b=0; e = p->edit_info; for (s=0; s < 50; s++) { search[s] = 0; replace[s] = 0; } s=0; while (*str && *str != '\"') str++; str++; while (*str && *str != '\"') { if (s < 50) search[s++] = *str++; else str++; } str++; while (*str && *str != '\"') str++; str++; while (*str && *str != '\"') { if (r < 50) replace[r++] = *str++; else str++; } for (holder = e->buffer; (*holder && b < 10000); holder++) { if (strnomatch(search, holder, 1)) buff[b++] = *holder; else { cnt++; r = 0; s = 0; while (replace[r] && b < 10000) buff[b++] = replace[r++]; while (search[s] && *holder && search[s]==*holder) { holder++; s++; } holder--; /* if (*holder && b < 10000) buff[b++] = *holder; */ } } /* will this work?! guess so.. */ strncpy(e->buffer, buff, e->max_size); if (cnt) { oldstack = stack; if (cnt != 1) sprintf(stack, " %d replacements made.\n", cnt); else strcpy(stack, " One replacement made.\n"); stack = end_string(stack); tell_player(p, oldstack); e->current = e->buffer; stack = oldstack; } else tell_player(p, " No changes made.\n"); }