/*************************************************************************** * 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. * * * ***************************************************************************/ #if defined(macintosh) #include <types.h> #else #include <sys/types.h> #endif #include <cctype> #include <cstdio> #include <cstdlib> #include <stdarg.h> #include <cstring> #include <ctime> #include "merc.h" #include "tables.h" #include "olc.h" char *string_linedel (char *, int); char *string_lineadd (char *, char *, int); char *numlines (char *); bool is_ansi_printed_char(char c); extern char *string_space; extern char *top_string; extern char str_empty[1]; /*Dumped here now*/ char *nsprintf(char *fr, char *fmt, ...) { char buf[2*MSL]; va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); free_string(fr); return str_dup(buf); } /* source: EOD, by John Booth <???> */ void ch_printf(CHAR_DATA *ch, char *fmt, ...) { char buf[MAX_STRING_LENGTH*2]; /* better safe than sorry */ va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); send_to_char(buf, ch); } void printf_to_world(char *fmt, ...) { char buf[2*MSL]; va_list args; DESCRIPTOR_DATA *d; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); for(d=descriptor_list;d;d=d->next) { if(d->character==NULL) continue; send_to_char(buf, d->character); } return; } /* JH 3/29/2004 5:27PM *Basically take "stuff %s" where %s is "poop" and return "stuff poop". *If we didn't have this, we would have to do char buf[MSL]; and do *sprintfs in every function where we wanted to send debug messages. *This function makes use of va stuff. */ char *create_string(char *fmt, ...) { static char buf[2*MSL]; va_list args; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); return buf; } void printf_to_room(ROOM_INDEX_DATA *rm, char *fmt, ...) { char buf[2*MSL]; va_list args; CHAR_DATA *ch; va_start(args,fmt); vsprintf(buf,fmt,args); va_end(args); for(ch=rm->people;ch;ch=ch->next_in_room) send_to_char(buf, ch); return; } /*end dump*/ /***************************************************************************** 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 ("-========- Entering {YEDIT {cMode{x -=========-\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) { send_to_char ("-=======- Entering {CAPPEND {xMode{x -========-\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 (numlines (*pString), ch); /* numlines sends the string with \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_str) { 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_str); strcat (xbuf, &orig[i + strlen (old)]); free_string (orig); } return str_dup (xbuf); } /***************************************************************************** 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 (numlines (*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); ch_printf (ch, "'%s' replaced with '%s'.\n\r", arg2, arg3); 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, ".poop")) { *ch->desc->pString = nice_format (*ch->desc->pString); send_to_char ("String formatted (not like ass).\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 (".p - properly indent code (for programs)\n\r", ch); send_to_char (".ld <num> - delete line number <num>\n\r", ch); send_to_char (".li <num> <str> - insert <str> at 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) { /* for the 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) { ch_printf(ch, "Editing mob %d.\n\r", mob->vnum); mpl->code = mpc->code; mpl->comments = mpc->comments; } } 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 ) { ch_printf( ch, "Fixing object %d.\n\r", obj->vnum ); opl->code = opc->code; opl->comments = opc->comments; } } 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 ) { ch_printf( ch, "Fixing room %d.\n\r", room->vnum ); rpl->code = rpc->code; rpl->comments = rpc->comments; } } ch->desc->pString = NULL; return; } strcpy (buf, *ch->desc->pString); /* * Truncate strings to MAX_STRING_LENGTH. * -------------------------------------- * Edwin strikes again! Fixed avoid adding to a too-long * note. JR -- 10/15/00 */ 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 line 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; } /* para que quedemos en el inicio de la prox linea */ buf[tmp] = '\0'; return str; } char *numlines (char *str) { int cnt = 1; static char buf[MAX_STRING_LENGTH * 2]; char buf2[MAX_STRING_LENGTH], tmpb[MAX_STRING_LENGTH]; buf[0] = '\0'; while (*str) { str = getline (str, tmpb); sprintf (buf2, "%2d. %s\n\r", cnt++, tmpb); strcat (buf, buf2); } return buf; } /* Can use colour coded fills like eg. draw_line("{w-{W+{R*{W+", 0); */ /* From 1stMUD (Ryan Jennings)*/ 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) { len = 79; /*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 if (fill[m] == ANSI_CUSTOM) { lbuf[m] = fill[m]; m++; while (fill[m] != ANSI_END) { lbuf[m] = fill[m]; m++; } lbuf[m] = fill[m]; m++; 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); strcat(result, "\n\r"); 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) { length = 79; /*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; } 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) { 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; } else if (temp == ANSI_CUSTOM) { temp = result[pos++] = *string++; while (temp != ANSI_END) temp = result[pos++] = *string++; continue; } count++; } while (count++ < length) result[pos++] = *fill; result[pos] = '\0'; return (result); } bool is_ansi_printed_char(char c) { switch (c) { case ' ': case '-': case ANSI_KEY: return TRUE; default: return FALSE; } } unsigned int strlen_color(const char *string) { unsigned int count = 0; if (string == NULL) return count; while (*string != '\0') { if (*string != ANSI_KEY && *string != ANSI_CUSTOM) { 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_CUSTOM && *(string + 1) != '\0') { string++; while (*string != '\0' && *string != ANSI_END) string++; string++; continue; } else if ((*string == ANSI_KEY || *string == ANSI_CUSTOM) && *(string + 1) == '\0') { break; } else { count++; string++; continue; } } return count; } /* ** TRIM.C - Remove leading, trailing, & excess embedded spaces ** ** public domain by Bob Stout & Michael Dehlwes */ char *trim (char *str) { char *ibuf, *obuf; if (str) { for (ibuf = obuf = str; *ibuf; ) { while (*ibuf && (isspace (*ibuf))) ibuf++; if (*ibuf && (obuf != str)) *(obuf++) = ' '; while (*ibuf && (!isspace (*ibuf))) *(obuf++) = *(ibuf++); } *obuf = '\0'; } return (str); } /*JH: Format a string, leaving paragraph breaks alone. Anything else is not touched, except for the whitespace. 4/2/2004 3:00AM */ char *nice_format(char *str) { char buf[MSL]; //Smash the fucking \r, if they exist. smash_slashr(str); //Now trim it. //str = trim(str); //Wrap. //str_wrap(str, 80); return str; strcpy(buf, str); free_string (str); return (str_dup (buf)); } char *smash_slashr( char *str ) //broken as fuck. { /*I don't fucking touch share read only strings. I hate them.*/ if (str == NULL || str == &str_empty[0] || (str >= string_space && str < top_string)) return str; for( ; *str != '\0'; str++) { if( *str == '\r' ) { memmove(str-1, str, strlen(str-1)); --str; writelogf("Moved str 1 left; *str is now: %c poop", *str); } if( *str == '\n') { if (*(str+1) && *(str+1) != '\n') { memmove(str-1, str, strlen(str-1)); --str; writelogf("str was \\n and 1 ahead was too; *str is now: %c poop", *str); } else { *str = ' '; writelogf("just one \\n, *str is now: %c poop", *str); } } } return str; } char *str_wrap ( char *str, int width) { int i_len = 0; int breakat = 0; char buf[MSL]; if (--width < 20) width = 78; char *str_start = str; while (*str) { if (++i_len >= width) { i_len = 0; if (isspace(*str)) *str = '\n'; else { breakat = 0; while (*str && str >= str_start && !isspace(*str)) { buf[breakat++] = *str; str--; if (breakat > 2500) { writelogf(buf); return str; } } if (*str && str >= str_start) *str = '\n'; } str++; } str++; } return str; } //quick and ugly itoa code. JH 6/9/2004 7:27PM char *itoa (int d) { static char buf[MSL]; sprintf(buf, "%d", d); return buf; }