EmberMUD-0.9.43/
EmberMUD-0.9.43/clan/
EmberMUD-0.9.43/classes/
EmberMUD-0.9.43/gods/
EmberMUD-0.9.43/log/
EmberMUD-0.9.43/player/
EmberMUD-0.9.43/player/temp/
EmberMUD-0.9.43/src/MSVC/
EmberMUD-0.9.43/src/Sleep/
EmberMUD-0.9.43/src/StartMUD/
EmberMUD-0.9.43/src/Win32Common/
/***************************************************************************
 *  File: string.c                                                         *
 *                                                                         *
 *  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.                                                  *
 *                                                                         *
 *  This code was freely distributed with the The Isles 1.1 source code,   *
 *  and has been used here for OLC - OLC would not be what it is without   *
 *  all the previous coders who released their source code.                *
 *                                                                         *
 ***************************************************************************/


#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 <time.h>
#include "merc.h"

void show_line_numbers args( ( CHAR_DATA *ch, const char * oldstring ) );
char * line_replace  args( (char *orig, int line, char *arg3) );
int    count_lines   args( ( const char *orig ) );
char * line_delete   args( (char *orig, int line) );

/*
   The line_replace, count_lines, and line_delete functions
   were provided by Thanatos (Jonathan Rose).  I wrote the new 
   line_add and show_line_numbers functions and modified the 
   string_add function.  --Kyle Boyd
*/

/*****************************************************************************
 Name:		line_replace
 Purpose:	Substitutes one line of text for another.
 Called by:	string_add(string.c) (aedit_builder)olc_act.c.
 ****************************************************************************/
char *line_replace(char *orig, int line, char *arg3)
{

	unsigned int len;   
        int count = 0;
        char *pOut, outbuf[4*MAX_STRING_LENGTH], buf[4*MAX_STRING_LENGTH];
        bool copy = TRUE;
                
        
        strcpy(buf,orig);
        outbuf[0] = '\0';
        pOut = outbuf;
        if (line == 1)
        {
                *pOut = '\0';
                strcat(outbuf, arg3);
                pOut += strlen(arg3);
                if (*pOut-2 != '\n') *pOut++ = '\n';
                if (*pOut-1 != '\r') *pOut++ = '\r';
                copy = FALSE;
        }
                
        for (len = 0; len < strlen(buf); len++)
        {
                if (buf[len] == '\r')
                {
                    if (copy) *pOut++ = '\r';
                    count++;
                    if (count == line-1)
                    {
                        *pOut = '\0';
                        strcat(outbuf, arg3);
                        pOut += strlen(arg3);
                        if (*pOut-2 != '\n') *pOut++ = '\n';
                        if (*pOut-1 != '\r') *pOut++ = '\r';
                        copy = FALSE;
                    }
                    else if (count == line) copy = TRUE;
                }
                else
                    if (copy) *pOut++ = buf[len];
        }
        *pOut = '\0';
        free_string(orig);
        return str_dup(outbuf);
}             

/*****************************************************************************
 Name:		count_lines
 Purpose:	counts the number of lines in the string
 Called by:     string_add for use in line_delete
 *****************************************************************************/
int count_lines( const char *orig )
{
    int line;
    
    for( line = 0; *orig; )
    {
        if ( *orig++ == '\r' )
           line++;
    }
    
    return line;
}

/*****************************************************************************
 Name:		line_delete
 Purpose:	deletes one line of text 
 Called by:	string_add(string.c) (aedit_builder)olc_act.c.
 ****************************************************************************/
char *line_delete(char *orig, int line)
{

	int len, buflen;   
        int count = 0;
        char *pOut, outbuf[4*MAX_STRING_LENGTH], buf[4*MAX_STRING_LENGTH];
                
        strcpy(buf, orig);
        buflen = strlen(buf);
        outbuf[0] = '\0';
        pOut = outbuf;
        len = 0;
        if (line == 1)
        {
                *pOut = '\0';
                for ( ; buf[len] != '\r'; len++)
                    continue;
                len++;
        }
                
        for ( ; len < buflen; len++)
        {
                if ( buf[len] == '\r')
                {
                    count++;
                    if (count == line-1)
                    {
                        for (len++ ; len < buflen; len++ )
                        {
                           if ( buf[len] == '\r' )
                           { 
                               break;
                           }
                        }
                        *pOut++ = '\r';
                    }
                    else 
                       *pOut++ = buf[len];
                }
                else
                   *pOut++ = buf[len];
        }
        *pOut = '\0';
        free_string(orig);
        return str_dup(outbuf);
}             


/*****************************************************************************
 Name:		line_add
 Purpose:	adds one line of text at line # specified
 Called by:	string_add(string.c) (aedit_builder)olc_act.c.
 ****************************************************************************/
/* The old one was buggy, at lesat for my mud */
/* So I rewrote it.  -- Kyle Boyd */
char *line_add(char *orig, int line, char *add)
{
	char *string, outbuf[MAX_STRING_LENGTH], buf[MAX_STRING_LENGTH];
	int count = 1, pos;
	strcpy( buf, orig );
	string = buf;
	outbuf[0]='\0';

	if ( line == 1 )
	{
		outbuf[0]='\0';
		strcat( outbuf, add );
		strcat( outbuf, "\n\r" );
		strcat( outbuf, orig );
		free_string( orig );
		return str_dup( outbuf );
	}
	for( pos = 0; string[pos] != '\0'; pos++ ) {
	if( string[pos] == '\n' && string[pos+1] != '\0' ) {
	if( string[pos+1] == '\r' && string[pos+2] != '\0' )
	{
		count++;
		if ( count == line )
		{
			strncat( outbuf, orig, pos+2 );
			strcat( outbuf, add );
			strcat( outbuf, "\n\r" );
			break;
		}
	}
	}
	}
	for( ; string[pos] != '\0'; pos++ ) {
	if( string[pos] == '\n' && string[pos+1] != '\0' ) {
	if( string[pos+1] == '\r' )
	{
		strcat( outbuf, &orig[pos+2] );
		free_string( orig );
		return str_dup( outbuf );
	}
	}
	}
	return orig;
}
/*****************************************************************************
 Name:		string_edit
 Purpose:	Clears string and puts player into editing mode.
 Called by:	none
 ****************************************************************************/
void string_edit( CHAR_DATA *ch, char **pString )
{
    send_to_char( "-========- Entering EDIT Mode -=========-\n\r", ch );
    send_to_char( "    Type .h on a new line for help\n\r", ch );
    send_to_char( " Terminate with a ~ or @ on a blank line.\n\r", ch );
    send_to_char( "-=======================================-\n\r", ch );

    if ( *pString == NULL )
    {
        *pString = str_dup( "" );
    }
    else
    {
        **pString = '\0';
    }

    ch->desc->pString = pString;

    return;
}



/*****************************************************************************
 Name:		string_append
 Purpose:	Puts player into append mode for given string.
 Called by:	(many)olc_act.c
 ****************************************************************************/
void string_append( CHAR_DATA *ch, char **pString )
{
    send_to_char( "-=======- Entering APPEND Mode -========-\n\r", ch );
    send_to_char( "    Type .h on a new line for help\n\r", ch );
    send_to_char( " Terminate with a ~ or @ on a blank line.\n\r", ch );
    send_to_char( "-=======================================-\n\r", ch );

    if ( *pString == NULL )
    {
        *pString = str_dup( "" );
    }
    show_line_numbers( ch, *pString );
    
    if ( *(*pString + strlen( *pString ) - 1) != '\r' )
    send_to_char( "\n\r", ch );

    ch->desc->pString = pString;

    return;
}



/*****************************************************************************
 Name:		string_replace
 Purpose:	Substitutes one string for another.
 Called by:	string_add(string.c) (aedit_builder)olc_act.c.
 ****************************************************************************/
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';
        strcat( xbuf, new );
        strcat( xbuf, &orig[i+strlen( old )] );
        free_string( orig );
	orig = NULL;
    }

    if( orig ) free_string( orig );
    return str_dup( xbuf );
}



/*****************************************************************************
 Name:		string_add
 Purpose:	Interpreter for string editing.
 Called by:	game_loop_xxxx(comm.c).
 ****************************************************************************/
void string_add( CHAR_DATA *ch, char *argument )
{
   char arg[MAX_INPUT_LENGTH];
   char buf[MAX_STRING_LENGTH];
    /*
     * Thanks to James Seng
     */
   if ( *argument == '~' )
    {
        ch->desc->pString = NULL;
        return;
    }

    smash_tilde( argument );

    if ( *argument == '.' )
    {
        char arg2 [MAX_INPUT_LENGTH];
        char arg3 [MAX_INPUT_LENGTH];

        argument = one_argument( argument, arg );
        argument = first_arg( argument, arg2, FALSE );
        argument = first_arg( argument, arg3, FALSE );

        if ( !str_cmp( arg, ".c" ) )
        {
            send_to_char( "String cleared.\n\r", ch );
            **ch->desc->pString = '\0';
            return;
        }

        if ( !str_cmp( arg, ".s" ) )
        {
            send_to_char( "String so far:\n\r", ch );
            show_line_numbers(ch, *ch->desc->pString );
            return;
        }

        if ( !str_cmp( arg, ".r" ) )
        {
            if ( arg2[0] == '\0' )
            {
                send_to_char(
                    "usage:  .r \"old string\" \"new string\"\n\r", ch );
                return;
            }

	    smash_tilde( arg3 );   /* Just to be sure -- Hugin */
            *ch->desc->pString =
                string_replace( *ch->desc->pString, arg2, arg3 );
            sprintf( buf, "'%s' replaced with '%s'.\n\r", arg2, arg3 );
            send_to_char( buf, ch );
            return;
        }

	  if ( !str_cmp( arg, ".l" ) )
        {
            if (!(*ch->desc->pString) || !(*ch->desc->pString[0]))
            {        
                send_to_char("No lines to replace.\n\r",ch);
                return;
            }
            
            if (!is_number(arg2) || !arg3[0])
            {
                send_to_char( "usage:  .l line# 'new text'\n\r", ch );
                return;
            }
            
            if (atoi(arg2) < 1)
            {   
                send_to_char("Line numbers start at 1.\n\r",ch);
                return;
            }
            smash_tilde( arg3 );
            *ch->desc->pString = 
                       line_replace(*ch->desc->pString, atoi(arg2), arg3);
            return;
        }
        
        if ( !str_cmp( arg, ".a" ) )
        {
            if (!(*ch->desc->pString) || !(*ch->desc->pString[0]))
            {        
                send_to_char("No lines to replace.\n\r",ch);
                return;
            }
            
            if (!is_number(arg2) || !arg3[0])
            {
                send_to_char( "usage:  .a line# 'new text'\n\r", ch );
                return;
            }
            
            if (atoi(arg2) < 1)
            {   
                send_to_char("Line numbers start at 1.\n\r",ch);
                return;
            }
            smash_tilde( arg3 );
            *ch->desc->pString = 
                       line_add(*ch->desc->pString, atoi(arg2), arg3);
            return;
        }        
        
        if ( !str_cmp( arg, ".d" ) )
        {
            int line;
            
            if ( !(*ch->desc->pString) || !(*ch->desc->pString[0]) )
            {
               send_to_char("No lines to delete.\n\r", ch);
               return;
            }

            if ( arg2[0]=='\0' )
            {
                line = count_lines( *ch->desc->pString );
            }
            else 
                line = atoi(arg2);
            
            if ( line < 1 )
            {   
                send_to_char("Line numbers start at 1.\n\r",ch);
                return;
            }
            smash_tilde( arg3 );
            *ch->desc->pString = 
                       line_delete(*ch->desc->pString, line );
            return;
        }

        if ( !str_cmp( arg, ".f" ) )
        {
            *ch->desc->pString = format_string( *ch->desc->pString );
            send_to_char( "String formatted.\n\r", ch );
            return;
        }
        
        if ( !str_cmp( arg, ".h" ) )
        {
            send_to_char( "Sedit help (commands on blank line):   \n\r", ch );
            send_to_char( ".r 'old' 'new'   - replace a substring \n\r", ch );
            send_to_char( "                   (requires '', \"\") \n\r", ch );
            send_to_char( ".l line# 'new'   - replace a line      \n\r", ch );
            send_to_char( ".d               - delete last line    \n\r", ch );
            send_to_char( ".d line#         - delete a line       \n\r", ch );
            send_to_char( ".a line# 'new'   - add a new line      \n\r", ch );
            send_to_char( ".h               - get help (this info)\n\r", ch );
            send_to_char( ".s               - show string so far  \n\r", ch );
            send_to_char( ".f               - (word wrap) string  \n\r", ch );
            send_to_char( ".c               - clear string so far \n\r", ch );
            send_to_char( "@                - end string          \n\r", ch );
            return;
        }

        send_to_char( "SEdit:  Invalid dot command.\n\r", ch );
        return;
    }

    if ( *argument == '~' || *argument == '@' )
    {
        ch->desc->pString = NULL;
        return;
    }

    strcpy( buf, *ch->desc->pString );

    /*
     * Truncate strings to MAX_STRING_LENGTH.
     * --------------------------------------
     */
    if ( strlen( buf ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
    {
        send_to_char( "String too long, last line skipped.\n\r", ch );

	/* Force character out of editing mode. */
        ch->desc->pString = NULL;
        return;
    }

    /*
     * Ensure no tilde's inside string.
     * --------------------------------
     */
    smash_tilde( argument );

    strcat( buf, argument );
    strcat( buf, "\n\r" );
    free_string( *ch->desc->pString );
    *ch->desc->pString = str_dup( buf );
    return;
}



/*
 * Thanks to Kalgen for the new procedure (no more bug!)
 * Original wordwrap() written by Surreality.
 */
/*****************************************************************************
 Name:		format_string
 Purpose:	Special string formating and word-wrapping.
 Called by:	string_add(string.c) (many)olc_act.c
 ****************************************************************************/
char *format_string( char *oldstring /*, bool fSpace */)
{
  char xbuf[MAX_STRING_LENGTH];
  char xbuf2[MAX_STRING_LENGTH];
  char *rdesc;
  int i=0;
  bool cap=TRUE;
  
  xbuf[0]=xbuf2[0]=0;
  
  i=0;
  
  for (rdesc = oldstring; *rdesc; rdesc++)
  {
    if (*rdesc=='\n')
    {
      if (xbuf[i-1] != ' ')
      {
        xbuf[i]=' ';
        i++;
      }
    }
    else if (*rdesc=='\r') ;
    else if (*rdesc==' ')
    {
      if (xbuf[i-1] != ' ')
      {
        xbuf[i]=' ';
        i++;
      }
    }
    else if (*rdesc==')')
    {
      if (xbuf[i-1]==' ' && xbuf[i-2]==' ' && 
          (xbuf[i-3]=='.' || xbuf[i-3]=='?' || xbuf[i-3]=='!'))
      {
        xbuf[i-2]=*rdesc;
        xbuf[i-1]=' ';
        xbuf[i]=' ';
        i++;
      }
      else
      {
        xbuf[i]=*rdesc;
        i++;
      }
    }
    else if (*rdesc=='.' || *rdesc=='?' || *rdesc=='!') {
      if (xbuf[i-1]==' ' && xbuf[i-2]==' ' && 
          (xbuf[i-3]=='.' || xbuf[i-3]=='?' || xbuf[i-3]=='!')) {
        xbuf[i-2]=*rdesc;
        if (*(rdesc+1) != '\"')
        {
          xbuf[i-1]=' ';
          xbuf[i]=' ';
          i++;
        }
        else
        {
          xbuf[i-1]='\"';
          xbuf[i]=' ';
          xbuf[i+1]=' ';
          i+=2;
          rdesc++;
        }
      }
      else
      {
        xbuf[i]=*rdesc;
        if (*(rdesc+1) != '\"')
        {
          xbuf[i+1]=' ';
          xbuf[i+2]=' ';
          i += 3;
        }
        else
        {
          xbuf[i+1]='\"';
          xbuf[i+2]=' ';
          xbuf[i+3]=' ';
          i += 4;
          rdesc++;
        }
      }
      cap = TRUE;
    }
    else
    {
      xbuf[i]=*rdesc;
      if ( cap )
        {
          cap = FALSE;
          xbuf[i] = UPPER( xbuf[i] );
        }
      i++;
    }
  }
  xbuf[i]=0;
  strcpy(xbuf2,xbuf);
  
  rdesc=xbuf2;
  
  xbuf[0]=0;
  
  for ( ; ; )
  {
    for (i=0; i<77; i++)
    {
      if (!*(rdesc+i)) break;
    }
    if (i<77)
    {
      break;
    }
    for (i=(xbuf[0]?76:73) ; i ; i--)
    {
      if (*(rdesc+i)==' ') break;
    }
    if (i)
    {
      *(rdesc+i)=0;
      strcat(xbuf,rdesc);
      strcat(xbuf,"\n\r");
      rdesc += i+1;
      while (*rdesc == ' ') rdesc++;
    }
    else
    {
      bug ("No spaces", 0);
      *(rdesc+75)=0;
      strcat(xbuf,rdesc);
      strcat(xbuf,"-\n\r");
      rdesc += 76;
    }
  }
  while (*(rdesc+i) && (*(rdesc+i)==' '||
                        *(rdesc+i)=='\n'||
                        *(rdesc+i)=='\r'))
    i--;
  *(rdesc+i+1)=0;
  strcat(xbuf,rdesc);
  if (xbuf[strlen(xbuf)-2] != '\n')
    strcat(xbuf,"\n\r");

  free_string(oldstring);
  return(str_dup(xbuf));
}



/*
 * Used above in string_add.  Because this function does not
 * modify case if fCase is FALSE and because it understands
 * parenthesis, it would probably make a nice replacement
 * for one_argument.
 */
/*****************************************************************************
 Name:		first_arg
 Purpose:	Pick off one argument from a string and return the rest.
 		Understands quates, parenthesis (barring ) ('s) and
 		percentages.
 Called by:	string_add(string.c)
 ****************************************************************************/
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;
}




/*
 * Used in olc_act.c for aedit_builders.
 */
char * string_unpad( char * argument )
{
char buf[MAX_STRING_LENGTH];
   char *s;

    s = argument;

    while ( *s == ' ' )
        s++;

    strcpy( buf, s );
    s = buf;

    if ( *s != '\0' )
    {
        while ( *s != '\0' )
            s++;
        s--;

        while( *s == ' ' )
            s--;
        s++;
        *s = '\0';
    }

    free_string( argument );
    return str_dup( buf );
}



/*
 * Same as capitalize but changes the pointer's data.
 * Used in olc_act.c in aedit_builder.
 */
char * string_proper( char * argument )
{
    char *s;

    s = argument;

    while ( *s != '\0' )
    {
        if ( *s != ' ' )
        {
            *s = UPPER(*s);
            while ( *s != ' ' && *s != '\0' )
                s++;
        }
        else
        {
            s++;
        }
    }

    return argument;
}

/* This functions by Kyle Boyd. */
/* This function assumes that the end of line is marked with a \n\r */
/* If you see any bugs, check to see if all of your strings end like that. */

void show_line_numbers( CHAR_DATA *ch, const char * oldstring )
{
	char * string;
	char newstring[MAX_STRING_LENGTH];
	char buf[8];
	char buf2[8];
	int line;
	if ( oldstring[0]=='\0' )
	{
		send_to_char("\n\r", ch);
		return;
	}
	string = str_dup( oldstring );
	newstring[0] = '\0';
	strcat( newstring, " 1 ");
	for( line = 2 ; *string != '\0' ; string++ )
	{
		if ( *string == '\n' )
		{
			string++;
			string++;
			if (*string == '\0')
				break;
			strcat( newstring, "\n\r");
			sprintf( buf2, "%2d ", line );
			line++;
			strcat( newstring, buf2 );
		}

		buf[0]= *string;
		buf[1]= '\0';
		strcat( newstring, buf );
	}
	strcat( newstring, "\n\r");
	send_to_char(newstring, ch);
	free_string( string);
	return;
}