/**************************************************************************** ** pDIRT: GPE (General Purpose Editor) ** ** Author : Peter Eussen ** Version : 1.01 ** Last Revision: 18 Jan 1996 ** ** This editor replaces the old 'writer' with a almost fully featured ** editor. Although the editing has been greatly improved, the interface ** has simplified, which causes some problems with implementation, but ** that's not of my concern any more, since it works for me ;) ** ** To start the editor, use the start_editor() function which needs: ** Player number, function that handles the file created by the editor ** Maximum amount of lines the player can type, and an optional parameter, ** which you can use to store data (use NULL if not needed). ** ** The editor allows you to review your text, overwrite lines, delete lines, ** append lines, cancel and quit. The prompt is automatically built. **************************************************************************/ #include "kernel.h" #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "mud.h" #include "log.h" #include "parse.h" #include "editor.h" #include "bprintf.h" /**************************************************************************** ** PROTOTYPES ****************************************************************************/ void editor_reader(char *inp); void end_editor(void); void delete_line(int i); void review(Line *start); void reinitialise_editor(void); Line *find_line(int nr); static char *Edit_Header = "&+w[ &+wpDirt&+w Editor V1.01 ========================================================&+w]&*\n" "&+w[ &+w~c &+wCancel Editor &+w~d <n> &+wDelete Line &+wn&* &+w]&*\n" "&+w[ &+w~q &+wEnd Editor &+w~r &+wReview Current Message &+w]&*\n" "&+w[ &+w~h &+wEditor Help &+w~e <command> &+wExecute &+wCommand&*. &+w]&*\n" "&+w[ &+w~a &+wAppend at the End. &+w~o <n> &+wStart Overwriting at line &+wn&* &+w]&*\n" "&+w[&+w============================================================================&+w]&*\n"; int start_file_editor(FILE *outp, void (*func)(char *,char *), int max_lines, char *fn) { if (cur_player->editor.active) { bprintf("Close other editor first.\n"); return 0; } if (fn == NULL) { mudlog("ERROR: start_file_writer() with no filename"); return -1; } if (outp == NULL) { mudlog("ERROR: start_file_writer() with no file."); return -1; } bprintf(Edit_Header); cur_player->editor.fp = outp; strcpy(cur_player->editor.filename,fn); strcpy(cur_player->editor.old_prompt,cur_player->prompt); cur_player->editor.func = func; cur_player->editor.start = NULL; cur_player->editor.current = NULL; cur_player->editor.parameter = NULL; cur_player->editor.num_lines = 0; cur_player->editor.max_lines = max_lines; cur_player->editor.active = True; cur_player->editor.mode = Append; push_input_handler(editor_reader); sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.num_lines+1); bprintf("\r%s",cur_player->prompt); return 1; } /***************************************************************************** ** START_EDITOR ** Initialisation routine. Sets up all parameters needed for this editor. *****************************************************************************/ int start_editor(int player, void (*func)(char *,char *),int max_lines, char *param) { int save_mynum = real_mynum; setup_globals(player); if (cur_player->editor.active) { bprintf("Close other editor first.\n"); return 0; } bprintf(Edit_Header); sprintf(cur_player->editor.filename,"%s/TMP/Editor.%s",data_dir,pname(mynum)); cur_player->editor.fp = fopen(cur_player->editor.filename,"w"); if (cur_player->editor.fp == NULL) { fwerror(cur_player->editor.filename); return -1; } strcpy(cur_player->editor.old_prompt,cur_player->prompt); cur_player->editor.func = func; cur_player->editor.start = NULL; cur_player->editor.current = NULL; cur_player->editor.num_lines = 0; cur_player->editor.max_lines = max_lines; cur_player->editor.active = True; cur_player->editor.mode = Append; if (param == NULL) cur_player->editor.parameter = NULL; else { cur_player->editor.parameter = NEW(char,strlen(param) + 1); strcpy(cur_player->editor.parameter,param); } push_input_handler(editor_reader); sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.num_lines+1); bprintf("\r%s",cur_player->prompt); setup_globals(save_mynum); return 1; } void editor_reader(char *inp) { Line *l=NULL; if (inp == NULL) replace_input_handler(editor_reader); else if (inp[0] == '~' || inp[0] == '$' || inp[0] == '*') { /* Process commands */ switch(inp[1]) { case 'c' : /* Cancel Editor */ case 'C' : bprintf("&+wEditor Cancelled.\n"); end_editor(); unlink(cur_player->editor.filename); cur_player->editor.func(NULL,cur_player->editor.parameter); reinitialise_editor(); return; case '*' : /* Quit Editor */ case 'q' : case 'Q' : bprintf("&+wQuitting Editor.\n"); end_editor(); if (cur_player->editor.num_lines == 0) cur_player->editor.func(NULL,cur_player->editor.parameter); else cur_player->editor.func(cur_player->editor.filename, cur_player->editor.parameter); reinitialise_editor(); return; case 'D' : /* Delete line or last line */ case 'd' : inp += 2; while(!isdigit(*inp) && *inp != '\0') inp++; if (isdigit(*inp)) delete_line(atoi(inp)); else delete_line(cur_player->editor.num_lines); break; case 'o': /* Start Overwrite mode */ case 'O': inp += 2; while(!isdigit(*inp) && *inp != '\0') inp++; if (!isdigit(*inp)) bprintf("&+wOverwrite which line?\n"); else { if (atoi(inp) > cur_player->editor.num_lines) { bprintf("&+wYou still need to type that line.\n"); break; } cur_player->editor.current = find_line(atoi(inp)); if (cur_player->editor.current == NULL) { cur_player->editor.mode = Append; sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.current->nr+1); } else { cur_player->editor.mode = Overwrite; sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]&+w> &*",cur_player->editor.current->nr); } } break; case 'a': /* Start Append Mode */ case 'A': bprintf("&+wAppending after line %d\n",cur_player->editor.num_lines); cur_player->editor.current = find_line(cur_player->editor.num_lines); cur_player->editor.mode = Append ; sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.num_lines+1); break; case 'r': /* Review current message */ case 'R': review(cur_player->editor.start); break; case 'h': /* Command information */ case 'H': bprintf("&+wThe Editor has the following commands: \n" " &+w~q : &+wEnd Editor and save message.\n" " &+w~c : &+wEnd Editor and do NOT save the message.\n" " &+w~d <n> : &+wDelete line &+wn&+w.\n" " &+w~r : &+wReview the current text.\n" " &+w~a : &+wAppend at the end of the file.\n" " &+w~o <n> : &+wStart Overwriting at line &+wn&+w.\n" " &+w~h : &+wThis help file.\n" " &+w~e <command>: &+wExecute a command.\n" "&+wBecause some mud clients have a problem with the &+w'~'&+w char, you can also use the &+w'$'&*.\n"); break; case 'e': /* Execute a game command */ case 'E': inp += 2; while (isspace(*inp)) inp++; Game_Com(inp,False); break; default: bprintf("Unknown command, use &+w*h&* for help.\n"); } } else if (cur_player->editor.mode == Overwrite) { l = cur_player->editor.current; if (l->line != NULL) free(l->line); l->line = NEW(char,strlen(inp) + 2); strcpy(l->line,inp); strcat(l->line,"\n"); if (l->next != NULL) { cur_player->editor.current = l->next; sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]&+w> &*",cur_player->editor.current->nr); } else { /* Reached the end of the file, switch to append */ cur_player->editor.mode = Append; sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.num_lines+1); } } else { char *p; if (cur_player->editor.num_lines == cur_player->editor.max_lines) { bprintf("&+wWarning: &+wBuffer is full, can't add new lines to the text.\n"); bprintf("\r%s\n",cur_player->prompt); return; } for (p = inp; strlen(p) > 0 && cur_player->editor.num_lines < cur_player->editor.max_lines; ) { l = NEW(Line,1); if (strlen(p) > 74) { l->line = NEW(char,77); strncpy(l->line,p,74); strcat(l->line,"\n"); p += 74; } else { l->line = NEW(char,strlen(p) +2); strcpy(l->line,p); strcat(l->line,"\n"); p += strlen(p); } l->nr = ++cur_player->editor.num_lines; if (cur_player->editor.start == NULL) { cur_player->editor.start = l; l->next = NULL; } if (cur_player->editor.current != NULL) { l->next = cur_player->editor.current->next; cur_player->editor.current->next = l; } cur_player->editor.current = l; } if (cur_player->editor.num_lines == (cur_player->editor.max_lines -5)) bprintf("&+wWarning&* &+wReaching Buffer Limit, please end your message.\n"); else if (cur_player->editor.num_lines == cur_player->editor.max_lines -5) bprintf("&+wWarning &+wBuffer full, line could not be added completely.\n"); sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]: &*",cur_player->editor.num_lines+1); } bprintf("\r%s",cur_player->prompt); } /* A little tricky, but the termination process is broken in two. This is * done cause sometimes you want to open the file in the handler, to write * some additional data. But it is asking for problems if you have two * links for writing to the same file, so that is done in end_editor(). * This handles the cleanup of the file, if it is still there, and * reinitialises the data. */ void reinitialise_editor(void) { int fd; if (cur_player->editor.parameter != NULL) free(cur_player->editor.parameter); cur_player->editor.parameter = NULL; cur_player->editor.func = NULL; cur_player->editor.num_lines = 0; fd = open(cur_player->editor.filename,O_RDONLY); if (fd != -1) { close(fd); unlink(cur_player->editor.filename); } bprintf("\r%s",cur_player->prompt); } /* Writes buffer to a temporary file, and closes the file. Also resets the * input handler as it was before the writer was started. */ void end_editor(void) { Line *l = cur_player->editor.start, *p; while (l != NULL) { fputs(l->line,cur_player->editor.fp); free(l->line); p = l; l = l->next; free(p); } cur_player->editor.start = cur_player->editor.current = NULL; cur_player->editor.active = False; fclose(cur_player->editor.fp); strcpy(cur_player->prompt,cur_player->editor.old_prompt); pop_input_handler(); } void delete_line(int i) { Line *p = cur_player->editor.start, *l; if (i > cur_player->editor.num_lines || i < 1 || p == NULL) { bprintf("&+wThere is nothing to be deleted.\n"); return; } if (i == 1) { cur_player->editor.start = p->next; cur_player->editor.num_lines--; if (p->next == NULL) cur_player->editor.current = NULL; free(p->line); free(p); l = cur_player->editor.start; /* Update line numbers */ while (l != NULL) { l->nr--; l = l->next; } if (cur_player->editor.start == NULL && cur_player->editor.mode == Overwrite) cur_player->editor.mode = Append; } else { l = p; while (l->next != NULL && l->next->nr != i) l = l->next; if (l->next == NULL) { bprintf("&+wLine not found.\n"); return; } if (l->next->nr == i) { p = l->next; l->next = p->next; if (cur_player->editor.current == p) { if (cur_player->editor.mode == Overwrite) { if (l->next == NULL) { cur_player->editor.mode = Append; cur_player->editor.current = l; } else cur_player->editor.current = l->next; } else cur_player->editor.current = l; } cur_player->editor.num_lines--; free(p->line); free(p); l = l->next; /* Update line numbers */ while (l != NULL) { l->nr--; l = l->next; } } } bprintf("&+wDeleted line %d.\n",i); sprintf(cur_player->prompt,"&+w[&+w%.2d&+w]%s &*", cur_player->editor.mode == Overwrite ? cur_player->editor.current->nr : cur_player->editor.num_lines+1, cur_player->editor.mode == Overwrite ? "&+w>" : ":"); } void review(Line *l) { bprintf("&+wThis is what you typed sofar: \n&+w%s&*\n",DOUBLELINE); while (l != NULL) { bprintf("&+w[&+w%.2d&+w]&* %s",l->nr,l->line); l = l->next; } bprintf("&+w%s\n&+wEnd of Message.\n",DOUBLELINE); } Line *find_line(int nr) { Line *l = cur_player->editor.start; if (l == NULL) return l; while (l->nr != nr && l->next != NULL) l = l->next; return l; } void terminate_editors(void) { int plx,save = real_mynum; for (plx = 0; plx < max_players; plx++) { if (players[plx].editor.active) { setup_globals(real_mynum); end_editor(); reinitialise_editor(); } } setup_globals(save); } /* Since the data is finally written to a file, we can use stat() to get the * filesize. */ long editor_message_size(char *filename) { struct stat buffer; stat(filename,&buffer); return buffer.st_size + 1; }