/*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- ~ 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 ~ ~ ACK!MUD is modified Merc2.0/2.1/2.2 code (c)Stephen Zepp 1998 Ver: 4.3 ~ ~ ~ ~ In order to use any part of this PA Diku Mud, you must comply with ~ ~ both the original Diku license in 'license.doc' as well the Merc ~ ~ license in 'license.txt', and the Ack!Mud license in 'ack_license.txt'.~ ~ In particular, you may not remove any of these copyright notices. ~ ~ ~ ~ _______ _____ ~ ~ / __ /\ / ___ \ 222222 PA_MUD by Amnon Kruvi ~ ~ /______/ / / /___\ \ 2 PA_MUD is modified ~ ~ / _______/ / _______ \ 2 Ack!Mud, v4.3 ~ ~ /_/ /_/ \_\ 2 ~ ~ 2 ~ ~ 2222222 ~ ~ ~ ~ ~ ~ Years of work have been invested to create DIKU, Merc, Ack and PA. ~ ~ Please show your respect by following the licenses, and issuing ~ ~ credits where due. ~ ~ ~ ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-*/ #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 *); char * string_replace( char * orig, char * old, char * new ) { char xbuf[MAX_STRING_LENGTH]; int i; xbuf[0] = '\0'; strcpy( xbuf, orig ); if ( strstr( orig, old ) != NULL ) { i = strlen( orig ) - strlen( strstr( orig, old ) ); xbuf[i] = '\0'; safe_strcat( MSL, xbuf, new ); safe_strcat( MSL, xbuf, &orig[i+strlen( old )] ); free_string( orig ); } return str_dup( xbuf ); } char *first_arg( char *argument, char *arg_first, bool fCase ) { char cEnd; while ( *argument == ' ' ) argument++; cEnd = ' '; if ( *argument == '\'' || *argument == '"' || *argument == '%' || *argument == '(' ) { if ( *argument == '(' ) { cEnd = ')'; argument++; } else cEnd = *argument++; } while ( *argument != '\0' ) { if ( *argument == cEnd ) { argument++; break; } if ( fCase ) *arg_first = LOWER(*argument); else *arg_first = *argument; arg_first++; argument++; } *arg_first = '\0'; while ( *argument == ' ' ) argument++; return argument; } 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]) == 'T' ) { char arg[MSL]; argument = one_argument(argument,arg); do_say(ch,argument); 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(".talk or .t : says something to the room.\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; }