cotn/notes/
cotn/src/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments 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.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  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.                                                  *
 ***************************************************************************/

/***************************************************************************
 *  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.                *
 *                                                                         *
 ***************************************************************************/
 /***************************************************************************
 *                                 _/                            _/        *
 *      _/_/_/  _/_/      _/_/_/  _/    _/_/    _/    _/    _/_/_/         *
 *     _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/          *
 *    _/    _/    _/  _/        _/  _/    _/  _/    _/  _/    _/           *
 *   _/    _/    _/    _/_/_/  _/    _/_/      _/_/_/    _/_/_/            *
 ***************************************************************************
 * Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius),                 *
 * Additional credits are in the help file CODECREDITS                     *
 * All Rights Reserved.                                                    *
 ***************************************************************************/


#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "olc.h"

char     *string_linedel(char *, int);
char     *string_lineadd(char *, char *, int);
char     *numlineas(char *);

/*
 * Returns an all-caps string.		OLC 1.1b
 */
char     *all_capitalize(const char *str)
{
        static char strcap[MAX_STRING_LENGTH];
        int       i;

        for (i = 0; str[i] != '\0'; i++)
                strcap[i] = UPPER(str[i]);
        strcap[i] = '\0';
        return strcap;
}

/*****************************************************************************
 Name:          commanum
 Purpose:       Places a comma in appropriate places for large numbers
 Notes:         Written originally by Kagai for SoH
 ****************************************************************************/
char     *commanum(int number)
{
        static char string[MAX_STRING_LENGTH];
        char      string2[MAX_STRING_LENGTH];
        char      thing[MAX_STRING_LENGTH];
        char      negative[MAX_STRING_LENGTH];
        int       x, y;

        xprintf(thing, "%d", number);
        strcpy(string, "");

        for (x = (strlen(thing) - 1), y = 0; x >= 0; x--)
        {
                xprintf(string2, "%s%s%c", string, (y >= 3) ? "," : "",
                        thing[x]);
                if (y >= 3)
                        y = 0;
                strcpy(string, string2);
                xprintf(negative, "%c", thing[x]);
                if (str_cmp(negative, "-"))
                        y++;
        }
        strcpy(thing, string);
        strcpy(string, "");
        for (x = (strlen(thing) - 1); x >= 0; x--)
        {
                xprintf(string2, "%s%c", string, thing[x]);
                strcpy(string, string2);
        }
        return &string[0];
}

/*****************************************************************************
 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("#Y-========- #wEntering EDIT Mode#Y -=========-\n\r",
                     ch);
        send_to_char("#w    Type .h on a new line for help\n\r", ch);
        send_to_char("#w Terminate with a ~ or @ on a blank line.\n\r", ch);
        send_to_char("#Y-=======================================-\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)
{
        send_to_char("#Y-=======- #wEntering APPEND Mode #Y-========-\n\r",
                     ch);
        send_to_char("#w    Type .h on a new line for help\n\r", ch);
        send_to_char("#w Terminate with a ~ or @ on a blank line.\n\r", ch);
        send_to_char("#Y-=======================================-\n\r", ch);

        if (*pString == NULL)
        {
                *pString = str_dup("");
        }
        send_to_char(numlineas(*pString), ch);

/* numlineas entrega el string con \n\r */
/*  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.
 ****************************************************************************/
char     *string_replace(char *orig, char *old, char *new)
{
        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, new);
                strcat(xbuf, &orig[i + strlen(old)]);
                free_string(orig);
        }

        return str_dup(xbuf);
}


/* OLC 1.1b */
/*****************************************************************************
 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];

        /*
         * Thanks to James Seng
         */
        smash_tilde(argument);

        if (*argument == '.')
        {
                char      arg1[MAX_INPUT_LENGTH];
                char      arg2[MAX_INPUT_LENGTH];
                char      arg3[MAX_INPUT_LENGTH];
                char      tmparg3[MAX_INPUT_LENGTH];

                argument = one_argument(argument, arg1);
                argument = first_arg(argument, arg2, FALSE);
                strcpy(tmparg3, argument);
                argument = first_arg(argument, arg3, FALSE);

                if (!str_cmp(arg1, ".c"))
                {
                        send_to_char("String cleared.\n\r", ch);
                        free_string(*ch->desc->pString);
                        *ch->desc->pString = str_dup("");
                        return;
                }

                if (!str_cmp(arg1, ".s"))
                {
                        send_to_char("String so far:\n\r", ch);
                        send_to_char(numlineas(*ch->desc->pString), ch);
                        return;
                }

                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);
                        sprintf(buf, "'%s' replaced with '%s'.\n\r", arg2,
                                arg3);
                        send_to_char(buf, ch);
                        return;
                }

                if (!str_cmp(arg1, ".f"))
                {
                        *ch->desc->pString =
                                format_string(*ch->desc->pString);
                        send_to_char("String formatted.\n\r", ch);
                        return;
                }

                if (!str_cmp(arg1, ".ld"))
                {
                        *ch->desc->pString =
                                string_linedel(*ch->desc->pString,
                                               atoi(arg2));
                        send_to_char("Line deleted\n\r", ch);
                        return;
                }

                if (!str_cmp(arg1, ".li"))
                {
                        *ch->desc->pString =
                                string_lineadd(*ch->desc->pString, tmparg3,
                                               atoi(arg2));
                        send_to_char("Line inserted.\n\r", ch);
                        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));
                        send_to_char("Line replaced.\n\r", ch);
                        return;
                }

                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
                                (".ld <num>        - delete line number <num>\n\r",
                                 ch);
                        send_to_char
                                (".li <num> <str>  - insert <str> on line <num>\n\r",
                                 ch);
                        send_to_char
                                (".lr <num> <str>  - replace line <num> with <str>\n\r",
                                 ch);
                        send_to_char
                                ("@                - end string          \n\r",
                                 ch);
                        return;
                }

                send_to_char("SEdit:  Invalid dot command.\n\r", ch);
                return;
        }

        if (*argument == '~' || *argument == '@')
        {
                if (ch->desc->editor == ED_MPCODE)  /* para los 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)
                                                        {
                                                                xprintf(buf,
                                                                        "Fixing mob %d.\n\r",
                                                                        mob->
                                                                        vnum);
                                                                send_to_char
                                                                        (buf,
                                                                         ch);
                                                                mpl->code =
                                                                        mpc->
                                                                        code;
                                                        }
                        if (ch->desc->editor == ED_OPCODE)  /* for the objprogs */
                        {
                                OBJ_INDEX_DATA *obj;
                                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)
                                                                {
                                                                        xprintf(buf, "Fixing object %d.\n\r", obj->vnum);
                                                                        send_to_char
                                                                                (buf,
                                                                                 ch);
                                                                        opl->code = opc->code;
                                                                }
                        }

                        if (ch->desc->editor == ED_RPCODE)  /* for the roomprogs */
                        {
                                ROOM_INDEX_DATA *room;
                                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)
                                                                {
                                                                        xprintf(buf, "Fixing room %d.\n\r", room->vnum);
                                                                        send_to_char
                                                                                (buf,
                                                                                 ch);
                                                                        rpl->code = rpc->code;
                                                                }
                        }
                }

                ch->desc->pString = NULL;
                send_to_char("You have exited the editor.\n\r", ch);
                return;
        }

        strcpy(buf, *ch->desc->pString);

        /*
         * Truncate strings to MAX_STRING_LENGTH.
         * --------------------------------------
         */
        //if ( strlen( buf ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
        if (strlen(*ch->desc->pString) + 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;
        }

        /*
         * 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
 ****************************************************************************/
char     *format_string(char *oldstring /*, bool fSpace */ )
{
        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
                {
                        bug("No spaces", 0);
                        *(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);
}



/*
 * 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[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);
}

char     *string_lineadd(char *string, char *newstr, int line)
{
        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 */
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[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;
}