/**************************************************************************/
// string.cpp - string related functions
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with the dawn license *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
**************************************************************************/
/***************************************************************************
* 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. *
***************************************************************************/
#include "include.h" // dawn standard includes
#include "interp.h"
#include "olc.h"
#include "nanny.h"
#include "help.h"
char *string_linedel( char *, int );
char *string_lineadd( char *, char *, int );
char *number_lines( char_data* ch, char * );
/*****************************************************************************
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 )
{
ch->println("-=======- Entering APPEND Mode -========-");
ch->println(" Type .h on a new line for help");
ch->println(" Terminate with a ~ or @ on a blank line.");
ch->println("-=======================================-");
if ( *pString == NULL )
{
*pString = str_dup( "" );
}
// Find dawnftp/mudftp connection if they have one
bool using_dawnftp=false;
if(TRUE_CH(ch)->pcdata && TRUE_CH(ch)->pcdata->preference_dawnftp==PREF_AUTOSENSE){
for (connection_data *m = connection_list; m; m=m->next) {
if (m->connected_state == CON_FTP_COMMAND &&
m->ftp.mode == FTP_PUSH &&
!str_cmp(m->username, TRUE_CH(ch)->name))
{
using_dawnftp=true;
break;
}
}
}else if (TRUE_CH(ch)->pcdata->preference_dawnftp==PREF_ON){
using_dawnftp=true; // perm on
}
if (using_dawnftp)
{
ch->desc->pString = pString;
if (ftp_push(ch->desc)){ // ftp: PUSH mode
ch->println("Editing string via DawnFTP/mudFTP push connection. Use ~ or @ to abort.");
ch->desc->ftp.inuse=true;
return;
}
{ // try PULL mode, since PUSH mode didnt' work and we have the connection forced on
ch->printf("Sending DawnFTP/mudFTP request. If your client does not support DawnFTP/mudFTP, abort this\n"
"edit (type ~ or @ on a blank line), toggle dawnftp off, and try again.\n"
"\ntmp/%lu%c\n", *((unsigned long*) pString), 230);
return;
}
}
if (str_len(*pString)>MSL-4){
char buf2[MSL*2];
strncpy(buf2, *pString, MSL-4);
buf2[MSL-4]='\0';
ch->printf("The text you are trying to edit is longer "
"than %d characters!\r\n", MSL-4);
bug("string_append: Text too long! - trimmed version will be shown");
log_string(buf2);
ch->print(buf2);
ch->printlnf("\r\n\r\n`RThe text you are trying to edit is longer "
"than %d characters!`x", MSL-4);
ch->wrapln("`YSorry, the text will have to be trimmed to a "
"smaller size before it can be worked on.`x");
ch->desc->pString = NULL;
}else{
ch->print( number_lines(ch, *pString));
ch->print("`x");
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 * newstr )
{
char xbuf[HSL];
int i;
xbuf[0] = '\0';
strcpy( xbuf, orig );
if ( strstr( orig, old ) != NULL )
{
i = (int)(str_len( orig ) - str_len( strstr( orig, old ) ));
xbuf[i] = '\0';
strcat( xbuf, newstr );
strcat( xbuf, &orig[i+str_len( old )] );
free_string( orig );
}
return str_dup( xbuf );
}
/**************************************************************************/
// Kal
// assumes orig is an already str_duped string
char * string_replace_all( char * orig, char * old, char * newstr )
{
if(!strstr( orig, old ) || !str_cmp(old, newstr)){
return orig;
}
while(strstr( orig, old )){
orig=string_replace(orig,old,newstr);
}
return orig;
}
/**************************************************************************/
// getline_by_number returns the line specified by the number,
// caller needs to free it
char *getline_by_number( char *string, int linenum);
/**************************************************************************/
/*****************************************************************************
Name: string_add
Purpose: Interpreter for string editing.
Called by: game_loop_xxxx(comm.c).
****************************************************************************/
void save_bans(void);
void string_add( char_data *ch, char *argument )
{
char buf[HSL];
smash_tilde( argument );
if(ch->desc && ch->desc->ftp.inuse && str_cmp(argument, "@"))
{
ch->println("Type @ to manually abort FTP mode.\r\n"
"If DawnFTP/mudFTP is not supported by your client, abort this edit and turn dawnftp off.");
return;
}
if ( *argument == '.' )
{
char arg1 [MIL];
char arg2 [MIL];
char arg3 [MIL];
char tmparg3 [MIL];
char text [MIL];
argument = one_argument( argument, arg1 );
sprintf(text, argument);
argument = first_arg( argument, arg2, false );
strcpy( tmparg3, argument );
argument = first_arg( argument, arg3, false );
if ( !str_cmp( arg1, ".a" ) )
{
do_answer(ch, text);
return;
}
if ( !str_cmp( arg1, ".o" ) )
{
do_ooc(ch, text);
return;
}
if ( !str_cmp( arg1, ".q" ) )
{
do_question(ch, text);
return;
}
if ( !str_cmp( arg1, ".:" ))
{
interpret(ch, text);
return;
}
/* if ( !str_cmp( arg1, ".:" ) )
{
do_immtalk(ch, text);
return;
}
*/
if ( !str_cmp( arg1, ".c" ) )
{
ch->println("String cleared.");
free_string(*ch->desc->pString);
*ch->desc->pString = str_dup( "" );
return;
}
// .i <word> - spellcheck a single word
// .i - spellcheck the whole string
#ifdef unix
if ( !str_cmp( arg1, ".i" ) )
{
if (!IS_NULLSTR(arg2))
do_ispell(ch, arg2);
else
ispell_string(ch);
return;
}
#endif
if ( !str_cmp( arg1, ".s" ) )
{
// decide if to put line numbers on the string
if (str_infix("`1",*ch->desc->pString)){
ch->println("String so far:");
ch->print( number_lines(ch, *ch->desc->pString));
ch->print("`x");
}else{
ch->println("String so far: (has ``1 codes in it, use .b to see line numbering)");
ch->print( *ch->desc->pString);
}
return;
}
if ( !str_cmp( arg1, ".b" ) )
{
ch->println( "String so far:" );
ch->printbw( number_lines(ch, *ch->desc->pString));
ch->print( "`x" );
return;
}
if ( !str_cmp( arg1, ".r" ) )
{
if ( arg2[0] == '\0' )
{
ch->println("usage: .r \"old string\" \"new string\"");
return;
}
if (!str_infix(arg2 , *ch->desc->pString)){
// check the lengths
if ( str_len( *ch->desc->pString) + str_len( arg3 ) - str_len( arg2 )>= ( MSL - 50 ) )
{
ch->println("You can't replace that much, the resulting string would be too long.");
return;
}
*ch->desc->pString =
string_replace( *ch->desc->pString, arg2, arg3 );
sprintf( buf, "'%s' replaced with '%s'.", arg2, arg3 );
ch->printlnbw( buf );
}else{
sprintf( buf, "Couldn't find '%s' in string.", arg2);
ch->printlnbw( buf );
}
return;
}
if ( IS_IMMORTAL(ch) && !str_cmp( arg1, ".z" ) )
{
int count=0;
// hide all ``1 codes from the replace of `1 codes
while(!str_infix("``1", *ch->desc->pString)){
*ch->desc->pString =
string_replace( *ch->desc->pString, "``1", "!@#$%%^%$#@!");
}
while(!str_infix("`1", *ch->desc->pString)){
*ch->desc->pString =
string_replace( *ch->desc->pString, "`1", "`+\n");
count++;
}
// return all original ``1 codes
while(!str_infix("!@#$%%^%$#@!", *ch->desc->pString)){
*ch->desc->pString =
string_replace( *ch->desc->pString, "!@#$%%^%$#@!", "``1");
}
if(count==0){
sprintf( buf, "Couldn't find any `1 code in string to mass replace.");
ch->printlnbw( buf );
}else{
ch->printlnf("Replaced %d ``1 symbols with ``+\\n",count);
}
return;
}
if ( !str_cmp( arg1, ".n" ) || !str_cmp( arg1, ".f" ) )
{
*ch->desc->pString = note_format_string( *ch->desc->pString );
ch->println("String noteformatted.");
return;
}
if ( !str_cmp( arg1, ".w" ) )
{
*ch->desc->pString = format_string( *ch->desc->pString );
ch->println("String formatted.");
return;
}
if (!str_cmp(arg1,".-") || !str_cmp(arg1,".d"))
{
size_t len;
bool found = false;
if (ch->desc->pString == NULL || *ch->desc->pString[0] == '\0')
{
ch->println("No lines left to remove.");
return;
}
strcpy(buf,*ch->desc->pString);
for (len = str_len(buf); len > 0; len--)
{
if (buf[len] == '\n')
{
if (!found) // back it up
{
if (len > 0)
len--;
found = true;
}
else // found the second one
{
buf[len + 1] = '\0';
free_string(*ch->desc->pString);
*ch->desc->pString = str_dup(buf);
ch->println("Bottom line removed.");
return;
}
}
}
buf[0] = '\0';
free_string(*ch->desc->pString);
*ch->desc->pString = str_dup(buf);
ch->println("Bottom line removed.");
return;
}
if ( !str_cmp( arg1, ".ld" ) )
{
*ch->desc->pString = string_linedel( *ch->desc->pString, atoi(arg2) );
ch->printlnf("Line %d deleted.", atoi(arg2) );
return;
}
if ( !str_cmp( arg1, ".li" ) )
{
*ch->desc->pString = string_lineadd( *ch->desc->pString, tmparg3, atoi(arg2) );
ch->printlnf("Line '%s' inserted above line %d.", tmparg3, atoi(arg2));
return;
}
// line swap - Kal - Nov 99
if ( !str_cmp( arg1, ".ls" ) )
{
char *first, *second;
int line1=atoi(arg2);
int line2=atoi(arg3);
// validate the numbers
if(line1<1 || line2<1){
ch->printf("Line Swap (.ls) requires 2 numbers, both greater than 0.\r\n"
"(e.g. '.ls 2 5' would swap lines 2 and 5.)\r\n");
return;
}
first=getline_by_number( *ch->desc->pString, line1);
if(IS_NULLSTR(first)){
ch->printlnf("Line %d not found!", line2);
free_string(first);
return;
}
second=getline_by_number( *ch->desc->pString, line2);
if(IS_NULLSTR(second)){
ch->printlnf("Line %d not found!", line2);
free_string(first);
free_string(second);
return;
}
*ch->desc->pString = string_linedel( *ch->desc->pString, line1 );
*ch->desc->pString = string_lineadd( *ch->desc->pString, second, line1 );
*ch->desc->pString = string_linedel( *ch->desc->pString, line2 );
*ch->desc->pString = string_lineadd( *ch->desc->pString, first, line2 );
ch->printlnf("Line %d swapped with line %d.", line1, line2);
free_string(first);
free_string(second);
return;
}
if ( !str_cmp( arg1, ".lr" ) )
{
*ch->desc->pString = string_linedel( *ch->desc->pString, atoi(arg2) );
*ch->desc->pString = string_lineadd( *ch->desc->pString, tmparg3, atoi(arg2) );
ch->printlnf("Line %d replaced with '%s'.", atoi(arg2), tmparg3);
return;
}
if ( !str_cmp( arg1, ".h" ) )
{
ch->println("`xSedit help (commands on blank line): ");
ch->println(".r 'old' 'new' - replace a substring ");
ch->println(" (requires '', \"\") ");
if ( IS_IMMORTAL(ch)){
ch->println(".z - convert ``1 format to ``+ format");
}
ch->println(".h - get help (this info)");
ch->println(".s - show string so far ");
ch->println(".b - show string bare with line numbers");
ch->println(" and with colour codes");
ch->println(".n - noteformat string (wordwrap but");
ch->println(" dont put spaces after fullstops)");
ch->println(".f - noteformat string");
ch->println(".w - wordwrap string (changing spacing)");
ch->println(".c - clear string so far ");
ch->println(".i - spell check string so far ");
ch->println(".d - delete the bottom line");
ch->println(".- - delete the bottom line");
ch->println(".ld <num> - delete the line numbered <num>");
ch->println(".li <num> <str> - insert <str> before line <num>");
ch->println(".lr <num> <str> - replace line <num> with <str>");
ch->println(".ls <num1> <num2> - swap lines <num1> and <num2>");
ch->println("@ - end string ");
ch->println("-External commands-");
ch->println(".a <text to reply> - answer a question");
ch->println(".o <text to ooc> - ask a question");
ch->println(".q <text to ask> - ask a question");
if (IS_IMMORTAL(ch))
{
ch->println(".: or : process external command");
}
return;
}
ch->println("SEdit: Invalid dot command.");
return;
}
if ( *argument == '~' || *argument == '@' )
{
// all changed flags system, enables some olc editor to mark
// something as changed when they come out of the editor
if(ch->desc->changed_flag){
SET_BIT(*ch->desc->changed_flag,A);
ch->desc->changed_flag=NULL;
}
if ( ch->desc->editor == ED_BAN) // banedit
{
save_bans();
}else if ( ch->desc->editor == ED_HELP ){ // hedit
help_data *pHelp;
EDIT_HELP(ch, pHelp);
get_widest_line_stats(pHelp->text, true, &pHelp->widest_line, &pHelp->widest_line_width);
if(pHelp->widest_line_width>78){
ch->printlnf("`RWARNING: Line text is %d characters wide.`x", pHelp->widest_line_width);
}
}else if ( ch->desc->editor == ED_MPCODE ){ // mob progs
MOB_INDEX_DATA *mob;
int hash;
MPROG_LIST *mpl;
MPROG_CODE *mpc;
EDIT_MPCODE(ch, mpc);
if ( mpc != NULL )
{
AREA_DATA *pArea;
pArea=get_vnum_area( mpc->vnum);
if (pArea)
{
SET_BIT( pArea->olc_flags, OLCAREA_CHANGED );
}
// display which mobs was affected by the updating of code
// - not really necessary but message is cool :)
for ( hash = 0; hash < MAX_KEY_HASH; hash++ )
{
for ( mob = mob_index_hash[hash]; mob; mob = mob->next )
{
for ( mpl = mob->mprogs; mpl; mpl = mpl->next )
{
if ( mpl->prog == mpc)
{
ch->printlnf("Updated mob %d %s(%s).",
mob->vnum, mob->short_descr, mob->player_name);
continue;
}
}
}
}
}
}
ch->desc->pString = NULL;
ch->desc->ftp.inuse=false;
return;
}
strcpy( buf, *ch->desc->pString );
/*
* Truncate strings to MSL.
* --------------------------------------
*/
if ( str_len( buf ) + str_len( argument ) >= ( MSL - 4 ) )
{
ch->println("String too long, last line skipped.");
/* 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, "\r\n" );
free_string( *ch->desc->pString );
*ch->desc->pString = str_dup( buf );
return;
}
/* Second half of format_string was rewritten by kalahn May 98,
* Now wordwraps correct with ` colorcode sequences.
*/
/*
* 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[HSL];
char xbuf2[HSL];
char *rdesc;
int i=0;
bool cap=true;
xbuf[0]=xbuf2[0]=0;
i=0;
for (rdesc = oldstring; *rdesc; rdesc++)
{
if (*rdesc=='\r')
{
if (xbuf[i-1] != ' ')
{
if(!(i>1 && xbuf[i-1]== '+' && xbuf[i-2]== '`')){
xbuf[i]=' ';
i++;
}
}
}
else if (*rdesc=='\n') ;
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++;
}
}
rdesc=xbuf2;
xbuf[i]=0;
strcpy(xbuf2,xbuf);
xbuf[0]=0;
/*
* Code above here removes all the lines and caps the correct words.
* below here puts in lines
*/
// code below here was written by Kalahn May 98
// next wordwrap the string so no line is no greater
// than 77 visible characters
// rdesc is a pointer to the start of the string
// get the formatted version of rdesc into xbuf
{
int i=0; // index
int vischars=0; // visible characters on the current line
int last_space=0;
char *point;
int width=77;
bool more_string= true;
point=xbuf; // target buffer
bool inside_tag=false;
while(more_string)
{
while (vischars<width && *(rdesc+i)!='\0')
{
*point= *(rdesc+i); // copy the character
{
// this section of code enables note_format_string_width()
// to wrap strings with embeded MXP tags correctly
// - Kal, Jan 04
if (*(point)==MXP_BEGIN_TAG){
inside_tag=true;
}
if (*(point)==MXP_END_TAG){
inside_tag=false;
vischars--;
}
if(inside_tag){
// when inside a tag, just keep copying till we reach the end
i++;
*(++point)='\0';
continue;
}
}
vischars++;
// record the last space location.
if (*(point)==' ')
{
last_space=i;
}
// calculate the effects of colour codes
if (*(point)=='`')
{
i++;
point++;
*point= *(rdesc+i); // copy the next character
switch (*point)
{
default: // most codes count as none
vischars--;
break;
case '1': // newline system reset the counters
vischars=0;
rdesc+=i;
i=-1;
point--;
last_space=-1;
break;
case '+': // inline paragraph system `+
point++;
*point= '\n';
vischars=0;
rdesc+=i+1;
i=-1;
last_space=-1;
break;
case 'N': // N - counts as the length of the name
vischars+=str_len(game_settings->gamename)-1;
break;
case '-': // creates ~ counts as one
case '`': // creates ` counts as one
break;
}
i++;
point++;
continue;
}
i++;
*(++point)='\0';
}
// all tags should be terminated, otherwise someone has
// a bug somewhere... if so close the tag anyway
if(inside_tag){
bugf("note_format_string_width(): mxp/html tag not closed!");
*(point)=MXP_END_TAG;
point++;
}
// end of string or adding a new line
if (vischars<width)
{
*point='\0';
more_string=false;
}
else
{
if (last_space>-1)
{
last_space++;
point-= (i-last_space);
*point++='\r';
*point++='\n';
i=last_space;
}
else // line to long
{
logf("noteformatstring: line too long. '%s'", rdesc);
*point++='-';
*point++='\r';
*point++='\n';
}
// setup for next time thru loop
vischars=0;
rdesc+=i;
i=0;
last_space=-1;
}
}
*point++='\r';
*point++='\n';
*point='\0';
}
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 force_lowercase)
{
char cEnd;
while ( is_space(*argument) )
argument++;
cEnd = ' ';
if ( *argument == '\'' || *argument == '"'
|| *argument == '%' || *argument == '(' )
{
if ( *argument == '(' )
{
cEnd = ')';
argument++;
}
else cEnd = *argument++;
}
while ( *argument != '\0' )
{
if( (is_space(cEnd) && is_space(*argument)) || *argument== cEnd ){
argument++;
break;
}
if ( force_lowercase) *arg_first = LOWER(*argument);
else *arg_first = *argument;
arg_first++;
argument++;
}
*arg_first = '\0';
while ( is_space(*argument) ){
argument++;
}
return argument;
}
/**************************************************************************/
/*
* 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;
}
/**************************************************************************/
char *string_linedel( char *string, int line )
{
char *strtmp = string;
char buf[HSL];
int cnt = 1, tmp = 0;
buf[0] = '\0';
for ( ; *strtmp != '\0'; strtmp++ )
{
if ( cnt != line )
buf[tmp++] = *strtmp;
if ( *strtmp == '\n' )
{
if ( *(strtmp + 1) == '\r' )
{
if ( cnt != line )
buf[tmp++] = *(++strtmp);
else
++strtmp;
}
cnt++;
}
}
buf[tmp] = '\0';
free_string(string);
return str_dup(buf);
}
/**************************************************************************/
char *string_lineadd( char *string, char *newstr, int line )
{
char *strtmp = string;
int cnt = 1, tmp = 0;
bool done = false;
char buf[HSL];
buf[0] = '\0';
for ( ; *strtmp != '\0' || (!done && cnt == line); strtmp++ )
{
if ( cnt == line && !done )
{
strcat( buf, newstr );
strcat( buf, "\r\n" );
tmp += str_len(newstr) + 2;
cnt++;
done = true;
}
buf[tmp++] = *strtmp;
if ( done && *strtmp == '\0' )
break;
if ( *strtmp == '\n' )
{
if ( *(strtmp + 1) == '\r' )
buf[tmp++] = *(++strtmp);
cnt++;
}
buf[tmp] = '\0';
}
free_string(string);
return str_dup(buf);
}
/**************************************************************************/
// copy up till a \n from str into buf
// return the position of str after the line has been put into buf
char *getline( char *str, char *buf, int bufsize )
{
int tmp = 0;
bool found = false;
bufsize--;
while ( *str && tmp<bufsize){
if ( *str == '\n' )
{
found = true;
break;
}
if(*(str)=='\r'){// dont want \r codes returned at all
str++;
}else{
buf[tmp++] = *(str++);
}
}
// buffer bounds check
if(tmp>=bufsize){
boundsbug("getline(): bufsize=%d - insufficient buffer space allocated.", bufsize);
}
if ( found )
{
// skip over line codes
if ( *(str + 1) == '\r' ){
str += 2;
}else{
str += 1;
}
}
buf[tmp] = '\0';
return str;
}
/**************************************************************************/
// return the lines in a string numbered on the right hand side
// (.s in the string editor)
char *number_lines( char_data *ch, char *string )
{
int cnt = 1;
static char buf[MSL*4];
char buf2[MSL*4], tmpb[MSL*4];
char *string_start=string;
buf[0] = '\0';
while ( *string )
{
string = getline( string, tmpb, MSL*4 );
if(HAS_MXP(ch)){
sprintf( buf2, "%s. %s\n",
mxp_create_send(ch,
FORMATF("@|.ld %d\" hint=\"exit editor|delete line %d", cnt, cnt)
,FORMATF("%2d", cnt)) // text seen on screen underlined
, tmpb );
cnt++;
}else{
sprintf( buf2, "%2d. %s\n", cnt++, tmpb );
}
// bounds check
if(str_len(buf) + str_len(buf2)> MSL*4){
boundsbug("number_lines(): insufficient buffer space allocated "
"to display string '%200.200s'.", string_start);
}
strcat( buf, buf2 );
}
return buf;
}
/**************************************************************************/
// returns the line specified by the number, caller needs to free it
// Kal - Nov 99
char *getline_by_number( char *string, int linenum)
{
char buf[HSL];
int cnt = 0;
if(linenum<1){
return str_dup("");
}
buf[0] = '\0';
while ( !IS_NULLSTR(string) )
{
string = getline( string, buf, HSL);
if(++cnt==linenum){
// return our string without \r and ~ codes (removed by fix_string)
// note: getline doesn't returns up to the first \n
return str_dup(fix_string(buf));
break;
}
}
return str_dup("");
}
/**************************************************************************/
// add whitespace around the sides
// remove the name
// remove any double white spaces, and trim the sides
char *string_remove_name(char *str, char *name)
{
name=lowercase(name);
// pad with whitespace .. we only work in lowercase
char *padded=str_dup(lowercase(FORMATF(" %s ", str)));
free_string(str);
padded=string_replace_all(padded, FORMATF(" %s ", name), " "); // remove the name
padded=string_replace_all(padded, " ", " "); // remove double spaces
str=str_dup(trim_string(padded)); // trim the sides
free_string(padded);
return str;
}
/**************************************************************************/
/**************************************************************************/