/*___________________________________________________________________________*
)()( DalekenMUD 1.12 (C) 2000, 2001, 2002 )()(
`][' by Martin Thomson, Lee Brooks, `]['
|| Ken Herbert and David Jacques ||
|| ----------------------------------------------------------------- ||
|| Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, ||
|| David Love, Guilherme 'Willie' Arnold, and Mitchell Tse. ||
|| Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael ||
|| Chastain, Michael Quan, and Mitchell Tse. ||
|| Original Diku Mud copyright (C) 1990, 1991 ||
|| by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt, ||
|| Tom Madsen, and Katja Nyboe. ||
|| ----------------------------------------------------------------- ||
|| Any use of this software must follow the licenses of the ||
|| creators. 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. ||
|| ----------------------------------------------------------------- ||
|| string.c ||
|| As distributed with OLC, based on The Isles 1.1 source code. ||
|| The colour interpreter based on that distributed with CircleMUD. ||
*_/<>\_________________________________________________________________/<>\_*/
#include <stdarg.h>
#if defined( unix )
# include <unistd.h>
# include <sys/wait.h>
#endif
#include "mud.h"
#include "regexp.h"
#if defined( HAVE_VSNPRINTF )
int vsnprintf args( ( char *str, size_t n,
const char *format, va_list ap ) );
#endif
#if defined( HAVE_ISPELL )
void ispell_string args( ( CHAR_DATA *ch, const char *str ) );
#endif
#define BUILDER_XP 17 /* 17 xp per 100 characters */
/*
* Colour codes.
*/
int is_colour args( ( char code ) );
/*
* Normal.
*/
#define CNRM "\x1B[0;0m"
/*
* Normal Colours.
*/
#define CBLK "\x1B[0;30m"
#define CRED "\x1B[0;31m"
#define CGRN "\x1B[0;32m"
#define CYEL "\x1B[0;33m"
#define CBLU "\x1B[0;34m"
#define CMAG "\x1B[0;35m"
#define CCYN "\x1B[0;36m"
#define CWHT "\x1B[0;37m"
#define CNUL ""
/*
* Bolds.
*/
#define BRED "\x1B[1;31m"
#define BGRN "\x1B[1;32m"
#define BYEL "\x1B[1;33m"
#define BBLU "\x1B[1;34m"
#define BMAG "\x1B[1;35m"
#define BCYN "\x1B[1;36m"
#define BWHT "\x1B[1;37m"
#define BBLK "\x1B[1;30m"
/*
* Backgrounds
*/
#define BKRED "\x1B[41m"
#define BKGRN "\x1B[42m"
#define BKYEL "\x1B[43m"
#define BKBLU "\x1B[44m"
#define BKMAG "\x1B[45m"
#define BKCYN "\x1B[46m"
#define BKWHT "\x1B[47m"
#define BKBLK "\x1B[40m"
/*
* Special codes.
*/
#define CUDL "\x1B[4m" /* Underline ANSI code */
#define CFSH "\x1B[5m" /* Flashing ANSI code. Change to "" if
* you want to disable flashing colour codes
*/
#define CRVS "\x1B[7m" /* Reverse video ANSI code */
/*
* Special characters.
*/
#define CAMP "&"
#define CSLH "\\"
#define CTIL "~"
#define CCR "\n"
#define BELL "\a"
#define BARLN "|"
#define MAX_COLOURS 34
const char *COLOURLIST[] = {
CNRM,
CRED, CGRN, CYEL, CBLU, CMAG, CCYN, CWHT, CBLK,
BRED, BGRN, BYEL, BBLU, BMAG, BCYN, BWHT, BBLK,
BKRED, BKGRN, BKYEL, BKBLU, BKMAG, BKCYN, BKWHT, BKBLK,
CFSH, CRVS, CUDL,
CAMP, CSLH, CTIL, CCR, BELL, BARLN
};
/*****************************************************************************
Name: string_edit
Purpose: Puts player into append mode for given string.
Called by: (many)olc_act.c
****************************************************************************/
void string_edit( CHAR_DATA *ch, char **pString )
{
int len;
send_to_char( " &w--<[====]>--<[ &bString Editor&w ]>--<[====]>--\n\r"
" [ &g Type &r.h&g on a new line for help. &w ]\n\r"
" [ &r@&g or &r~&g on a blank line to finish.&w ]\n\r"
" --<[===================================]>--&n\n\r", ch );
if( *pString == NULL )
{
*pString = str_dup( "" );
}
send_to_char( *pString, ch );
len = strlen( *pString );
if( *( *pString + len - 1 ) != '\r' )
send_to_char( "\n\r", ch );
if( len > 0 && ch->class == CLASS_BUILDER
&& *pString != ch->description
&& ( !ch->pcdata->note || *pString != ch->pcdata->note->text ) )
{
char buf[ 256 ];
sprintf( buf, "&YYou lose %d.%2.2d experience points.&n\n\r",
( BUILDER_XP * len ) / 100, ( BUILDER_XP * len ) % 100 );
send_to_char( buf, ch );
gain_exp( ch, -1 * BUILDER_XP * len );
}
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).
****************************************************************************/
int string_replace( char **orig, const char *old, const char *new, bool fAll )
{
char xbuf[MAX_STRING_LENGTH * 3];
char temp, *substr, *start;
int count = 0;
xbuf[0] = '\0';
start = substr = *orig;
if( fAll )
{
while( ( substr = strstr( start, old ) ) )
{
count++;
temp = *substr;
*substr = '\0';
if( strlen( xbuf ) + strlen( new ) + strlen( start )
>= MAX_STRING_LENGTH * 3 - 4 )
{
count = -1;
break;
}
strcat( xbuf, start );
strcat( xbuf, new );
*substr = temp;
substr += strlen( old );
start = substr;
}
strcat( xbuf, start );
}
else
{
if( ( substr = strstr( start, old ) ) )
{
if( strlen( start ) + strlen( new ) + strlen( start )
>= MAX_STRING_LENGTH * 3 - 4 )
return -1;
count++;
temp = *substr;
*substr = '\0';
strcat( xbuf, start );
strcat( xbuf, new );
strcat( xbuf, substr + strlen( old ) );
*substr = temp;
}
}
if( count > 0 )
{
free_string( *orig );
*orig = str_dup( xbuf );
}
return count;
}
/*****************************************************************************
Name: regex_replace
Purpose: Substitutes one string for another.
Called by: string_add (string.c) aedit_builder (olc_act.c).
****************************************************************************/
int regex_replace( char **orig, char *pat, char *new, bool fAll )
{
int count = 0;
regexp *preg;
int len;
char *origpt = *orig;
char frombuf[MAX_STRING_LENGTH];
char *frompt;
char tobuf[MAX_STRING_LENGTH];
char *topt = &tobuf[0];
int space = MAX_STRING_LENGTH;
if( strlen( *orig ) > MAX_STRING_LENGTH - 4 )
{
regerror( "String too long" );
return -1;
}
if( !( preg = regcomp( pat, 1 ) ) )
return -1;
for( ;; )
{
len = strchr( origpt, '\n' ) - origpt;
if( len < 0 )
break;
strncpy( frombuf, origpt, len );
frombuf[len] = '\0';
origpt += len + 2; /* to the next line. */
frompt = &frombuf[0];
if( regexec( preg, frompt ) )
do
{
int diff;
char *old;
count++;
/*
* Copy leading text.
*/
diff = preg->startp[0] - frompt;
if( ( space -= diff ) < 0 )
return -1;
strncpy( topt, frompt, diff );
topt += diff;
/* Substitution */
old = topt;
topt = regsub( preg, new, topt, space );
if( !topt || ( space -= topt - old ) < 0 ) /* amylaar */
return -1;
if( frompt == preg->endp[0])
{ /* amylaar : prevent infinite loop */
if( !*frompt )
break;
if( --space < 0 )
{
regerror( "Ran out of space" );
return -1;
}
*topt++ = *frompt++;
}
else
frompt = preg->endp[0];
}
while( fAll && !preg->reganch && regexec( preg, frompt ) );
/*
* Add the end of the line.
*/
if( ( space -= strlen( frompt ) + 1 ) < 0 )
{
regerror( "Ran out of space" );
return -1;
}
strcpy( topt, frompt );
topt += strlen( frompt );
*topt++ = '\n';
*topt++ = '\r';
}
if( count )
{
free_string( *orig );
*orig = str_dup( tobuf );
}
free( preg );
return count;
}
/* OLC 1.1b */
/*****************************************************************************
Name: string_add
Purpose: Interpreter for string editing.
Called by: game_loop_xxxx (comm.c) .
****************************************************************************/
void string_add( CHAR_DATA *ch, const char *argument )
{
char buf[MAX_STRING_LENGTH];
if( *argument == '@' || *argument == '~' )
{
if( ch->class == CLASS_BUILDER
&& *ch->desc->pString != ch->description
&& ( !ch->pcdata->note || *ch->desc->pString != ch->pcdata->note->text ) )
{
sprintf( buf, "&YYou receive %d.%2.2d experience points.&n\n\r",
( BUILDER_XP * strlen( *ch->desc->pString ) ) / 100,
( BUILDER_XP * strlen( *ch->desc->pString ) ) % 100 );
send_to_char( buf, ch );
gain_exp( ch, BUILDER_XP * strlen( *ch->desc->pString ) );
}
ch->desc->pString = NULL;
return;
}
if( *argument == '.' )
{
char arg1[MAX_INPUT_LENGTH];
argument = first_arg( argument, arg1, FALSE );
switch( arg1[1] )
{
case 'c': case 'C':
send_to_char( "String cleared.\n\r", ch );
free_string( *ch->desc->pString );
*ch->desc->pString = str_dup( "" );
return;
case 'e': case 'E':
send_to_char( "External Command:\n\r", ch );
interpret( ch, argument );
return;
case 'f': case 'F':
*ch->desc->pString = format_string( *ch->desc->pString );
send_to_char( "String formatted.\n\r", ch );
return;
case 'h': case 'H':
send_to_char(
"StrEdit help (commands on blank line):\n\r"
".c - clear string so far \n\r"
".d<xnum> - delete line number <xnum>\n\r"
".e <command> - external command\n\r"
".f - format (word wrap) string\n\r"
".h - get help (this info)\n\r"
".i<num> <str> - insert string at line <num>\n\r"
".r 'old' 'new' - replace a substring\n\r"
".ra 'old' 'new' - replace ALL substrings\n\r"
".rr 'pat' 'str' - replace using regular expressions\n\r"
" (requires '' or \"\",\n\r"
" use $^ for end of line)\n\r"
".s[n] - show string so far\n\r"
".l[n] - show with line numbers\n\r"
" (.sn or .ln shows raw colour codes)\n\r"
#if defined( HAVE_ISPELL )
".p - ispell\n\r"
#endif
"@ - end string\n\r", ch );
return;
case 's': case 'S':
{
char buf[MAX_STRING_LENGTH];
char *p;
int i;
if( arg1[2] != 'n' && arg1[2] != 'N' )
{
send_to_char( "String so far:\n\r", ch );
send_to_char( *ch->desc->pString, ch );
return;
}
i = 0;
p = *ch->desc->pString;
while( *p && i < MAX_STRING_LENGTH )
{
if( *p == '&' )
buf[i++] = '&';
buf[i++] = *p++;
}
buf[i] = '\0';
send_to_char( buf, ch );
return;
}
case 'i': case 'I':
{
int num;
char *p1, chsave;
char buf[MAX_STRING_LENGTH];
char buf1[MAX_STRING_LENGTH];
if( !is_number( &arg1[2] ) )
{
send_to_char( "Usage: .i<linenum> <string>\n\r", ch );
return;
}
num = atoi( &arg1[2] );
strcpy( buf, *ch->desc->pString );
for( p1 = &buf[0]; p1 && *p1 && --num > 0; )
p1 = strchr( p1 + 1, '\n' );
if( !p1 || !*p1 )
{
send_to_char( "The string isn't that long.\n\r", ch );
return;
}
if( p1 != &buf[0] )
{
if( *p1 == '\n' ) p1++;
if( *p1 == '\r' ) p1++;
}
chsave = *p1;
*p1 = '\0';
strcpy( buf1, buf );
*p1 = chsave;
strcat( buf1, argument );
strcat( buf1, "\n\r" );
strcat( buf1, p1 );
free_string( *ch->desc->pString );
*ch->desc->pString = str_dup( buf1 );
send_to_char( "Line Inserted.\n\r", ch );
return;
}
case 'd': case 'D':
{
int num;
char *p1, *p2;
char buf[MAX_STRING_LENGTH * 2];
if( !is_number( &arg1[2] ) )
{
send_to_char( "Usage: .d<xnumber>\n\r", ch );
return;
}
num = atoi( &arg1[2] );
if( num < 0 )
{
send_to_char( ".d<xnumber> : Try using a positive number.\n\r",
ch );
return;
}
strcpy( buf, *ch->desc->pString );
for( p1 = &buf[0]; p1 && *p1 && --num > 0; )
p1 = strchr( p1 + 1, '\n' );
if( !p1 || !*p1 )
{
send_to_char( "The string isn't that long.\n\r", ch );
return;
}
if( p1 != &buf[0] )
{
if( *p1 == '\n' ) p1++;
if( *p1 == '\r' ) p1++;
}
p2 = strchr( p1, '\n' );
if( !p2 ) p2 = strchr( buf, '\0' );
if( *p2 == '\n' ) p2++;
if( *p2 == '\r' ) p2++;
strcpy( p1, p2 );
free_string( *ch->desc->pString );
*ch->desc->pString = str_dup( buf );
send_to_char( "Line deleted.\n\r", ch );
return;
}
case 'l': case 'L':
{
char buf1[MAX_STRING_LENGTH * 2];
char *p;
char *i;
int line = 1;
send_to_char( "String so far:\n\r", ch );
strcpy( buf1, "1 : " );
i = strchr( buf1, '\0' );
for( p = *ch->desc->pString; p && *p; p++ )
{
if( *p == '\r' )
{
/* ignore */
}
else if( *p == '\n' )
{
*i++ = '\n';
*i++ = '\r';
line++;
sprintf( i, "%-3d: ", line );
i = strchr( i, '\0' );
}
else if( *p == '&' && ( arg1[2] == 'n' || arg1[2] == 'N' ) )
{
*i++ = '&';
*i++ = '&';
}
else
*i++ = *p;
}
i = strrchr( buf1, '\r' );
if( i == NULL )
strcpy( buf1, "\n\r" );
else
strcpy( i, "\r&n" );
send_to_char( buf1, ch );
return;
}
case 'r': case 'R':
{
bool fAll = FALSE;
bool fRegex = FALSE;
int replaced;
int i;
char *str;
char arg2[MAX_INPUT_LENGTH];
char arg3[MAX_INPUT_LENGTH];
argument = first_arg( argument, arg2, FALSE );
first_arg( argument, arg3, FALSE );
if( arg2[0] == '\0' )
{
send_to_char(
"usage: .r[a][r] \"old string\" \"new string\"\n\r", ch );
return;
}
for( i = 2; i < 5 && arg1[i] != '\0'; ++i )
{
if( UPPER( arg1[i] ) == 'A' )
fAll = TRUE;
else if( UPPER( arg1[i] ) == 'R' )
fRegex = TRUE;
}
str = arg2;
while( ( str = strstr( str, "$^" ) ) )
{
*str++ = '\n';
*str++ = '\r';
}
str = arg3;
while( ( str = strstr( str, "$^" ) ) )
{
*str++ = '\n';
*str++ = '\r';
}
if( fRegex )
replaced = regex_replace( ch->desc->pString,
arg2, arg3, fAll );
else
replaced = string_replace( ch->desc->pString,
arg2, arg3, fAll );
if( replaced > 0 )
sprintf( buf, "Replaced %d lot%s of '&g%s&n' with '&y%s&n'.\n\r",
replaced, ( replaced > 1 ) ? "s" : "", arg2, arg3 );
else if( replaced == 0 )
strcpy( buf, "No pattern matching that was found.\n\r" );
else if( fRegex && regexp_error )
{
sprintf( buf, "REGEX error: %s.\n\r", regexp_error );
regexp_error = NULL;
}
else
strcpy( buf, "The string became too long.\n\r" );
send_to_char( buf, ch );
return;
}
case 'p': case 'P':
#if defined( HAVE_ISPELL )
ispell_string( ch, *ch->desc->pString );
#else
send_to_char( "ISpell has been disabled on this server.\n\r", ch );
#endif
return;
}
}
/*
* 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;
}
strcpy( buf, *ch->desc->pString );
strcat( buf, argument );
strcat( buf, "\n\r" );
free_string( *ch->desc->pString );
*ch->desc->pString = str_dup( buf );
return;
}
/*****************************************************************************
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 */ )
{
const int MAX_LINE_LENGTH = 77;
char xbuf[MAX_STRING_LENGTH];
char *wptr = &xbuf[0];
char *lastwordstart = NULL;
int linelength = 0;
bool newsentence = TRUE;
int endoflines = 0;
while( *oldstring )
{
if( *oldstring == '&' )
{
*wptr++ = *oldstring++;
if( isprint( COLOURLIST[is_colour( *oldstring )][0] ) )
{
linelength++;
}
*wptr++ = *oldstring;
endoflines = 0;
}
else if( isspace( *oldstring ) )
{
if( *oldstring == '\r' )
;
else if( *oldstring == '\n' && endoflines )
{
strncpy( wptr, "\n\r\n\r", endoflines * 2 );
wptr += endoflines * 2;
endoflines = 1;
linelength = 0;
newsentence = TRUE;
}
else
{
/* Only set this for the first '\n' so multiple '\n's don't
* cause extra end-of-line sequences to be added. */
if( *oldstring == '\n' )
endoflines = 2;
if( wptr == &xbuf[0] || !isspace( *(wptr - 1) ) )
{
if( newsentence )
{
*wptr++ = ' ';
linelength++;
}
*wptr++ = ' ';
linelength++;
}
}
lastwordstart = oldstring + 1;
}
else
{
if( newsentence && isalpha( *oldstring ) )
{
*wptr++ = UPPER( *oldstring );
newsentence = FALSE;
}
else
{
*wptr++ = *oldstring;
}
linelength++;
if( *oldstring == '.' || *oldstring == '?' || *oldstring == '!' )
newsentence = TRUE;
endoflines = 0;
}
if( linelength >= MAX_LINE_LENGTH )
{
if( lastwordstart )
{
oldstring = lastwordstart;
do
{
--wptr;
}
while( !isspace( *wptr ) );
if( wptr > &xbuf[0] && isspace( *(wptr - 1) ) )
{
--wptr;
}
}
else
{
oldstring -= 2;
wptr -= 2;
*wptr++ = '-';
}
*wptr++ = '\n';
*wptr++ = '\r';
linelength = 0;
endoflines = 1;
lastwordstart = NULL;
}
else
oldstring++;
}
while( wptr > &xbuf[0] && isspace( *(wptr - 1) ) )
wptr--;
*wptr++ = '\n';
*wptr++ = '\r';
*wptr = '\0';
free_string( oldstring );
return ( str_dup( xbuf ) );
}
#if defined( HAVE_ISPELL )
/* Ispell, based on code by Erwin S. Andreasen, mostly just a straight copy. */
static FILE *ispell_out;
static int ispell_pid = -1;
static int to[2], from[2];
#define ISPELL_BUF_SIZE 1024
void ispell_init()
{
char ignore_buf[1024];
if( !IS_SET( SysInfo->flags, SYSINFO_ISPELL ) )
{
ispell_pid = -1;
return;
}
pipe( to );
pipe( from );
ispell_pid = fork();
if( ispell_pid < 0 )
{
bug( "ispell_init: fork." );
}
else if( ispell_pid == 0 ) /* child */
{
int i;
dup2( to[0], 0 ); /* this is where we read commands from - (stdin) */
close( to[0] );
close( to[1] );
dup2( from[1], 1 ); /* this is where we write stuff to - (stdout) */
close( from[0] );
close( from[1] );
/* Close all the other files */
for( i = 2; i < 255; i++ )
close( i );
if( SysInfo->dictionary && SysInfo->dictionary[0] )
{
sprintf( ignore_buf, "-p%s", SysInfo->dictionary );
execlp( "ispell", "ispell", "-a", ignore_buf,
(char*) NULL );
}
else
execlp( "ispell", "ispell", "-a", (char*) NULL );
exit( 1 );
}
else /* ok !*/
{
close( to[0] );
close( from[1] );
ispell_out = fdopen( to[1], "w" );
setbuf( ispell_out, NULL );
fprintf( ispell_out, "+\n" ); /* terse output, less to worry about */
#if !defined( __sun ) /* that ispell on sun gives no (c) msg */
read( from[0], ignore_buf, 1024 );
#endif
}
}
void ispell_done()
{
if( ispell_pid != -1 )
{
fprintf( ispell_out, "#\n" );
fclose( ispell_out );
close( from[0] );
waitpid( ispell_pid, NULL, 0 );
ispell_pid = -1;
}
}
char *get_ispell_line( char *buf, const char *word )
{
char buf2[MAX_INPUT_LENGTH + 10];
int len;
if( ispell_pid == -1 )
return NULL;
if( word )
{
fprintf( ispell_out, "^%s\n", word );
fflush( ispell_out );
}
len = read (from[0], buf2, ISPELL_BUF_SIZE);
buf2[len] = '\0';
/* Read up to max 1024 characters here */
if( sscanf( buf2, "%1024[^\n]\n\n", buf ) != 1 )
return NULL;
return buf;
}
void do_ispell( CHAR_DATA *ch, const char *argument )
{
const char *pc;
char buf[MAX_STRING_LENGTH];
if( ispell_pid <= 0 )
{
send_to_char( "ispell is not running.\n\r", ch );
return;
}
if( !argument[0] || strchr( argument, ' ' ) )
{
send_to_char( "Invalid input.\n\r", ch );
return;
}
if( argument[0] == '+' )
{
if( !authorized( get_char( ch ), "ispell" ) )
return;
for( pc = argument + 1; *pc; pc++ )
if( !isalpha( *pc ) )
{
charprintf( ch, "'%c' is not a letter.\n\r", *pc );
return;
}
fprintf( ispell_out, "*%s\n", argument + 1 );
fflush( ispell_out );
charprintf( ch, "Word '%s' added to system dictionary.\n\r",
argument + 1 );
send_to_char( "If you didn't mean to add that, please inform admin.\n\r", ch );
log_string( "%s added the word '%s' to the dictionary.",
get_char( ch )->name, argument + 1 );
return; /* we assume everything is OK.. better be so! */
}
pc = get_ispell_line( buf, argument );
if( !pc )
{
send_to_char( "ispell: failed.\n\r", ch );
return;
}
switch( pc[0] )
{
case '*':
case '+': /* root */
case '-': /* compound */
send_to_char( "Correct.\n\r", ch );
break;
case '&': /* miss */
case '?': /* guess */
charprintf( ch, "Not found. Possible words: %s\n\r",
strchr( pc, ':' ) + 1 );
break;
case '#': /* none */
send_to_char( "Unable to find anything that matches.\n\r", ch );
break;
default:
charprintf( ch, "Weird output from ispell: %s\n\r", pc );
}
}
void ispell_string( CHAR_DATA *ch, const char *str )
{
char buf[MAX_STRING_LENGTH];
char word[MAX_INPUT_LENGTH];
char *wordp;
const char *p, *q;
int len, i;
if( ispell_pid <= 0 )
{
send_to_char( "ispell isn't running.\n\r", ch );
return;
}
for( q = str; ( p = strchr( q, '\n' ) ); q = p + 2 )
{
strncpy( buf, q, p - q );
buf[p - q] = '\0';
fprintf( ispell_out, "^%s\n", buf );
}
fflush( ispell_out );
len = read( from[0], buf, MAX_STRING_LENGTH - 2 );
buf[len] = '\0';
for( i = 0; i < len; ++i )
{
if( buf[i] == '\n' )
buf[i] = '\0';
}
for( i = 0; i < len; ++i )
{
switch( buf[i] )
{
case '*': /* correct */
case '+': /* root */
case '-': /* compound */
case '\0':
break;
case '&': /* miss */
case '?': /* guess */
i += 2;
wordp = &word[0];
while( !isspace( buf[i] ) )
*wordp++ = buf[i++];
*wordp = '\0';
while( buf[i] != ':' )
++i;
i += 2;
charprintf( ch, "'%s': %s.\n\r", word, &buf[i] );
break;
case '#': /* none */
i += 2;
wordp = &word[0];
while( !isspace( buf[i] ) )
*wordp++ = buf[i++];
*wordp = '\0';
charprintf( ch, "'%s': No suggestions.\n\r", word );
break;
default:
charprintf( ch, "Weird output from ispell: %s\n\r", &buf[i] );
break;
}
while( buf[i] != '\0' )
++i;
}
return;
}
#else /* !defined( HAVE_ISPELL ) */
void do_ispell( CHAR_DATA *ch, const char *argument )
{
send_to_char( "ISpell has been disabled on this system.\n\r", ch );
return;
}
#endif
/*
* 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 quotes, parenthesis (barring) ('s) and
percentages.
Called by: string_add( string.c )
****************************************************************************/
const char *first_arg( const char *argument, char *arg_first, bool fCase )
{
char cEnd;
while( *argument == ' ' )
argument++;
cEnd = ' ';
if( strchr( "'\"%([{<", *argument ) )
{
switch( *argument )
{
/* Careful here, we could run off the end by accident. */
case '\0':
cEnd = ' ';
argument--;
break;
case '(': cEnd = ')'; break;
case '[': cEnd = ']'; break;
case '{': cEnd = '}'; break;
case '<': cEnd = '>'; break;
default:
cEnd = *argument;
break;
}
argument++;
}
while( *argument != '\0' )
{
if( *argument == cEnd || ( cEnd == ' ' && isspace( *argument ) ) )
{
argument++;
break;
}
if( fCase )
*arg_first = LOWER( *argument );
else
*arg_first = *argument;
arg_first++;
argument++;
}
*arg_first = '\0';
while( isspace( *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;
}
/*
* Returns an all-caps string. OLC 1.1b
* Used for saving helps.
*/
char *all_capitalize( char *strcap, const char *str )
{
int i;
for( i = 0; str[i] != '\0'; i++ )
strcap[i] = UPPER( str[i] );
strcap[i] = '\0';
return strcap;
}
/*
* Takes a string of one line and splits it if it is too long
*/
char *multi_line( char *buf, const char *str, int length, int indent )
{
int i, j;
const char *p;
char *q;
p = str;
j = 0;
while( p < strchr( str, '\0' ) )
{
i = length;
if( p > str )
i -= indent;
while( i > 0 )
{
if( isspace( p[i] ) )
break;
i--;
if( p[i] == '-' )
break;
}
if( indent && p > str )
{
char *sp;
int k;
sp = strchr( buf, '\0' );
for( k = 0; k < indent; k++ )
{
*sp++ = ' ';
}
j += indent;
}
strncpy( &buf[j], p, i );
if( str[i] == '-' )
{
strcpy( &buf[i + j], "-\n\r" );
j++;
}
else
strcpy( &buf[i + j], "\n\r" );
p += i + 1;
j += i + 2;
}
q = strchr( buf, '\0' ) - 1;
while( isspace( *q ) )
{
*q-- = '\0';
}
++q;
*q++ = '\n';
*q = '\r';
return buf;
}
/*
Implementation of a dynamically expanding buffer.
Inspired by Russ Taylor's <rtaylor@efn.org> buffers in ROM 2.4b2.
The buffer is primarily used for null-terminated character strings.
A buffer is allocated with buffer_new, written to using buffer_strcat,
cleared (if needed) using buffer_clear and free'ed using buffer_free.
Erwin S. Andreasen <erwin@pip.dknet.dk>
*/
#define EMEM_SIZE -1 /* find_mem_size returns this when block is too large */
#define NUL '\0'
#define MAX_MEM_LIST 14 /* from db.c */
extern const int rgSizeList [MAX_MEM_LIST];
/* Find in rgSizeList a memory size at least this long */
int find_mem_size( int min_size )
{
int i;
for( i = 0; i < MAX_MEM_LIST; i++ )
if( rgSizeList[i] >= min_size )
return rgSizeList[ i ];
/* min_size is bigger than biggest allowable size! */
return EMEM_SIZE;
}
/* Create a new buffer, of at least size bytes */
BUFFER *buffer_new( int min_size )
{
int size;
BUFFER *buffer;
char buf[200]; /* for the bug line */
size = find_mem_size( min_size );
if( size == EMEM_SIZE )
{
bug( buf );
abort( );
}
buffer = alloc_mem( sizeof( BUFFER ) );
buffer->size = size;
buffer->data = alloc_mem( size );
buffer->data[0] = '\0';
buffer->overflowed = FALSE;
buffer->len = 0;
return buffer;
}
void buffer_strcat( BUFFER *buffer, const char *text )
{
int new_size;
int text_len;
char *new_data;
char buf[200];
if( buffer->overflowed ) /* Do not attempt to add anymore if buffer is already overflowed */
return;
if( !text ) /* Adding NULL string ? */
return;
text_len = strlen( text );
if( text_len == 0 ) /* Adding empty string ? */
return;
/* Will the combined len of the added text and the current text exceed our buffer? */
if( ( text_len + buffer->len + 1 ) > buffer->size ) /* expand? */
{
new_size = find_mem_size( buffer->size + text_len + 1 );
if( new_size == EMEM_SIZE ) /* New size too big ? */
{
bug( buf );
buffer->overflowed = TRUE;
return;
}
/* Allocate the new buffer */
new_data = alloc_mem( new_size );
/* Copy the current buffer to the new buffer */
memcpy( new_data, buffer->data, buffer->len );
free_mem( buffer->data, buffer->size );
buffer->data = new_data;
buffer->size = new_size;
}
memcpy( buffer->data + buffer->len, text, text_len ); /* Start copying */
buffer->len += text_len; /* Adjust length */
buffer->data[ buffer->len ] = NUL; /* Null-terminate at new end */
}
/* Free a buffer */
void buffer_free( BUFFER *buffer )
{
free_mem( buffer->data, buffer->size );
free_mem( buffer, sizeof( BUFFER ) );
}
/* Clear a buffer's contents, but do not deallocate anything */
void buffer_clear( BUFFER *buffer )
{
buffer->overflowed = FALSE;
buffer->len = 0;
}
/* print stuff, append to buffer. safe-ish, a bit of a hack. */
#if !defined( HAVE_VSNPRINTF )
int bprintf( BUFFER *buffer, const char *fmt, ... )
{
/* we have to allow for overflow, this is a bit of a hack */
char buf[MAX_STRING_LENGTH + MAX_INPUT_LENGTH];
va_list va;
int res;
va_start( va, fmt );
vsprintf( buf, fmt, va );
va_end( va );
res = strlen( buf );
if( res >= MAX_STRING_LENGTH - 1 )
{
buf[0] = NUL;
bug( "Overflow when printing string %s", fmt );
}
else
buffer_strcat( buffer, buf );
return res;
}
#else
int bprintf( BUFFER *buffer, const char *fmt, ... )
{
char buf[MAX_STRING_LENGTH];
va_list va;
int res;
va_start( va, fmt );
res = vsnprintf( buf, MAX_STRING_LENGTH, fmt, va );
va_end( va );
if( res >= MAX_STRING_LENGTH - 1 )
{
buf[0] = NUL;
bug( "Overflow when printing string %s", fmt );
}
else
buffer_strcat( buffer, buf );
return res;
}
#endif
int is_colour( char code )
{
switch( code )
{
/* Normal */
case 'n':
case 'x':
return 0; break;
/* Normal colours */
case 'r':
return 1; break; /* Red */
case 'g':
return 2; break; /* Green */
case 'y':
return 3; break; /* Yellow */
case 'b':
return 4; break; /* Blue */
case 'm':
return 5; break; /* Magenta */
case 'c':
return 6; break; /* Cyan */
case 'w':
return 7; break; /* White */
case 'k':
return 8; break; /* Black */
/* Bold colours */
case 'R':
return 9; break; /* Bold red */
case 'G':
return 10; break; /* Bold green */
case 'Y':
return 11; break; /* Bold yellow */
case 'B':
return 12; break; /* Bold blue */
case 'M':
return 13; break; /* Bold magenta */
case 'C':
return 14; break; /* Bold cyan */
case 'W':
return 15; break; /* Bold white */
case 'K':
return 16; break; /* Bold black */
/* Background colours */
case '1':
return 17; break; /* Red background */
case '2':
return 18; break; /* Green background */
case '3':
return 19; break; /* Yellow background */
case '4':
return 20; break; /* Blue background */
case '5':
return 21; break; /* Magenta background */
case '6':
return 22; break; /* Cyan background */
case '7':
return 23; break; /* White background */
case '0':
return 24; break; /* Black background */
/* Special codes */
case 'f':
return 25; break; /* Flash */
case 'v':
return 26; break; /* Reverse video */
case 'u':
return 27; break; /* Underline (Only for mono screens) */
/* Misc characters */
case '&':
return 28; break; /* The & character */
case '\\':
return 29; break; /* The \ character */
case '-':
return 30; break; /* tilde ~ */
case '/':
return 31; break; /* carriage return \n */
case '*':
return 32; break; /* bell */
case '!':
return 33; break; /* bar | */
}
return 0;
}
void proc_colour( char *outbuf, const char *inbuf, bool colour )
{
register int j = 0, p = 0;
int k, max, c = 0;
if( inbuf[0] == '\0' )
return;
while( inbuf[j] != '\0' && p < MAX_STRING_LENGTH * 4 - 3 )
{
if( ( inbuf[j] == '&' ) )
{
c = is_colour( inbuf[j + 1] );
j += 2;
}
else
{
outbuf[p] = inbuf[j];
j++;
p++;
continue;
}
max = strlen( COLOURLIST[c] );
if( colour || max == 1 )
{
for( k = 0; k < max; k++ )
{
outbuf[p] = COLOURLIST[c][k];
p++;
}
}
}
if( p >= MAX_STRING_LENGTH * 4 - 3 )
{
outbuf[p - 30] = '\0'; /* 30 back just to be safe */
strcat( outbuf, "\n\r\n\r***Output Overflow***\n\r" );
}
else
{
outbuf[p] = '\0';
}
return;
}
/*
* Length of the string as seen minus colour codes.
*/
int colour_strlen( const char *str )
{
int i, j;
j = 0;
for( i = 0; str[i]; i++ )
{
if( str[i] == '&' )
{
if( !isprint( COLOURLIST[is_colour( str[i + 1] )][0] ) )
j--;
}
else
j++;
}
return j;
}
/*
* Makes the string the correct length for format with colour.
*/
char *colour_strpad( char *outstr, const char *str, const int length )
{
int i, j;
j = 0;
for( i = 0; str[i] && j < length; i++ )
{
outstr[i] = str[i];
if( str[i] == '&' )
{
if( !isprint( COLOURLIST[is_colour( str[i + 1] )][0] ) )
j--;
}
else
j++;
}
outstr[i++] = '&';
outstr[i++] = 'n';
while( j < length )
{
outstr[i++] = ' ';
j++;
}
outstr[i] = '\0';
return outstr;
}
/*
* Centres the string on a certain length line.
*/
char *colour_strcentre( char *outstr, const char *str, const int length )
{
char *p = outstr;
int pad, i;
pad = length - colour_strlen( str );
if( pad <= 0 )
return colour_strpad( outstr, str, length );
for( i = 0; i < pad / 2; ++i )
*p++ = ' ';
for( i = 0; str[i] != '\0'; ++i )
*p++ = str[i];
for( i = pad / 2; i < pad; ++i )
*p++ = ' ';
*p = '\0';
return outstr;
}
/*
* Limits the length of a colourised string.
* Very similar to the above, except destructive to the string.
*/
void str_limit( char *str, const int length )
{
int i, j;
j = 0;
for( i = 0; str[i] && j < length; i++ )
{
if( str[i] == '&' )
{
if( !isprint( COLOURLIST[is_colour( str[i + 1] )][0] ) )
j--;
}
else
j++;
}
str[i++] = '&';
str[i++] = 'n';
str[i] = '\0';
}
/*
* Remove as much of the colour code as possible.
*/
char *kill_colour( char *outstr, const char *str )
{
int i, j;
j = 0;
for( i = 0; str[i]; i++ )
{
if( str[i] == '&' )
{
if( isprint( COLOURLIST[is_colour( str[++i] )][0] ) )
outstr[j++] = COLOURLIST[is_colour( str[i] )][0];
}
else
outstr[j++] = str[i];
}
outstr[j] = '\0';
return outstr;
}