/************************************************************************** * 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 <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" #include "tables.h" #include "olc.h" 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 -=========-"); chprintln (ch, " Type .h on a new line for help"); chprintln (ch, " Terminate with a .q or @ on a blank line."); 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 -========-"); chprintln (ch, " Type .h on a new line for help"); chprintln (ch, " Terminate with a .q or @ on a blank line."); 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, "-------------------------------------------------------"); chprintln (ch, "Edit help (commands on blank line):\n\r" ".h - get help (this info)\n\r" ".s - show string so far\n\r" ".S - show string so far without line numbers\n\r" ".f - formats text\n\r" ".c - clear string so far\n\r" ".d# - delete line number <num>\n\r" ".d - delete last line\n\r" ".i# <str> - insert <str> on line <num>\n\r" ".e# <str> - replace line <num> with <str>\n\r" ".r 'a' 'b' - replace first occurance of text\n\r" ".R 'a' 'b' - replace all occurances of text\n\r" " usage: .r 'pattern' 'replacement'\n\r" ".| <command> - execute a mud command\n\r" ".q - end string"); 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 == '.')) { 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; MPROG_LIST *mpl; MPROG_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) { chprintlnf (ch, "Fixing mob %ld.", mob->vnum); mpl->code = mpc->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; 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; } /* Converts a ~ into a colour code for ~ */ void tilde_to_color (char *buffer, char *str) { int i = 0; char buf[MSL]; memset (buf, 0, MSL); if (!str || *str == '\0') return; while (*str != '\0') { if (*str == '~') { buf[i] = ANSI_KEY; i++; buf[i] = '-'; i++; str++; } else { buf[i] = *str; i++; str++; } } strcpy (buffer, buf); return; } /* Removes all colour coding from a string */ void smash_colour (char *buffer, const char *str) { int i = 0; char buf[MSL]; memset (buf, 0, MSL); if (!str || *str == '\0') return; while (*str != '\0') { if (*str == ANSI_KEY) { str++; str++; } else if (*str == ANSI_CUSTOM) { str++; while (*str != ANSI_END) str++; str++; } else { buf[i] = *str; i++; str++; } } strcpy (buffer, buf); return; } /* Converts a colour code for a ~ into a ~ */ void color_to_tilde (char *buffer, char *str) { int i = 0; char buf[MSL]; memset (buf, 0, MSL); if (!str || *str == '\0') return; while (*str != '\0') { if (*str == ANSI_KEY) { str++; if (*str == '-') { buf[i] = '~'; i++; str++; } else str++; } else { buf[i] = *str; i++; str++; } } strcpy (buffer, buf); return; } /* formats a string into a length and alignment *fill can be used as NULL, length '0' returns 77 */ void stringf (char *buffer, int length, int align, char *fill, char *string) { char buf[MSL]; char buf2[MSL]; char *new_string; char *count_string; char temp; int count = 0, nCount = 0; int pos = 0; new_string = buf; count_string = buf2; strcpy (buf2, string); if (!fill) fill = " "; if (length == 0) length = 77; while (*count_string && nCount != length) { temp = *count_string++; if (temp == ANSI_KEY) { temp = *count_string++; if (temp == ANSI_KEY) nCount++; continue; } else if (temp == ANSI_CUSTOM) { temp = *count_string++; while (temp != ANSI_END) temp = *count_string++; continue; } nCount++; } if (align == ALIGN_RIGHT) { count = (length - ++nCount); while (nCount++ <= length) { buf[pos++] = *fill; } } if (align == ALIGN_CENTER) { nCount = (length - nCount) / 2; count = nCount; while (nCount-- > 0) { buf[pos++] = *fill; } } while (*string && count != length) { temp = *string++; buf[pos++] = temp; if (temp == ANSI_KEY) { temp = buf[pos] = *string++; if (temp == ANSI_KEY) count++; pos++; continue; } else if (temp == ANSI_CUSTOM) { temp = buf[pos] = *string++; while (temp != ANSI_END) { pos++; temp = buf[pos] = *string++; } pos++; continue; } count++; } while (count++ < length) buf[pos++] = *fill; buf[pos] = '\0'; strcpy (buffer, new_string); return; } /* Counts the length of a string excluding colour codes */ int strlen_color (const char *string) { int i, count = 0; char arg[MSL]; if (!string) return count; strcpy (arg, string); for (i = 0; i <= MIL; i++) { if (arg[i] == '\0') { break; } else if (string[i] != ANSI_KEY && string[i] != ANSI_CUSTOM) { count++; continue; } else if (arg[i] == ANSI_KEY && arg[i + 1] == ANSI_KEY) { i++; count++; continue; } else if (arg[i] == ANSI_KEY && arg[i + 1] != ANSI_KEY && arg[i + 1] != '\0') { i += 1; continue; } else if (arg[i] == ANSI_CUSTOM) { i += 1; while (arg[i] != ANSI_END) i += 1; i += 1; continue; } else if (arg[i] == ANSI_KEY && arg[i + 1] == '\0') { break; } else { count++; 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); */ char *draw_line (char *fill, int len) { static char buf_new[MSL]; int mod; int l; char lbuf[MSL]; int count; unsigned int m; buf_new[0] = '\0'; if (!fill) fill = "-"; if (len <= 0) { len = 79; } mod = len % strlen_color (fill); len /= strlen_color (fill); for (l = 0; l < len; l++) strcat (buf_new, fill); count = 0; lbuf[0] = '\0'; for (m = 0; m < strlen (fill); m++) { if (fill[m] == '{') { lbuf[m] = fill[m]; m++; lbuf[m] = fill[m]; continue; } else { lbuf[m] = fill[m]; count++; if (count >= mod) break; } } lbuf[m] = '{'; lbuf[++m] = 'x'; lbuf[++m] = '\0'; strcat (buf_new, lbuf); return buf_new; }