/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
/***************************************************************************
* 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 <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "tables.h"
#include "olc.h"
#if defined(WIN32)
#include "../win32/winstuff.h"
#endif
const char *string_linedel(const char *, int);
const char *string_lineadd(const char *, const char *, int);
const char *numlineas(const char *);
/*****************************************************************************
Name: string_edit
Purpose: Clears string and puts player into editing mode.
Called by: none
****************************************************************************/
void string_edit(CHAR_DATA * ch, const char **pString)
{
chprintln(ch, "-========- Entering EDIT Mode -=========-");
chprintlnf(ch, " Type %ch on a new line for help", STR_EDIT_KEY(ch));
chprintlnf(ch, " Terminate with a %cq or @ on a blank line.",
STR_EDIT_KEY(ch));
chprintln(ch, "-=======================================-");
if (*pString == NULL)
{
*pString = str_dup("");
}
else
{
*(char *) *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, const char **pString)
{
chprintln(ch, "-=======- Entering APPEND Mode -========-");
chprintlnf(ch, " Type %ch on a new line for help", STR_EDIT_KEY(ch));
chprintlnf(ch, " Terminate with a %cq or @ on a blank line.",
STR_EDIT_KEY(ch));
chprintln(ch, "-=======================================-");
if (*pString == NULL)
{
*pString = str_dup("");
}
chprint(ch, numlineas(*pString));
/* numlineas entrega el string con \n\r */
/* if ( *(*pString + strlen( *pString ) - 1) != '\r' )
chprint( "\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.
****************************************************************************/
const char *string_replace(const char *orig, char *old, char *pnew)
{
char xbuf[MAX_STRING_LENGTH];
int i;
xbuf[0] = '\0';
strcpy(xbuf, orig);
if (strstr(orig, old) != NULL)
{
i = strlen(orig) - strlen(strstr(orig, old));
xbuf[i] = '\0';
strcat(xbuf, pnew);
strcat(xbuf, &orig[i + strlen(old)]);
free_string(orig);
}
return str_dup(xbuf);
}
#define PARSE_FORMAT 0
#define PARSE_REPLACE 1
#define PARSE_REPLACE_ALL 2
#define PARSE_HELP 3
#define PARSE_DELETE 4
#define PARSE_INSERT 5
#define PARSE_LIST_NORM 6
#define PARSE_LIST_NUM 7
#define PARSE_EDIT 8
const char *del_last_line(const char *string)
{
int len;
bool found = FALSE;
char xbuf[MSL];
xbuf[0] = '\0';
if (IS_NULLSTR(string))
return (str_dup(xbuf));
strcpy(xbuf, string);
for (len = strlen(xbuf); len > 0; len--)
{
if (xbuf[len] == '\r')
{
if (!found)
{
if (len > 0)
len--;
found = TRUE;
}
else
{
xbuf[len + 1] = '\0';
free_string(string);
return (str_dup(xbuf));
}
}
}
xbuf[0] = '\0';
free_string(string);
return (str_dup(xbuf));
}
const char *string_replace_all(const 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;
}
void parse_action(const char **text, int command, const char *string,
CHAR_DATA * ch)
{
char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
switch (command)
{
case PARSE_HELP:
chprintln(ch,
"-------------------------------------------------------");
chprintlnf(ch,
"Edit help (commands on blank line):\n\r"
"%ch - get help (this info)\n\r"
"%cs - show string so far\n\r"
"%cS - show string so far without line numbers\n\r"
"%cf - formats text\n\r"
"%cc - clear string so far\n\r"
"%cd# - delete line number <num>\n\r"
"%cd - delete last line\n\r"
"%ci# <str> - insert <str> on line <num>\n\r"
"%ce# <str> - replace line <num> with <str>\n\r"
"%cr 'a' 'b' - replace first occurance of text\n\r"
"%cR 'a' 'b' - replace all occurances of text\n\r"
" usage: %cr 'pattern' 'replacement'\n\r"
"%c| <command> - execute a mud command\n\r"
"%cq - end string", STR_EDIT_KEY(ch),
STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
STR_EDIT_KEY(ch), STR_EDIT_KEY(ch), STR_EDIT_KEY(ch),
STR_EDIT_KEY(ch));
chprintln(ch, "------------------------------------------------------");
break;
case PARSE_FORMAT:
*text = format_string(*text);
chprintln(ch, "String formatted.");
break;
case PARSE_EDIT:
string = one_argument(string, arg1);
if (arg1[0] == '\0')
{
chprintln(ch, "You must specify a line number.");
return;
}
*text = string_linedel(*text, atoi(arg1));
*text = string_lineadd(*text, string, atoi(arg1));
chprintln(ch, "Line replaced.");
break;
case PARSE_DELETE:
if (string[0] == '\0')
*text = del_last_line(*text);
else
*text = string_linedel(*text, atoi(string));
chprintln(ch, "Line deleted.");
break;
case PARSE_REPLACE:
string = first_arg(string, arg1, FALSE);
string = first_arg(string, arg2, FALSE);
if (arg1[0] == '\0')
{
chprintln(ch, "Usage: .r 'old string' 'new string'");
return;
}
*text = string_replace(*text, arg1, arg2);
chprintlnf(ch, "'%s' replaced with '%s'.", arg1, arg2);
break;
case PARSE_REPLACE_ALL:
string = first_arg(string, arg1, FALSE);
string = first_arg(string, arg2, FALSE);
if (arg1[0] == '\0')
{
chprintln(ch, "Usage: .R 'old string' 'new string'");
return;
}
*text = string_replace_all(*text, arg1, arg2);
chprintlnf(ch, "All occurances of '%s' replaced with '%s'.",
arg1, arg2);
break;
case PARSE_INSERT:
string = first_arg(string, arg1, FALSE);
*text = string_lineadd(*text, string, atoi(arg1));
chprintln(ch, "Line inserted.");
break;
case PARSE_LIST_NORM:
chprintln(ch, "String so far:");
page_to_char(*text, ch);
break;
case PARSE_LIST_NUM:
chprintln(ch, "String so far:");
page_to_char(numlineas(*text), ch);
break;
default:
chprintln(ch, "Invalid command.");
bug("invalid command passed", 0);
break;
}
}
int parse_string_command(const char **text, const char *str, CHAR_DATA * ch)
{
int i = 2, j = 0;
char actions[MAX_INPUT_LENGTH];
if ((*str == STR_EDIT_KEY(ch)))
{
while (str[i] != '\0')
{
actions[j] = str[i];
i++;
j++;
}
actions[j] = '\0';
*(char *) str = '\0';
switch (str[1])
{
case 'q':
*(char *) str = '\0';
return STRING_END;
case '|':
interpret(ch, actions);
chprintln(ch, "Command performed.");
return STRING_FOUND;
case 'c':
chprintln(ch, "String cleared.");
replace_string(*text, "");
return STRING_FOUND;
case 's':
parse_action(text, PARSE_LIST_NUM, actions, ch);
return STRING_FOUND;
case 'S':
parse_action(text, PARSE_LIST_NORM, actions, ch);
return STRING_FOUND;
case 'r':
parse_action(text, PARSE_REPLACE, actions, ch);
return STRING_FOUND;
case 'R':
parse_action(text, PARSE_REPLACE_ALL, actions, ch);
return STRING_FOUND;
case 'f':
parse_action(text, PARSE_FORMAT, actions, ch);
return STRING_FOUND;
case 'd':
parse_action(text, PARSE_DELETE, actions, ch);
return STRING_FOUND;
case 'i':
parse_action(text, PARSE_INSERT, actions, ch);
return STRING_FOUND;
case 'e':
parse_action(text, PARSE_EDIT, actions, ch);
return STRING_FOUND;
case 'h':
parse_action(text, PARSE_HELP, actions, ch);
return STRING_FOUND;
default:
chprintln(ch, "Invalid command.");
return STRING_FOUND;
}
}
else if (*str == '@')
{
*(char *) str = '\0';
return STRING_END;
}
return STRING_NONE;
}
void string_add(CHAR_DATA * ch, char *argument)
{
char buf[MSL];
int action = 0;
action = parse_string_command(ch->desc->pString, argument, ch);
switch (action)
{
case STRING_END:
if (ch->desc->editor == ED_MPCODE)
{
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->first_mprog; mpl; mpl = mpl->next)
if (mpl->vnum == mpc->vnum)
{
chprintlnf(ch, "Fixing mob %ld.", mob->vnum);
replace_string(mpl->code, mpc->code);
}
}
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->first_oprog; opl; opl = opl->next)
if (opl->vnum == opc->vnum)
{
chprintlnf(ch, "Fixing object %ld.", obj->vnum);
replace_string(opl->code, opc->code);
}
}
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->first_rprog; rpl; rpl = rpl->next)
if (rpl->vnum == rpc->vnum)
{
chprintlnf(ch, "Fixing room %ld.", room->vnum);
replace_string(rpl->code, rpc->code);
}
}
ch->desc->pString = NULL;
chprintln(ch, "Done editing.");
return;
case STRING_FOUND:
return;
default:
case STRING_NONE:
strcpy(buf, *ch->desc->pString);
/*
* Truncate strings to MAX_STRING_LENGTH.
* --------------------------------------
*/
if (strlen(buf) + strlen(argument) >= ((MSL * 2) - 6))
{
chprintln(ch, "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, "\n\r");
free_string(*ch->desc->pString);
*ch->desc->pString = str_dup(buf);
return;
}
}
/*
* Thanks to Kalgen for the new procedure (no more bug!)
* Original wordwrap() written by Surreality.
*/
/*****************************************************************************
Name: format_string
Purpose: Special string formating and word-wrapping.
Called by: string_add(string.c) (many)olc_act.c
****************************************************************************/
const char *format_string(const char *oldstring /*, bool fSpace */ )
{
char xbuf[MAX_STRING_LENGTH];
char xbuf2[MAX_STRING_LENGTH];
const 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)
{
*(char *) (rdesc + i) = 0;
strcat(xbuf, rdesc);
strcat(xbuf, "\n\r");
rdesc += i + 1;
while (*rdesc == ' ')
rdesc++;
}
else
{
bug("No spaces", 0);
*(char *) (rdesc + 75) = 0;
strcat(xbuf, rdesc);
strcat(xbuf, "-\n\r");
rdesc += 76;
}
}
while (*(rdesc + i) &&
(*(rdesc + i) == ' ' || *(rdesc + i) == '\n' ||
*(rdesc + i) == '\r'))
i--;
*(char *) (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)
****************************************************************************/
const char *first_arg(const char *argument, char *arg_first, bool fCase)
{
char cEnd;
if (IS_NULLSTR(argument))
{
arg_first[0] = '\0';
return "";
}
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.
*/
const char *string_unpad(const char *argument)
{
char buf[MAX_STRING_LENGTH];
char *s;
s = (char *) 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.
*/
const char *string_proper(const char *argument)
{
char *s;
s = (char *) argument;
while (*s != '\0')
{
if (*s != ' ')
{
*s = UPPER(*s);
while (*s != ' ' && *s != '\0')
s++;
}
else
{
s++;
}
}
return argument;
}
const char *string_linedel(const char *string, int line)
{
const char *strtmp = string;
char buf[MAX_STRING_LENGTH];
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);
}
const char *string_lineadd(const char *string, const char *newstr, int line)
{
const char *strtmp = string;
int cnt = 1, tmp = 0;
bool done = FALSE;
char buf[MAX_STRING_LENGTH];
buf[0] = '\0';
for (; *strtmp != '\0' || (!done && cnt == line); strtmp++)
{
if (cnt == line && !done)
{
strcat(buf, newstr);
strcat(buf, "\n\r");
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);
}
/* buf queda con la linea sin \n\r */
const char *getline(const char *str, char *buf);
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;
}
const char *numlineas(const char *string)
{
int cnt = 1;
static char buf[MAX_STRING_LENGTH * 2];
char buf2[MAX_STRING_LENGTH], tmpb[MAX_STRING_LENGTH];
buf[0] = '\0';
while (*string)
{
string = getline(string, tmpb);
sprintf(buf2, "%2d. %s\n\r", cnt++, tmpb);
strcat(buf, buf2);
}
return buf;
}
bool is_ansi_printed_char(char c)
{
switch (c)
{
case ' ':
case '-':
case ANSI_KEY:
return TRUE;
default:
return FALSE;
}
}
/* Converts a ~ into a colour code for ~ */
const char *tilde_to_color(const char *str)
{
int i = 0;
char buf[MSL];
static char buf_new[5][MSL];
static int p;
char *result = buf_new[p];
// rotate buffers
++p;
p %= 5;
memset(buf, 0, MSL);
if (IS_NULLSTR(str))
return "";
while (*str != '\0')
{
if (*str == '~')
{
buf[i] = ANSI_KEY;
i++;
buf[i] = '-';
i++;
str++;
}
else
{
buf[i] = *str;
i++;
str++;
}
}
strcpy(result, buf);
return (result);
}
const char *smash_colour(const char *str)
{
int i = 0;
char buf[MSL];
static char buf_new[5][MSL];
static int p;
char *result = buf_new[p];
// rotate buffers
++p;
p %= 5;
memset(buf, 0, MSL);
if (IS_NULLSTR(str))
return "";
while (*str != '\0')
{
if (*str == ANSI_KEY)
{
str++;
if (*str == '-')
{
buf[i] = C_TILDE;
i++;
}
str++;
}
else
{
buf[i] = *str;
i++;
str++;
}
}
strcpy(result, buf);
return (result);
}
const char *color_to_tilde(const char *str)
{
int i = 0;
char buf[MSL];
static char buf_new[5][MSL];
static int p;
char *result = buf_new[p];
// rotate buffers
++p;
p %= 5;
memset(buf, 0, MSL);
if (IS_NULLSTR(str))
return "";
while (*str != '\0')
{
if (*str == ANSI_KEY)
{
if (*(str + 1) == '-')
{
buf[i] = '~';
i++;
str++;
str++;
}
else
{
buf[i] = *str;
i++;
str++;
}
}
else
{
buf[i] = *str;
i++;
str++;
}
}
strcpy(result, buf);
return (result);
}
const char *stringf(CHAR_DATA * ch, int length, int align, const char *fill,
const char *string)
{
const char *count_string;
char temp;
int count = 0, nCount = 0;
int pos = 0;
char *result;
static char buf_new[5][MSL];
static int i;
// rotate buffers
++i;
i %= 5;
result = buf_new[i];
count_string = string;
if (!fill)
fill = " ";
if (length <= 0)
{
if (!ch || !ch->desc)
length = 79;
else
length = ch->desc->scr_width - 1;
}
while (*count_string && nCount != length)
{
temp = *count_string++;
if (temp == ANSI_KEY)
{
temp = *count_string++;
if (is_ansi_printed_char(temp))
nCount++;
continue;
}
nCount++;
}
if (align == ALIGN_RIGHT)
{
count = (length - ++nCount);
while (nCount++ <= length)
{
result[pos++] = *fill;
}
}
if (align == ALIGN_CENTER)
{
nCount = (length - nCount) / 2;
count = nCount;
while (nCount-- > 0)
{
result[pos++] = *fill;
}
}
while (*string && count != length)
{
temp = *string++;
result[pos++] = temp;
if (temp == ANSI_KEY)
{
temp = result[pos] = *string++;
if (is_ansi_printed_char(temp))
count++;
pos++;
continue;
}
count++;
}
while (count++ < length)
result[pos++] = *fill;
result[pos] = '\0';
return (result);
}
unsigned int strlen_color(const char *string)
{
unsigned int count = 0;
if (IS_NULLSTR(string))
return count;
while (*string != '\0')
{
if (*string != ANSI_KEY)
{
count++;
string++;
continue;
}
else if (*string == ANSI_KEY && is_ansi_printed_char(*(string + 1)))
{
string++;
string++;
count++;
continue;
}
else if (*string == ANSI_KEY && *(string + 1) != '\0')
{
string++;
string++;
continue;
}
else if (*string == ANSI_KEY && *(string + 1) == '\0')
{
break;
}
else
{
count++;
string++;
continue;
}
}
return count;
}
/* returns TRUE if the last char in a string i a colour code */
bool check_cstring(char *string)
{
unsigned int i;
if (string[0] == '\0')
{
return FALSE;
}
for (i = 0; i < strlen(string); i++)
{
if (string[i] == '\0')
{
return FALSE;
}
else if (string[i] != ANSI_KEY)
{
continue;
}
else if (string[i] == ANSI_KEY && string[i + 1] != '\0')
{
i++;
continue;
}
else if (string[i] == ANSI_KEY && string[i + 1] == '\0')
{
return TRUE;
}
else
{
continue;
}
}
return FALSE;
}
/* Can use colour coded fills like eg. draw_line("{w-{W+{R*{W+", 0); */
const char *draw_line(CHAR_DATA * ch, char *fill, int len)
{
static char buf_new[5][MSL];
static int i;
int mod;
int l;
char lbuf[MSL];
int count;
unsigned int m;
char *result;
// rotate buffers
++i;
i %= 5;
result = buf_new[i];
result[0] = '\0';
if (!fill)
fill = "-";
if (len <= 0)
{
if (!ch || !ch->desc)
len = 79;
else
len = ch->desc->scr_width - 1;
}
mod = len % strlen_color(fill);
len /= strlen_color(fill);
for (l = 0; l < len; l++)
strcat(result, fill);
count = 0;
lbuf[0] = '\0';
for (m = 0; m < strlen(fill); m++)
{
if (fill[m] == ANSI_KEY)
{
lbuf[m] = fill[m];
m++;
lbuf[m] = fill[m];
if (is_ansi_printed_char(lbuf[m]))
count++;
if (count >= mod)
break;
continue;
}
else
{
lbuf[m] = fill[m];
count++;
if (count >= mod)
break;
}
}
if (lbuf[m - 1] == ANSI_KEY)
{
lbuf[m] = 'x';
}
else
{
lbuf[m] = ANSI_KEY;
lbuf[++m] = 'x';
}
lbuf[++m] = '\0';
strcat(result, lbuf);
return result;
}
CH_CMD(do_strkey)
{
if (IS_NPC(ch))
return;
if (IS_NULLSTR(argument) || strlen(argument) > 1)
{
chprintln(ch, "Syntax: strkey <key>");
chprintln(ch, "Where <key> can be any 1 letter you want ");
chprintln(ch, "to use for string editor commands.");
return;
}
if (!isascii(argument[0]) || argument[0] == ' ' || argument[0] == '\\')
{
chprintln(ch, "Invalid string editor key.");
return;
}
ch->pcdata->str_ed_key = argument[0];
chprintlnf(ch, "The string editor now uses %c for commands.",
STR_EDIT_KEY(ch));
}
char *FORMATF(const char *formatbuf, ...)
{
static int i;
static char buf[10][MSL * 3];
va_list args;
++i;
i %= 10;
va_start(args, formatbuf);
vsnprintf(buf[i], sizeof(buf[i]), formatbuf, args);
va_end(args);
return buf[i];
}