player/a/
player/b/
player/c/
player/d/
player/e/
player/f/
player/g/
player/i/
player/j/
player/k/
player/m/
player/n/
player/r/
player/s/
player/v/
player/w/
player/x/
player/z/
player_fst/e/
player_fst/f/
player_fst/h/
player_fst/i/
player_fst/j/
player_fst/n/
player_fst/o/
player_fst/p/
player_fst/player/a/
player_fst/player/b/
player_fst/player/c/
player_fst/player/d/
player_fst/player/e/
player_fst/player/f/
player_fst/player/g/
player_fst/player/j/
player_fst/player/k/
player_fst/player/m/
player_fst/player/n/
player_fst/player/r/
player_fst/player/s/
player_fst/player/v/
player_fst/player/w/
player_fst/player/x/
player_fst/player/z/
player_fst/u/
player_fst/v/
player_fst/w/
player_fst/x/
/*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
 ~  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;
}