/*************************************************************************** * 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. * * * ***************************************************************************/ /********************************************************** *************** S U N D E R M U D *** 2 . 0 ************** ********************************************************** * The unique portions of the SunderMud code as well as * * the integration efforts for code from other sources is * * based primarily on the efforts of: * * * * Lotherius <aelfwyne@operamail.com> (Alvin W. Brinson) * * and many others, see "help sundermud" in the mud. * **********************************************************/ #include <stdarg.h> #include <limits.h> #include "everything.h" #include "olc.h" char *numlineas( char * ); char *getline( char *, char * ); char *linedel( char *, int ); char *lineadd( char *, char *, int ); /***************************************************************************** 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 ( "-==[ 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 @ 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 ) { if ( ch->pcdata->mode == MODE_DESCEDIT ) send_to_char ( "-==[ Description Editor ]======================================-\n\r", ch ); else if ( ch->pcdata->mode == MODE_LEASEDESC ) send_to_char ( "-==[ Lease Description ]=======================================-\n\r", ch ); else send_to_char ( "-==[ String 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 @ on a blank line.\n\r", ch ); send_to_char ( "-==============================================================-\n\r", ch ); if ( *pString == NULL ) { *pString = str_dup ( "" ); } send_to_char ( numlineas(*pString), ch ); 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. Notes: Fixes by Calath(gblues@jps.net) to prevent buffer overruns ****************************************************************************/ char *string_replace(char *orig, char *old, char *new) { char buf[MSL]; char *ptr; int a, b; if ( (ptr = strstr(orig, old)) == NULL || ( a = ptr - orig ) + strlen(new) >=(MSL-4) ) return orig; b = MSL - 4 - a - strlen(new); strncpy ( buf, orig, MSL ); strncpy ( buf+a, new, strlen(new)); strncpy ( buf+a+strlen(new), ptr+strlen(old), b); buf[MSL-4]='\0'; free_string ( orig ); return str_dup ( buf ); } /***************************************************************************** Name: string_add Purpose: Interpreter for string editing. Called by: game_loop_xxxx(comm.c). ****************************************************************************/ void string_add ( CHAR_DATA * ch, char *argument ) { char buf[MAX_STRING_LENGTH]; if ( *argument == '.' ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; char arg3[MAX_INPUT_LENGTH]; char tmparg[MIL]; argument = one_argument ( argument, arg1 ); argument = first_arg ( argument, arg2, FALSE ); strcpy( tmparg, argument ); argument = first_arg ( argument, arg3, FALSE ); if ( !str_cmp ( arg1, ".c" ) ) { send_to_char ( "String cleared.\n\r", ch ); *ch->desc->pString = str_dup( "" ); return; } else if ( !str_cmp ( arg1, ".s" ) ) { send_to_char ( "String so far:\n\r", ch ); send_to_char ( numlineas(*ch->desc->pString), ch ); return; } else if ( !str_cmp ( arg1, ".d" ) ) { int tot_len, i, count = 0; char newbuf[1024]; char buf[MAX_STRING_LENGTH*4]; send_to_char ( "Deleting last line.\n\r", ch ); strcpy ( buf, *ch->desc->pString ); tot_len = strlen ( buf ); if ( tot_len < 3 ) /*no lines left, just null or line terminators */ { send_to_char ( "No lines left to delete.\n\r", ch ); return; } for ( i = ( tot_len ); ( ( i >= 0 ) && ( count < 2 ) ); i-- ) { if ( buf[i] == '\r' ) count++; } if ( !( i <= 0 ) ) { strncpy ( newbuf, buf, ( i + 2 ) ); newbuf[i + 2] = '\0'; } else newbuf[0] = '\0'; free_string ( *ch->desc->pString ); *ch->desc->pString = str_dup ( newbuf ); send_to_char ( "Ok.\n\r", ch ); return; } else if ( !str_cmp ( arg1, ".r" ) ) { if ( arg2[0] == '\0' ) { send_to_char ( "usage: .r \"old string\" \"new string\"\n\r", ch ); return; } *ch->desc->pString = string_replace ( *ch->desc->pString, arg2, arg3 ); form_to_char ( ch, "'%s' replaced with '%s'.\n\r", arg2, arg3 ); return; } else if ( !str_cmp ( arg1, ".f" ) ) { *ch->desc->pString = format_string ( *ch->desc->pString ); send_to_char ( "String formatted.\n\r", ch ); return; } else if ( !str_cmp( arg1, ".ld" ) ) { *ch->desc->pString = linedel( *ch->desc->pString, atoi(arg2) ); write_to_buffer( ch->desc, "Line deleted.\n\r", 0 ); return; } else if ( !str_cmp( arg1, ".li" ) ) { if ( strlen( *ch->desc->pString ) + strlen( tmparg ) >= ( MAX_STRING_LENGTH - 4 ) ) { write_to_buffer( ch->desc, "Too long.\n\r", 0 ); return; } *ch->desc->pString = lineadd( *ch->desc->pString, tmparg, atoi(arg2)); write_to_buffer( ch->desc, "Line Inserted.\n\r", 0 ); return; } else if ( !str_cmp( arg1, ".lr" ) ) { *ch->desc->pString = linedel( *ch->desc->pString, atoi(arg2) ); *ch->desc->pString = lineadd( *ch->desc->pString, tmparg, atoi(arg2) ); write_to_buffer( ch->desc, "Line Replaced.\n\r", 0 ); return; } else if ( !str_cmp ( arg1, ".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 ( ".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 ( ".d - delete the last line\n\r", ch ); send_to_char ( ".ld <num> - delete line <num> \n\r", ch ); send_to_char ( ".li <num> <txt> - insert <txt> at <num>\n\r", ch ); send_to_char ( ".lr <num> <txt> - replace line <num> w/<txt>\n\r", ch ); send_to_char ( "@ - end string \n\r", ch ); return; } send_to_char ( "Edit: Invalid dot command - Use .h for help.\n\r", ch ); return; } if ( *argument == '@' ) { if ( ch->desc->editor == ED_MPCODE ) /* for mobprogs */ { MOB_INDEX_DATA *mob; int hash; PROG_LIST *mpl; PROG_CODE *mpc; 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 ) { form_to_char ( ch, "Fixing mob %d.\n\r", mob->vnum ); mpl->code = mpc->code; } } else if ( ch->desc->editor == ED_OPCODE ) /* for the objprogs */ { OBJ_INDEX_DATA *obj; int hash; PROG_LIST *opl; PROG_CODE *opc; EDIT_OPCODE(ch, opc); if ( opc != NULL ) for ( hash = 0; hash < MAX_KEY_HASH; hash++ ) for ( obj = obj_index_hash[hash]; obj; obj = obj->next ) for ( opl = obj->oprogs; opl; opl = opl->next ) if ( opl->vnum == opc->vnum ) { form_to_char ( ch, "Fixing object %d.\n\r", obj->vnum ); opl->code = opc->code; } } else if ( ch->desc->editor == ED_RPCODE ) /* for the roomprogs */ { ROOM_INDEX_DATA *room; int hash; PROG_LIST *rpl; PROG_CODE *rpc; EDIT_RPCODE(ch, rpc); if ( rpc != NULL ) for ( hash = 0; hash < MAX_KEY_HASH; hash++ ) for ( room = room_index_hash[hash]; room; room = room->next ) for ( rpl = room->rprogs; rpl; rpl = rpl->next ) if ( rpl->vnum == rpc->vnum ) { form_to_char ( ch, "Fixing room %d.\n\r", room->vnum ); rpl->code = rpc->code; } } ch->pcdata->mode = MODE_NORMAL; ch->desc->pString = NULL; return; } if ( ch->pcdata->mode == MODE_LEASEDESC ) smash_codes ( argument ); strcpy ( buf, *ch->desc->pString ); /* * Truncate strings to MAX_STRING_LENGTH. * -------------------------------------- */ if ( strlen ( *ch->desc->pString ) + strlen ( argument ) >= ( MAX_STRING_LENGTH - 200 ) ) { send_to_char ( "String too long, extra truncated.\n\r", ch ); /* Force character out of editing mode. */ ch->desc->pString = NULL; return; } 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. */ /* * This function needs to become colour-code aware. */ /***************************************************************************** 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) { 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 { // Okay so somebody tried to format a string with no spaces... // Why are we calling it a bug??? // bugf ( "No spaces" ); *( 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 ); } /* Very basic "int" to "string" conversion function * I'm sure this is done somewhere in the std C library, but I couldn't * find it - Lotherius */ char *itos ( int num ) { char buf[256]; SNP ( buf, "%d", num ); 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; } /* Complete with Spanish from OLC 2.01 or so.... */ char * rip_arg( char *argument, char *arg_first ) { int tipo; while ( *argument && isspace(*argument) ) argument++; if ( isalpha(*argument) ) tipo = 0; /* letras */ else if ( isdigit(*argument) ) tipo = 1; /* numeros */ else tipo = 2; /* otros */ while ( *argument ) { if ( (isalpha(*argument) && tipo != 0) || (isdigit(*argument) && tipo != 1) || (!isalpha(*argument) && !isdigit(*argument) && tipo != 2) ) break; *arg_first = LOWER(*argument); arg_first++; argument++; } *arg_first = '\0'; while ( isspace(*argument) ) argument++; return argument; } int linecount( char *str ) { int cnt = 0; while (*str) if ( *(str++) == '\n' ) cnt++; return cnt; } /* Working linedel from EmberMUD.. Ivan's and Calath's linedel both freaked. */ char *linedel(char *str, int line ) { int len, buflen; int count = 0; char *pOut, outbuf[4*MAX_STRING_LENGTH], buf[4*MAX_STRING_LENGTH]; strcpy(buf, str); 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(str); return str_dup(outbuf); } char *getline( 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; } buf[tmp] = '\0'; return str; } char *numlineas( char *string ) { int cnt = 1; static char buf[MSL*2]; char buf2[MSL], tmpb[MSL]; buf[0] = '\0'; while ( *string ) { string = getline( string, tmpb ); SNP( buf2, "{C%2d:{W>{w %s\n\r", cnt++, tmpb ); strcat( buf, buf2 ); } return buf; } /* New lineadd by Calath to prevent buffer overrun */ char *lineadd( char *string, char *newstr, int line ) { char *lineend, *linestart = string; char buf[MAX_STRING_LENGTH]; char newline[MAX_INPUT_LENGTH]; int bytes = 0, cnt = 1, done = FALSE; int len; SNP (newline, "%s\n\r", newstr); newstr = newline; if (strlen (string) + strlen (newstr) >= MAX_STRING_LENGTH - 4) return string; do { if (cnt == line) { strncpy (buf + bytes, newstr, strlen (newstr)); bytes += strlen (newstr); cnt++; continue; } if ((lineend = strstr (linestart, "\n\r")) == NULL) done = TRUE; /* Can't get rid of this warning due to fscking strlen */ len = lineend ? (lineend + 2) - linestart : strlen (linestart); strncpy (buf + bytes, linestart, len); bytes += len; linestart = lineend ? lineend + 2 : linestart; cnt++; } while (!done); buf[bytes] = '\0'; free_string (string); return str_dup ( 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. If BUFFER_DEBUG is defined, the buffer_strcat call is defined as having 2 extra parameters, __LINE__ and __FILE__. These are then saved to the bug file if an overflow occurs. Erwin S. Andreasen <erwin@pip.dknet.dk> */ #define EMEM_SIZE -1 /* find_mem_size returns this when block is too large */ #define NUL '\0' 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 */ #ifndef BUFFER_DEBUG /* no debugging */ BUFFER * __buffer_new (int min_size) #else /* debugging - expect filename and line */ BUFFER * __buffer_new (int min_size, const char * file, unsigned line) #endif { int size; BUFFER *buffer; size = find_mem_size (min_size); if (size == EMEM_SIZE) { #ifdef BUFFER_DEBUG bugf ( "Buffer size too big: %d bytes (%s:%u).", min_size, file, line); #else bugf ( "Buffer size too big: %d bytes.", min_size); #endif abort(); } buffer = alloc_mem (sizeof(BUFFER), "BUFFER" ); buffer->size = size; buffer->data = alloc_mem (size, "BUFFER" ); buffer->overflowed = FALSE; buffer->len = 0; return buffer; } /* __buf_new */ /* Add a string to a buffer. Expand if necessary */ #ifndef BUFFER_DEBUG /* no debugging */ void __buffer_strcat (BUFFER *buffer, const char *text) #else /* debugging - expect filename and line */ void __buffer_strcat (BUFFER *buffer, const char *text, const char * file, unsigned line) #endif { int new_size; int text_len; char *new_data; 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 ? */ { #ifdef BUFFER_DEBUG bugf ( "Buffer overflow, wanted %d bytes (%s:%u).", text_len+buffer->len, file, line); #else bugf ( "Buffer overflow, wanted %d bytes.",text_len+buffer->len); #endif buffer->overflowed = TRUE; return; } /* Allocate the new buffer */ new_data = alloc_mem (new_size, "BUFFER"); /* Copy the current buffer to the new buffer */ memcpy (new_data, buffer->data, buffer->len); free_mem (buffer->data, buffer->size, "BUFFER"); buffer->data = new_data; buffer->size = new_size; } /* if */ 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 */ } /* __buf_strcat */ /* Free a buffer */ void buffer_free (BUFFER *buffer) { /* Free data */ free_mem (buffer->data, buffer->size, "BUFFER"); /* Free buffer */ free_mem (buffer, sizeof(BUFFER), "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. */ int bprintf (BUFFER *buffer, char *fmt, ...) { char buf[MSL]; va_list va; int res; va_start (va, fmt); res = vsnprintf (buf, MSL, fmt, va); va_end (va); if (res >= MSL-1) { buf[0] = NUL; bugf ("Overflow when bprintf'ing a string" ); } else buffer_strcat (buffer, buf); return res; } /* strlen() that doesn't count any valid color codes -Zak */ /* Adapted to Sunder from EmberMud by Lotherius */ int cstrlen( const char *str ) { int numb=0; while (*str != '\0') { if (*str != '{') /* If there's no {, add to the count */ { numb++; str++; continue; } str++; /* If there _IS_ a {, check next char */ switch (*str) { /* If it's \0, count the first { and get outta here */ case '\0': numb++; return numb; /* If it doesn't take space, skip over it */ /* / (newline char) doesn't really fit in here, but we'll count it anyway. */ case 'x': case 'b': case 'c': case 'd': case 'g': case 'm': case 'r': case 'w': case 'y': case 'B': case 'C': case 'G': case 'M': case 'R': case 'W': case 'Y': case 'D': case '*': case '/': case '3': case '4': case '&': str++; break; /* If it's not a color code, count the following char (but not the {), and advance */ default: numb++; str++; break; } continue; } return numb; } /* We have to emulate the functionaility of strlcat and strlcpy on Win32 and Linux */ /* This should also work on any OS that doesn't have strlcat or strlcpy. */ #ifndef __FreeBSD__ /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(initial dst) + strlen(src); if retval >= siz, * truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif /* * This function is simply here to provide a place to test new code * without having to make new calls for it in interp.c, etc before it * is production ready. This is called from within the mud by "test" * by the imp only. */ void do_testfunc ( CHAR_DATA * ch, char *argument ) { send_to_char ( "No test code is ready.\n\r", ch ); return; }