/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "ack.h" /* This file deals with multi-line editing, and writing. */ typedef void RET_FUN ( void * , char * * , CHAR_DATA * , bool ) ; struct buf_data_struct { bool is_free; /* Ramias:for run-time checks of LINK/UNLINK */ BUF_DATA_STRUCT * next; BUF_DATA_STRUCT * prev; CHAR_DATA * ch; char * * dest; char * buf; int pos; RET_FUN * returnfunc; void * returnparm; int old_char_pos; }; extern char str_empty[1]; /* A str function in build.c, used to duplicate strings into perm. mem. */ char * build_simpstrdup(char *); void write_start( char * * dest, void * retfunc, void * retparm, CHAR_DATA * ch ) { BUF_DATA_STRUCT * buf_data; char * buf; /* Check that *dest != &str_empty[0] when calling this func. */ /* If it is, it's because we've run out of memory. */ buf=getmem(MAX_STRING_LENGTH); if (buf == NULL) { bug("Not enough memory for string editing.",0); *dest=&str_empty[0]; send_to_char("WARNING: No memory left. Things will start to go wrong.\n\r",ch); return; } /* Alloc mem. for a new buffer. */ GET_FREE(buf_data, buf_free); LINK(buf_data, first_buf, last_buf, next, prev); buf_data->ch=ch; buf_data->dest=dest; buf_data->buf=buf; buf_data->pos=0; buf_data->returnfunc=retfunc; buf_data->returnparm=retparm; *buf='\0'; buf_data->old_char_pos=ch->position; ch->position=POS_WRITING; *dest=buf; return; } void write_interpret args( ( CHAR_DATA * ch, char * argument ) ) { BUF_DATA_STRUCT * buf_data; char * buf; int curlen; for (buf_data=first_buf; buf_data != NULL; buf_data=buf_data->next) { if (buf_data->ch==ch) break; } if (buf_data == NULL) { bugf("Call to write_interpret when not writing (char=%s)\n\r", ch->name); ch->position=POS_STANDING; return; } buf=buf_data->buf; /* Check to see if text was a command or simply addition */ if (argument[0] != '.') { curlen=strlen(buf); if (curlen > MAX_STRING_LENGTH- 240) { send_to_char("String to long, cannot add new line.\n\r",ch); return; } for (buf=buf+curlen; *argument != '\0'; ) *(buf++)=*(argument++); *(buf++)='\n'; *(buf++)='\r'; *buf='\0'; return; } /* We have a command. */ /* Commands are .help .save .preview .- .clear .lines */ argument++; if (argument[0] == '\0' || UPPER(argument[0] == 'S' || UPPER(argument[0]) == 'Q')) { bool save; char * * dest; CHAR_DATA * ch; if (UPPER(argument[0]) == 'Q') save=0; else save=1; dest=buf_data->dest; ch=buf_data->ch; /* Save routine. */ if (save) { /* Check that dest still points to buf (to check for corruption) */ if (*dest != buf ) { bug("write_interpret: Original destination has been overwritten.",0); send_to_char("Cannot save, string pointer been modified.\n\r",ch); } else { *dest=str_dup(buf); if ((buf_data->returnfunc) != NULL) (*buf_data->returnfunc) ( buf_data->returnparm, dest, ch, TRUE ); } } else { *dest=&str_empty[0]; if ((buf_data->returnfunc) != NULL) (*buf_data->returnfunc) ( buf_data->returnparm, dest, ch, FALSE ); } /* Re-use memory.*/ dispose(buf_data->buf, MAX_STRING_LENGTH); UNLINK(buf_data, first_buf, last_buf, next, prev); /* Re-set char */ ch->position=buf_data->old_char_pos; PUT_FREE(buf_data, buf_free); return; } if (UPPER(argument[0]) == 'H' ) { /* Help */ CHAR_DATA * ch; ch=buf_data->ch; send_to_char("Normal type will be appended to the string, line by line.\n\r",ch); send_to_char(".help or .h : displays this help.\n\r",ch); send_to_char(".save or . : saves and exits the editor.\n\r",ch); send_to_char(".preview or .p : display a preview of the text.\n\r",ch); send_to_char(".-[num] or .- : deletes [num] lines from the end, or just one line\n\r",ch); send_to_char(".clear : deletes whole text.\n\r",ch); send_to_char(".quit or .q : quits without saving.\n\r",ch); send_to_char(".format or .f : formats text for 80 chars.\n\r",ch); send_to_char(".replace or .r : replaces word with string.\n\r", ch ); send_to_char(" (usage) : .r <word> <string>. If no string, arg1 deleted.\n\r", ch ); return; } if ( UPPER( argument[0] ) == 'R' ) { /* Mag: I bet you take one look at this, and change it :) -S- */ char arg1[MAX_STRING_LENGTH]; char arg2[MAX_STRING_LENGTH]; char word[MAX_STRING_LENGTH]; char new_buf[MAX_STRING_LENGTH]; char pBuf; int pos; int npos; int wpos; int buf_length; int foo; int i; char *src; argument = one_argument( argument+1, arg1 ); /* Skip the R */ strcpy( arg2, argument ); if ( arg1[0] == '\0' ) { send_to_char( "No arg1 supplied for replace command.\n\r", ch ); return; } new_buf[0] = '\0'; buf_length = strlen( buf ); pos = 0; npos =0; wpos = 0; word[0] = '\0'; for ( ; ; ) { pBuf = buf[pos]; if ( pBuf == '\0' || pos > buf_length ) break; if ( pBuf == ' ' ) { new_buf[npos] = ' '; pos++; npos++; continue; } if ( !isgraph( pBuf ) ) { new_buf[npos] = pBuf; pos++; npos++; continue; } wpos = 0; for ( ; ; ) { if ( !isgraph( pBuf ) ) break; word[wpos] = pBuf; pos++; wpos++; pBuf = buf[pos]; } word[wpos] = '\0'; if ( !str_cmp( word, arg1 ) ) { if ( arg2[0] != '\0' ) for ( foo = 0; arg2[foo] != '\0'; foo++ ) { new_buf[npos] = arg2[foo]; npos++; } else { /* Do nothing (much). */ if ( npos > 0 ) npos--; send_to_char( "Arg1 deleted.\n\r", ch ); } } else { for ( foo =0; word[foo] != '\0'; foo++ ) { new_buf[npos] = word[foo]; npos++; } } } /* -gulp- Copy new_buf into message structure... */ src=buf; for (i=0;i<npos;i++) *(src++)=new_buf[i]; *(src)='\0'; return; } if ( UPPER(argument[0]) == 'P' ) { send_to_char(buf,ch); return; } if (argument[0] == '-' ) { int num; int a; argument++; if (argument[0] == '\0') num=2; else num=atoi(argument)+1; if (num<=0) return; for (a=strlen(buf) ; a >= 0 ; a--) { if (buf[a]=='\n') { num--; if (num==0) break; } } if (a==0) { send_to_char("Tried to delete too many lines.\n\r",buf_data->ch); return; } a++; if (buf[a]=='\r') a++; send_to_char("Deleted:\n\r",buf_data->ch); send_to_char(buf+a,buf_data->ch); buf[a]='\0'; return; } if (argument[0] == 'f' ) { char * src; char dest[MAX_STRING_LENGTH]; int col; char * srcspc; int destspc; char c; int n,i; int lastcol; /* Format text */ /* Go through line by line, doing word wrapping */ lastcol=79; col=0; n=0; srcspc=NULL; destspc=0; for (src=buf; *src != '\0'; ) { c=*(src++); switch (c) { case '\n': /* Convert /n/r into one space */ if ( (*src == '\r') && (*(src+1)== '\n') && (*(src+2)== '\r') ) { /* Do not convert paragraph endings. */ dest[n++]=c; /* \n */ dest[n++]=*(src++); /* \r */ dest[n++]=*(src++); /* \n */ dest[n++]=*(src++); /* \r */ col=0; srcspc=NULL; destspc=0; break; } /* Also if there is a space on the next line, don't merge. */ if ( (*src == '\r') && (*(src+1)== ' ') ) { dest[n++]=c; /* \n */ dest[n++]=*(src++); /* \r */ col=0; srcspc=NULL; destspc=0; break; } /* Otherwise convert to a space */ /* Get rid of spaces at end of a line. */ if (n>0) { while (dest[--n]==' '); n++; } dest[n++]=' '; col++; srcspc=src-1; destspc=n-1; break; case '\r': break; case '\t': /* Tab */ col+=7; case '.': /* Punctuation */ case ' ': case ',': case ';': case '?': case '!': case ')': srcspc=src-1; destspc=n-1; case '-': if (srcspc==NULL) { srcspc=src-1; /* Only use a dash if necessary */ destspc=n-1; } default: dest[n++]=c; col++; break; } if (col >= lastcol) { /* Need to do a line break */ if (srcspc == NULL) { /* there were no breakable characters on the line. */ dest[n++]='\n'; dest[n++]='\r'; } else { n=destspc; /* n now points to a breakable char. */ src=srcspc; while (dest[n] == ' ' || dest[n] =='\n') { n--; } src++; n++; if (*src=='\r') src++; while (*src==' ') src++; /* src now points to the new line to be put in dest. */ dest[n++]='\n'; dest[n++]='\r'; col=0; srcspc=NULL; destspc=0; } } } /* Get rid of spaces at end, and add a newline. */ while (dest[--n]==' '); n++; dest[n++]='\n'; dest[n++]='\r'; /* Copy from dest back into buffer */ src=buf; for (i=0;i<n;i++) *(src++)=dest[i]; *(src)='\0'; return; } if (!str_cmp(argument,"clear")) { buf[0]='\0'; send_to_char("Done.\n\r",buf_data->ch); return; } send_to_char("Command not known, type .help for help.\n\r",buf_data->ch); return; }