/* * RAM $Id: olc_utils.c 81 2009-01-14 06:16:31Z ghasatta $ */ /*************************************************************************** * 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. * * * ***************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" #include "db.h" #include "interp.h" #include "tables.h" #include "strings.h" #include "olc.h" /***************************************************************************** Name: string_edit Purpose: Clears string and puts player into editing mode. Called by: none ****************************************************************************/ void string_edit( CHAR_DATA *ch, char **pString ) { ch_printf( ch, "-========- Entering EDIT Mode -=========-\r\n" ); ch_printf( ch, " Type .h on a new line for help\r\n" ); ch_printf( ch, " Terminate with a ~ or @ on a blank line.\r\n" ); ch_printf( ch, "-=======================================-\r\n" ); 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, std::string &pString ) { ch_printf( ch, "-=======- Entering APPEND Mode -========-\r\n" ); ch_printf( ch, " Type .h on a new line for help\r\n" ); ch_printf( ch, " Terminate with a ~ or @ on a blank line.\r\n" ); ch_printf( ch, "-=======================================-\r\n" ); ch_printf( ch, "%s", numlineas( pString.c_str() ) ); ch->desc->pString_std = &pString; ch->desc->pString = NULL; } void string_append( CHAR_DATA *ch, char **pString ) { ch_printf( ch, "-=======- Entering APPEND Mode -========-\r\n" ); ch_printf( ch, " Type .h on a new line for help\r\n" ); ch_printf( ch, " Terminate with a ~ or @ on a blank line.\r\n" ); ch_printf( ch, "-=======================================-\r\n" ); ch_printf( ch, "%s", numlineas( *pString ) ); ch->desc->pString_std = NULL; ch->desc->pString = pString; } /***************************************************************************** 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, const char *pOld, const char *pNew ) { char xbuf[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; int i = 0; strcpy( xbuf, orig ); if ( strstr( orig, pOld ) != NULL ) { i = strlen( orig ) - strlen( strstr( orig, pOld ) ); xbuf[i] = '\0'; strcat( xbuf, pNew ); strcat( xbuf, &orig[i + strlen( pOld )] ); free_string( orig ); } return str_dup( xbuf ); } void string_replace(std::string &orig, const char *pOld, const char *pNew) { size_t old_size = strlen(pOld); size_t replace_pos = orig.find(pOld); if(replace_pos != std::string::npos) orig.replace(replace_pos, old_size, pNew); } /***************************************************************************** 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] = "\0\0\0\0\0\0\0"; char local_argument[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; const char *lap = local_argument; /* * Thanks to James Seng */ strcpy( local_argument, argument ); smash_tilde( local_argument ); if ( *lap == '.' ) { char arg1[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; char arg2[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; char arg3[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; char tmparg3[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0"; lap = one_argument( lap, arg1 ); lap = first_arg( lap, arg2, FALSE ); strcpy( tmparg3, lap ); lap = first_arg( lap, arg3, FALSE ); if ( !str_cmp( arg1, ".c" ) ) { ch_printf( ch, "String cleared.\r\n" ); if(ch->desc->pString != NULL) { free_string( *ch->desc->pString ); *ch->desc->pString = str_dup( "" ); } else ch->desc->pString_std->erase(); return; } if ( !str_cmp( arg1, ".s" ) ) { const char *print_me = NULL; if(ch->desc->pString != NULL) print_me = *ch->desc->pString; else print_me = ch->desc->pString_std->c_str(); ch_printf( ch, "String so far:\r\n" ); ch_printf( ch, "%s", numlineas( print_me ) ); return; } if ( !str_cmp( arg1, ".r" ) ) { if ( arg2[0] == '\0' ) { ch_printf( ch, "usage: .r \"old string\" \"new string\"\r\n" ); return; } if(ch->desc->pString != NULL) *ch->desc->pString = string_replace( *ch->desc->pString, arg2, arg3 ); else string_replace(*ch->desc->pString_std, arg2, arg3); ch_printf( ch, "'%s' replaced with '%s'.\r\n", arg2, arg3 ); return; } if ( !str_cmp( arg1, ".f" ) ) { if(ch->desc->pString != NULL) *ch->desc->pString = format_string( *ch->desc->pString ); else format_string(*ch->desc->pString_std); ch_printf( ch, "String formatted.\r\n" ); return; } if ( !str_cmp( arg1, ".ld" ) ) { if(ch->desc->pString != NULL) *ch->desc->pString = string_linedel( *ch->desc->pString, atoi( arg2 ) ); else string_linedel(*ch->desc->pString_std, atoi(arg2)); ch_printf( ch, "Line deleted.\r\n" ); return; } if ( !str_cmp( arg1, ".li" ) ) { if(ch->desc->pString != NULL) *ch->desc->pString = string_lineadd( *ch->desc->pString, tmparg3, atoi( arg2 ) ); else string_lineadd(*ch->desc->pString, tmparg3, atoi(arg2)); ch_printf( ch, "Line inserted.\r\n" ); return; } if ( !str_cmp( arg1, ".lr" ) ) { if(ch->desc->pString != NULL) { *ch->desc->pString = string_linedel( *ch->desc->pString, atoi( arg2 ) ); *ch->desc->pString = string_lineadd( *ch->desc->pString, tmparg3, atoi( arg2 ) ); } else { string_linedel(*ch->desc->pString_std, atoi(arg2)); string_lineadd(*ch->desc->pString_std, tmparg3, atoi(arg2)); } ch_printf( ch, "Line replaced.\r\n" ); return; } if ( !str_cmp( arg1, ".h" ) ) { ch_printf( ch, "Sedit help (commands on blank line): \r\n" ); ch_printf( ch, ".r 'old' 'new' - replace a substring \r\n" ); ch_printf( ch, " (requires '', \"\") \r\n" ); ch_printf( ch, ".h - get help (this info)\r\n" ); ch_printf( ch, ".s - show string so far \r\n" ); ch_printf( ch, ".f - (word wrap) string \r\n" ); ch_printf( ch, ".c - clear string so far \r\n" ); ch_printf( ch, ".ld <num> - delete line number <num>\r\n" ); ch_printf( ch, ".li <num> <str> - insert <str> at line <num>\r\n" ); ch_printf( ch, ".lr <num> <str> - replace line <num> with <str>\r\n" ); ch_printf( ch, "@ - end string \r\n" ); return; } ch_printf( ch, "SEdit: Invalid dot command.\r\n" ); return; } if ( *argument == '~' || *argument == '@' ) { if ( ch->desc->editor == ED_MPCODE ) /* for mobprogs */ { MOB_INDEX_DATA *mob = NULL; int hash = 0; MPROG_LIST *mpl = NULL; MPROG_CODE *mpc = NULL; EDIT_MPCODE( ch, mpc ); if ( mpc != NULL ) 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->vnum == mpc->vnum ) { ch_printf( ch, "Fixing mob %d.\r\n", mob->vnum ); mpl->code = mpc->code; } } ch->desc->pString = NULL; ch->desc->pString_std = NULL; return; } /* * Truncate strings to MAX_STRING_LENGTH. * -------------------------------------- */ if( (ch->desc->pString != NULL && strlen(*ch->desc->pString) + strlen(lap) >= (MAX_STRING_LENGTH - 4)) || (ch->desc->pString_std != NULL && ch->desc->pString_std->size() + strlen(lap) >= (MAX_STRING_LENGTH - 4)) ) //if ( strlen( buf ) + strlen( lap ) >= ( MAX_STRING_LENGTH - 4 ) ) { ch_printf( ch, "String too long, last line skipped.\r\n" ); /* * Force character out of editing mode. */ ch->desc->pString = NULL; return; } else if(ch->desc->pString != NULL) strcpy( buf, *ch->desc->pString ); else strcpy(buf, ch->desc->pString_std->c_str()); /* * Ensure no tilde's inside string. * -------------------------------- */ smash_tilde( local_argument ); smash_tilde( buf ); strcat( buf, lap ); strcat( buf, "\r\n" ); if(ch->desc->pString != NULL) { free_string( *ch->desc->pString ); *ch->desc->pString = str_dup( buf ); } else *ch->desc->pString_std = buf; return; } /* * Thanks to Kalgen for the new procedure (no more bug!) * Original wordwrap() written by Surreality. */ /***************************************************************************** Name: format_string_const Purpose: Special string formating and word-wrapping. Called by: string_add(string.c) (many)olc_act.c ****************************************************************************/ char *format_string_const( const char *oldstring /* , bool fSpace */ ) { char xbuf[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; char xbuf2[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; char *rdesc = NULL; int i = 0; bool cap = true; for ( rdesc = str_dup(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, "\r\n" ); rdesc += i + 1; while ( *rdesc == ' ' ) rdesc++; } else { log_error( "No spaces" ); *( rdesc + 75 ) = 0; strcat( xbuf, rdesc ); strcat( xbuf, "-\r\n" ); 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, "\r\n" ); free_string( rdesc ); return ( str_dup( xbuf ) ); } char *format_string(char *oldstring) { char *retval = format_string_const(oldstring); free_string(oldstring); return retval; } void format_string(std::string &str) { // cheating :D format_string looks scary and will need to be cleaned up in the future. char *newstr = format_string_const(str.c_str()); str = newstr; free_string(newstr); } /* * 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) ****************************************************************************/ const char *first_arg( const char *argument, char *arg_first, bool fCase ) { char cEnd = '\0'; 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] = "\0\0\0\0\0\0\0"; char *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 = 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[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; int cnt = 1; int tmp = 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 ); } void string_linedel(std::string &str, int line) { size_t line_begin = string_getline(str, line); size_t next_line_begin = string_getline(str, line + 1); size_t line_length; if(next_line_begin == std::string::npos) line_length = std::string::npos; else line_length = next_line_begin - line_begin; str.erase(line_begin, line_length); } size_t string_getline(const std::string &str, int line) { size_t retval = 0; while(line-- > 1 && retval != std::string::npos) retval = str.find("\n", retval); // advance pos one more if the newline is \n\r. if(retval != std::string::npos && str.at(retval+1) == '\r') retval += 1; if(retval != 0 && retval != std::string::npos) // advance pos to point to the first character of the line. retval += 1; return retval; } char *string_lineadd( char *string, char *newstr, int line ) { char *strtmp = string; int cnt = 1; int tmp = 0; bool done = false; char buf[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; for ( ; *strtmp != '\0' || ( !done && cnt == line ); strtmp++ ) { if ( cnt == line && !done ) { strcat( buf, newstr ); strcat( buf, "\r\n" ); tmp += strlen( 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 ); } // Inserts newstr + a newline as line #. void string_lineadd(std::string &str, char *newstr, int line) { size_t insertpoint = string_getline(str, line); std::string insertme(newstr); insertme += "\r\n"; // if we didn't find the line, add the text to the end of the string. if(insertpoint == std::string::npos) str += insertme; else str.insert(insertpoint, insertme); } /* buf queda con la linea sin \r\n */ const char *getline( const char *str, char *buf ) { int tmp = 0; bool found = false; while ( *str ) { if ( *str == '\n' ) { found = true; break; } buf[tmp++] = *( str++ ); } if ( found ) { if ( *( str + 1 ) == '\r' ) str += 2; else str += 1; } /* para que quedemos en el inicio * de la prox linea */ buf[tmp] = '\0'; return str; } char *numlineas(const char *string ) { int cnt = 1; static char buf[MAX_STRING_LENGTH * 2] = "\0\0\0\0\0\0\0"; char buf2[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; char tmpb[MAX_STRING_LENGTH] = "\0\0\0\0\0\0\0"; buf[0] = '\0'; /* keep me, static */ while ( *string ) { string = getline( string, tmpb ); sprintf( buf2, "%2d. %s\r\n", cnt++, tmpb ); strcat( buf, buf2 ); } return buf; }