/trunk/src/string.c
C | 822 lines | 662 code | 66 blank | 94 comment | 170 complexity | 8d386606fa93d06dfcdfbcc22104de19 MD5 | raw file
- /***************************************************************************
- * 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, 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 );
- }
- 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 *s;
- char *result;
- char *tmp;
- s = argument;
- while ( *s == ' ' )
- s++;
- result = s;
- tmp = s;
- if ( *s != '\0' )
- {
- while ( *s != '\0' )
- if ( *s++ != ' ' )
- tmp = s - 1;
- *tmp = '\0';
- }
- free_string( &argument );
- return str_dup( result );
- }
- /*
- * 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. */
- /* If you see any bugs, check to see if all of your strings end like that. */
- void show_line_numbers( CHAR_DATA * ch, char *string )
- {
- char *ptr;
- char newstring[MAX_STRING_LENGTH];
- int line;
- if ( !*string )
- {
- send_to_char( "\n\r", ch );
- return;
- }
- ptr = newstring;
- *ptr = '\0';
- sprintf( ptr, " 1 " );
- ptr += 3;
- for ( line = 2; *string; string++ )
- {
- if ( *string == '\n' || *string == '\r' )
- {
- /*
- * Allow for both \n\r and \r\n and \n. Don't expect two chars
- * because you could condense two rows down to one in the case of
- * \n\n
- */
- if ( ( *string == '\n' && *( string + 1 ) == '\r' )
- || ( *string == '\r' && *( string + 1 ) == '\n' ) )
- string += 2;
- else
- string++;
- if ( *string == '\0' )
- break;
- sprintf( ptr, "\n\r%2d ", line++ );
- ptr += 5;
- }
- *ptr++ = *string;
- }
- sprintf( ptr, "\n\r" );
- send_to_char( newstring, ch );
- return;
- }