tbamud/src/improved-edit.c

690 lines
19 KiB
C
Raw Normal View History

/**************************************************************************
* File: improved-edit.c Part of tbaMUD *
* Usage: Routines specific to the improved editor. *
**************************************************************************/
2006-12-19 22:56:18 +00:00
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "interpreter.h"
#include "improved-edit.h"
jeremyosborne | 2008-04-04 02:36:38 +0200 (Fri, 04 Apr 2008) | 1 line Minor Bugfix: All game configuration settings now reference the world config structure, not the individual config variables found in config.c. ------------------------------------------------------------------------ rumble | 2008-03-22 13:27:00 +0100 (Sat, 22 Mar 2008) | 1 line Added lib/world/qst/ directory, index, index.mini, and 0.qst. ------------------------------------------------------------------------ jeremyosborne | 2008-03-08 03:27:51 +0100 (Sat, 08 Mar 2008) | 3 lines Bugfix: the include directory (for .h files) is now referenced correctly in the depend statement. Deletion: listrent.c removed as a separate utility. ------------------------------------------------------------------------ jeremyosborne | 2008-03-08 03:08:51 +0100 (Sat, 08 Mar 2008) | 1 line Enhancement: utils/ Makefile will now use a depends file, and looks for dependen cies in the ../ directory (shrinks the necessary information to make each utilit y). ------------------------------------------------------------------------ Rumble | 2008-03-06 23:39:35 +0100 (Thu, 06 Mar 2008) | 1 line Made TBA specific changes. do_cheat, removed help level checking, and advance to level 32. ------------------------------------------------------------------------ jeremyosborne | 2008-03-06 18:37:12 +0100 (Thu, 06 Mar 2008) | 1 line Minor Update: Changed header of Makefile.in to read 'tbaMUD' and also added in a ttribution for the changes. (Thanks seqwith.) ------------------------------------------------------------------------ jeremyosborne | 2008-03-06 18:31:07 +0100 (Thu, 06 Mar 2008) | 4 lines Changed Makefile.in to use glob expressions when building the objects. This translates into no longer a need to update Makefile.in whenever a new .c file is added to the mud code. Other Makefile.* have not yet been changed (and need review, anyway). All CXREF cruft left in Makefile.in has been removed. tbaMUD is now using Doxygen. Technically, CXREF provides a bit more auto-documentation than Doxygen does, however the tbaMUD (and legacy circle code) has never been marked-up with the special CXREF codes required to effectively use the program. Since Doxygen is easier to use, and provides almost as much functionality as CXREF, CXREF support has been dropped. ------------------------------------------------------------------------ jeremyosborne | 2008-03-06 08:31:02 +0100 (Thu, 06 Mar 2008) | 1 line Bug Fix: asciiflag_conv* functions now can handle a negative numeric value. ------------------------------------------------------------------------ jeremyosborne | 2008-03-06 08:16:06 +0100 (Thu, 06 Mar 2008) | 1 line Bug fix/enhancement: Charmed mobs (specifically charmed mobs with a ->master) will no longer attempt to wander off. ------------------------------------------------------------------------ jeremyosborne | 2008-03-06 08:13:38 +0100 (Thu, 06 Mar 2008) | 6 lines Based on the compiler warning about mag_materials being an unused function, and the clone spell being unused. Bug fix: Clone can now be cast. It is an 'ignore' target spell. Fix and Modification: Clone, being an effectively unused spell that is only used by mortal Magic Users at level 30, is now implemented as very simple example of how to use mag_materials(). The item required by mag_materials is vnum 161, which in stock tbaMUD is some sacrificial entrails. ------------------------------------------------------------------------ jeremyosborne | 2008-03-05 01:43:09 +0100 (Wed, 05 Mar 2008) | 3 lines Bug Fix for "Did you mean:" including DG commands. ------------------------------------------------------------------------ jeremyosborne | 2008-03-05 01:29:18 +0100 (Wed, 05 Mar 2008) | 3 lines Bug Fix: do_simple_move slightly rewritten to handle Leave triggers that purge a door. Documentation: do_simple_move documented. ------------------------------------------------------------------------ Laoris | 2008-03-01 08:22:12 +0100 (Sat, 01 Mar 2008) | 1 line Trial run of columnizer function on commands list to see how people like it. ------------------------------------------------------------------------ jeremyosborne | 2008-02-26 22:36:17 +0100 (Tue, 26 Feb 2008) | 1 line asciimap, an in game automap, along with a couple of minor bug fixes to do with the automap, patched in (Thanks Jamdog). ------------------------------------------------------------------------ jeremyosborne | 2008-02-22 04:08:05 +0100 (Fri, 22 Feb 2008) | 1 line Minor update: Relocate local variable declaration to the top of ACMD(do_help) ------------------------------------------------------------------------ jeremyosborne | 2008-02-22 04:04:37 +0100 (Fri, 22 Feb 2008) | 6 lines Checked in the following placeholders for do_gen_tog: #define SCMD_AUTOLOOT 24 #define SCMD_AUTOGOLD 25 #define SCMD_AUTOSPLIT 26 #define SCMD_AUTOSAC 27 #define SCMD_AUTOASSIST 28 ------------------------------------------------------------------------ jeremyosborne | 2008-02-22 03:57:06 +0100 (Fri, 22 Feb 2008) | 1 line The Autoquest patch, along with a couple of minor bug fixes, has been integrated into tbaMUD. (Thanks Jamdog, Kenneth Ray and Morgaelin.) ------------------------------------------------------------------------ jeremyosborne | 2008-02-18 21:46:45 +0100 (Mon, 18 Feb 2008) | 2 lines Minor Fix: Casted NOWHERE, NOTHING, NOBODY and NOFLAG as IDXTYPE for the signed short int index types. ------------------------------------------------------------------------ jeremyosborne | 2008-02-18 03:36:16 +0100 (Mon, 18 Feb 2008) | 7 lines Added a new atoidx() conversion function for dealing with string to IDXTYPE conversions (in utils.c, prototype exported through utils.h). Added IDXTYPE_MIN and IDXTYPE_MAX defines (in structs.h). Replaced atoi references with atoidx in do_oasis_zedit (in zedit.c). ------------------------------------------------------------------------ Rumble | 2008-02-18 01:44:13 +0100 (Mon, 18 Feb 2008) | 1 line Fixed direction mapping to give readable directions instead of sub commands. ------------------------------------------------------------------------ jeremyosborne | 2008-02-18 00:26:15 +0100 (Mon, 18 Feb 2008) | 5 lines Since general olc editing are automatically saved to disk, 'shutdown reboot' has been changed to not-autosave by default. (Small change made to do_shutdown in act.wizard.c). ------------------------------------------------------------------------ jeremyosborne | 2008-02-18 00:12:12 +0100 (Mon, 18 Feb 2008) | 3 lines Changed: struct attack_hit_type moved to fight.h attack_hit_text exported through fight.h ------------------------------------------------------------------------ jeremyosborne | 2008-02-17 22:32:51 +0100 (Sun, 17 Feb 2008) | 7 lines - do_file heads or tails files correctly and has also been enhanced to return file info (act.wizard.c) - defines made for common log files created by autorun, and those used by do_file (db.h) - utility functions added: file_head(), file_tail(), file_sizeof(), and file_numlines() (defined utils.c and exported through utils.h) ------------------------------------------------------------------------ Rumble | 2008-02-16 23:24:05 +0100 (Sat, 16 Feb 2008) | 1 line Fixed export command. (thanks Kyle) ------------------------------------------------------------------------ jeremyosborne | 2008-02-16 22:42:46 +0100 (Sat, 16 Feb 2008) | 1 line Files are now tagged as executable. Should be able to be checked out from subver sion and executed without running chmod. ------------------------------------------------------------------------ Rumble | 2008-02-15 17:03:06 +0100 (Fri, 15 Feb 2008) | 1 line Fixed strcat() writing out of bounds in cedit.c since strdup() only malloc() strlen(str)+1 bytes. (thanks Buggo) and moved attack_hit_text back. ------------------------------------------------------------------------ jeremyosborne | 2008-02-13 20:41:02 +0100 (Wed, 13 Feb 2008) | 1 line Event queue function definitions, global variables and defines doxygenated. ------------------------------------------------------------------------ Rumble | 2008-02-12 00:23:38 +0100 (Tue, 12 Feb 2008) | 1 line Updated levels command to use an arg/range and added color parsing to greetings. (thanks Jamdog) ------------------------------------------------------------------------ jeremyosborne | 2008-02-11 21:06:10 +0100 (Mon, 11 Feb 2008) | 1 line Doxygen comments completed for weather.c ------------------------------------------------------------------------ Rumble | 2008-02-11 03:52:50 +0100 (Mon, 11 Feb 2008) | 1 line Corrected several 64-bit warnings. (thanks Buggo) ------------------------------------------------------------------------ Rumble | 2008-02-10 22:56:56 +0100 (Sun, 10 Feb 2008) | 1 line Added get_flag_by_name allowing for new trigedit variable checks like %actor.pref(FLAG)% checks. (thanks Jamdog) ------------------------------------------------------------------------ jeremyosborne | 2008-02-08 21:22:26 +0100 (Fri, 08 Feb 2008) | 3 lines COMPLETE: tbaMUD code re-org of global and local scope function and variable declarations. There may be a few things that I did not catch (some non extern keyword declarations of function prototypes within other functions, for example). BUG FIX: Unused functions encrypt_hex() and decrypt_hex() removed from mail.c. ------------------------------------------------------------------------ jeremyosborne | 2008-02-05 23:31:09 +0100 (Tue, 05 Feb 2008) | 2 lines Continued clean-up of 'extern' references to functions and variables. BUG UNCOVERED: set_title() in class.c incorrectly handles the const nature of the char * returned from title_female and title_male. ------------------------------------------------------------------------ jeremyosborne | 2008-02-05 19:38:17 +0100 (Tue, 05 Feb 2008) | 3 lines More work on mud clean-up. New file: spec_procs.h Created this file to house the legacy special procedures (spec_procs.c and castle.c) and special feature assignment in general. ------------------------------------------------------------------------ jeremyosborne | 2008-02-05 00:59:44 +0100 (Tue, 05 Feb 2008) | 3 lines - Minor Bugfix: Fixed parse error in mobact.c - Minor Bugfix: act.h is now included in all of the act functions. Forgot to do that the first time :( - Additions: ban.h has been added as the external entry point into the ban.c globals and functions. Files needing ban.h have been updated. ------------------------------------------------------------------------ jeremyosborne | 2008-02-04 20:02:11 +0100 (Mon, 04 Feb 2008) | 1 line All act*.c functions, defines and globals have been prototyped/declared in act.h. The file act.h does not contain every ACMD, only those ACMDs and utility functions available within the act*.c files. ------------------------------------------------------------------------ Rumble | 2008-02-04 17:59:47 +0100 (Mon, 04 Feb 2008) | 1 line Fixed the last few flags missed for the 128 bit conversion. ------------------------------------------------------------------------ Laoris | 2008-02-04 07:27:56 +0100 (Mon, 04 Feb 2008) | 3 lines Adding a column formatter for lists. Accepts printf-like arguments. Only used by medit right now. ------------------------------------------------------------------------ jeremyosborne | 2008-02-04 07:09:19 +0100 (Mon, 04 Feb 2008) | 2 lines - Changed the 'struct queue' to 'struct dg_queue' to avoid namespace conflicts. - Ongoing cleanup to mud project. ------------------------------------------------------------------------ Rumble | 2008-02-04 00:07:09 +0100 (Mon, 04 Feb 2008) | 1 line Fixed run_autowiz which ran twice on advancement. ------------------------------------------------------------------------ jeremyosborne | 2008-02-03 03:46:22 +0100 (Sun, 03 Feb 2008) | 1 line act.h created and added. This header will be the external entry point for the functions, function subcommands and variables within the act*.c files. It is not designed to be the entry point for all ACMD functions. ------------------------------------------------------------------------ jeremyosborne | 2008-02-03 02:44:29 +0100 (Sun, 03 Feb 2008) | 1 line Merge of another part of the code cleanup, the dg script stuff. ------------------------------------------------------------------------ jeremyosborne | 2008-02-02 08:56:03 +0100 (Sat, 02 Feb 2008) | 1 line Modularizing and organizing files continues. Committing comm.c and comm.h because they are hairy, and I don't want to do them over if my hard drive crashes. ------------------------------------------------------------------------ jeremyosborne | 2008-02-02 07:05:08 +0100 (Sat, 02 Feb 2008) | 4 lines - Marking all file scope functions as 'static' - Reorganization of the global variables and functions. ------------------------------------------------------------------------ jeremyosborne | 2008-01-31 10:20:47 +0100 (Thu, 31 Jan 2008) | 1 line * Protected the conf.h.* system config files from multiple calls. ------------------------------------------------------------------------ jeremyosborne | 2008-01-31 09:56:18 +0100 (Thu, 31 Jan 2008) | 1 line * Removed extraneous references to TRUE / FALSE and YES / NO defines. ------------------------------------------------------------------------ jeremyosborne | 2008-01-31 09:46:20 +0100 (Thu, 31 Jan 2008) | 2 lines * BUGFIX: NUM_POSITIONS set to 8 (was incorrectly set to 15 before) * Migrated NUM_* settings from oasis.h to more appropriate locations near where they are defined. (For Example: NUM_POSITIONS moved to structs.h next to the POSITION_* defines.) ------------------------------------------------------------------------ jeremyosborne | 2008-01-31 03:58:28 +0100 (Thu, 31 Jan 2008) | 1 line Added Appendix A - Coder Support. Right now, it simply speaks to the fact that we have included doxygen config files, are working to document the source code, and provides a rudimentary "do this" guide to create the doxygen cross references. ------------------------------------------------------------------------ jeremyosborne | 2008-01-30 07:12:07 +0100 (Wed, 30 Jan 2008) | 2 lines - All .h files now have doxygen recognized headers, and the format is slightly altered to ease editing of headers. - Protected all .h files from multiple calls. (Standard format is #ifndef _HEADE R_H_ #define _HEADER_H_ .... #endif) ------------------------------------------------------------------------ jeremyosborne | 2008-01-29 11:18:14 +0100 (Tue, 29 Jan 2008) | 1 line constants.h, structs.h and utils.h now protected from multiple includes. This is sometimes overkill, but good practice overall. ------------------------------------------------------------------------ jeremyosborne | 2008-01-29 10:38:18 +0100 (Tue, 29 Jan 2008) | 1 line Updated documentation for constants.c and constants.h. ------------------------------------------------------------------------ jeremyosborne | 2008-01-29 10:15:25 +0100 (Tue, 29 Jan 2008) | 3 lines The standard Doxygen configuration doxyfiles (config files) for tbaMUD. One is to be used with the Graphviz DOT (dox_withGraphs), one is designed to be used if Graphviz is not available. Now just need a short document describing the usage of doxygen. ------------------------------------------------------------------------ jeremyosborne | 2008-01-29 10:11:36 +0100 (Tue, 29 Jan 2008) | 1 line Minor document correction in struct dex_app_tpe. ------------------------------------------------------------------------ jeremyosborne | 2008-01-28 20:53:51 +0100 (Mon, 28 Jan 2008) | 1 line *bugfix* do_drink command: When a container is empty, the correct, "It is empty." message is now displayed. ------------------------------------------------------------------------ jeremyosborne | 2008-01-28 07:58:15 +0100 (Mon, 28 Jan 2008) | 3 lines Merging changes to trunk for: * utils.h, utils.c and structs.h doxygen comments * adding file dox_withGraphs.doxyfile
2008-04-12 01:31:58 +00:00
#include "dg_scripts.h"
#include "modify.h"
2006-12-19 22:56:18 +00:00
void send_editor_help(struct descriptor_data *d)
{
if (using_improved_editor)
write_to_output(d, "Instructions: /s to save, /h for more options.\r\n");
else
write_to_output(d, "Instructions: Type @ on a line by itself to end.\r\n");
}
#if CONFIG_IMPROVED_EDITOR
int improved_editor_execute(struct descriptor_data *d, char *str)
{
char actions[MAX_INPUT_LENGTH];
if (*str != '/')
return STRINGADD_OK;
strncpy(actions, str + 2, sizeof(actions) - 1);
actions[sizeof(actions) - 1] = '\0';
*str = '\0';
switch (str[1]) {
case 'a':
return STRINGADD_ABORT;
case 'c':
if (*(d->str)) {
free(*d->str);
*(d->str) = NULL;
write_to_output(d, "Current buffer cleared.\r\n");
} else
write_to_output(d, "Current buffer empty.\r\n");
break;
case 'd':
parse_edit_action(PARSE_DELETE, actions, d);
2006-12-19 22:56:18 +00:00
break;
case 'e':
parse_edit_action(PARSE_EDIT, actions, d);
2006-12-19 22:56:18 +00:00
break;
case 'f':
if (*(d->str))
parse_edit_action(PARSE_FORMAT, actions, d);
2006-12-19 22:56:18 +00:00
else
write_to_output(d, "Current buffer empty.\r\n");
break;
case 'i':
if (*(d->str))
parse_edit_action(PARSE_INSERT, actions, d);
2006-12-19 22:56:18 +00:00
else
write_to_output(d, "Current buffer empty.\r\n");
break;
case 'h':
parse_edit_action(PARSE_HELP, actions, d);
2006-12-19 22:56:18 +00:00
break;
case 'l':
if (*d->str)
parse_edit_action(PARSE_LIST_NORM, actions, d);
2006-12-19 22:56:18 +00:00
else
write_to_output(d, "Current buffer empty.\r\n");
break;
case 'n':
if (*d->str)
parse_edit_action(PARSE_LIST_NUM, actions, d);
2006-12-19 22:56:18 +00:00
else
write_to_output(d, "Current buffer empty.\r\n");
break;
case 'r':
parse_edit_action(PARSE_REPLACE, actions, d);
2006-12-19 22:56:18 +00:00
break;
case 's':
return STRINGADD_SAVE;
case 't':
parse_edit_action(PARSE_TOGGLE, actions, d);
break;
2006-12-19 22:56:18 +00:00
default:
write_to_output(d, "Invalid option.\r\n");
break;
}
return STRINGADD_ACTION;
}
/* Handle some editor commands. */
void parse_edit_action(int command, char *string, struct descriptor_data *d)
2006-12-19 22:56:18 +00:00
{
int indent = 0, rep_all = 0, flags = 0, replaced, i, line_low, line_high, j = 0;
unsigned int total_len;
char *s, *t, temp;
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
switch (command) {
case PARSE_HELP:
write_to_output(d,
2006-12-19 22:56:18 +00:00
"Editor command formats: /<letter>\r\n\r\n"
"/a - aborts editor\r\n"
"/c - clears buffer\r\n"
"/d# - deletes a line #\r\n"
"/e# <text> - changes the line at # with <text>\r\n"
"/f - formats text\r\n"
"/fi - indented formatting of text\r\n"
"/h - list text editor commands\r\n"
"/i# <text> - inserts <text> before line #\r\n"
"/l - lists buffer\r\n"
"/n - lists buffer with line numbers\r\n"
"/r 'a' 'b' - replace 1st occurance of text <a> in buffer with text <b>\r\n"
"/ra 'a' 'b'- replace all occurances of text <a> within buffer with text <b>\r\n"
" usage: /r[a] 'pattern' 'replacement'\r\n"
"/t - toggles '@' and tabs\r\n"
2006-12-19 22:56:18 +00:00
"/s - saves text\r\n");
break;
case PARSE_TOGGLE:
if (strchr(*d->str, '@')) {
parse_at(*d->str);
write_to_output(d, "Toggling (at) into (tab) Characters...\r\n");
} else {
parse_tab(*d->str);
write_to_output(d, "Toggling (tab) into (at) Characters...\r\n");
}
break;
2006-12-19 22:56:18 +00:00
case PARSE_FORMAT:
if (STATE(d) == CON_TRIGEDIT) {
write_to_output(d, "Script %sformatted.\r\n", format_script(d) ? "": "not ");
return;
}
while (isalpha(string[j]) && j < 2) {
if (string[j++] == 'i' && !indent) {
indent = TRUE;
flags += FORMAT_INDENT;
}
}
switch (sscanf((indent ? string + 1 : string), " %d - %d ", &line_low, &line_high))
2006-12-19 22:56:18 +00:00
{
case -1:
case 0:
line_low = 1;
line_high = 999999;
break;
case 1:
line_high = line_low;
break;
case 2:
if (line_high < line_low) {
write_to_output(d, "That range is invalid.\\r\\n");
return;
}
break;
}
/* in case line_low is negative or zero */
line_low = MAX(1, line_low);
format_text(d->str, flags, d, d->max_str, line_low, line_high);
write_to_output(d, "Text formatted with%s indent.\r\n", (indent ? "" : "out"));
break;
case PARSE_REPLACE:
while (isalpha(string[j]) && j < 2)
if (string[j++] == 'a' && !indent)
rep_all = 1;
if ((s = strtok(string, "'")) == NULL) {
write_to_output(d, "Invalid format.\r\n");
return;
} else if ((s = strtok(NULL, "'")) == NULL) {
write_to_output(d, "Target string must be enclosed in single quotes.\r\n");
return;
} else if ((t = strtok(NULL, "'")) == NULL) {
write_to_output(d, "No replacement string.\r\n");
return;
} else if ((t = strtok(NULL, "'")) == NULL) {
write_to_output(d, "Replacement string must be enclosed in single quotes.\r\n");
return;
/*wb's fix for empty buffer replacement crashing */
} else if ((!*d->str)) {
return;
} else if ((total_len = ((strlen(t) - strlen(s)) + strlen(*d->str))) <= d->max_str) {
if ((replaced = replace_str(d->str, s, t, rep_all, d->max_str)) > 0) {
write_to_output(d, "Replaced %d occurance%sof '%s' with '%s'.\r\n", replaced, ((replaced != 1) ? "s " : " "), s, t);
} else if (replaced == 0) {
write_to_output(d, "String '%s' not found.\r\n", s);
} else
write_to_output(d, "ERROR: Replacement string causes buffer overflow, aborted replace.\r\n");
} else
write_to_output(d, "Not enough space left in buffer.\r\n");
break;
case PARSE_DELETE:
switch (sscanf(string, " %d - %d ", &line_low, &line_high)) {
case 0:
write_to_output(d, "You must specify a line number or range to delete.\r\n");
return;
case 1:
line_high = line_low;
break;
case 2:
if (line_high < line_low) {
write_to_output(d, "That range is invalid.\r\n");
return;
}
break;
}
i = 1;
total_len = 1;
if ((s = *d->str) == NULL) {
write_to_output(d, "Buffer is empty.\r\n");
return;
} else if (line_low > 0) {
while (s && i < line_low)
if ((s = strchr(s, '\n')) != NULL) {
i++;
s++;
}
if (s == NULL || i < line_low) {
write_to_output(d, "Line(s) out of range; not deleting.\r\n");
return;
}
t = s;
while (s && i < line_high)
if ((s = strchr(s, '\n')) != NULL) {
i++;
total_len++;
s++;
}
if (s && (s = strchr(s, '\n')) != NULL) {
while (*(++s))
*(t++) = *s;
} else
total_len--;
*t = '\0';
RECREATE(*d->str, char, strlen(*d->str) + 3);
write_to_output(d, "%d line%sdeleted.\r\n", total_len, (total_len != 1 ? "s " : " "));
} else {
write_to_output(d, "Invalid, line numbers to delete must be higher than 0.\r\n");
return;
}
break;
case PARSE_LIST_NORM:
/* Note: Rv's buf, buf1, buf2, and arg variables are defined to 32k so they
* are ok for what we do here. */
2006-12-19 22:56:18 +00:00
*buf = '\0';
if (*string)
switch (sscanf(string, " %d - %d ", &line_low, &line_high)) {
case 0:
line_low = 1;
line_high = 999999;
break;
case 1:
line_high = line_low;
break;
} else {
line_low = 1;
line_high = 999999;
}
if (line_low < 1) {
write_to_output(d, "Line numbers must be greater than 0.\r\n");
return;
} else if (line_high < line_low) {
write_to_output(d, "That range is invalid.\r\n");
return;
}
*buf = '\0';
if (line_high < 999999 || line_low > 1)
sprintf(buf, "Current buffer range [%d - %d]:\r\n", line_low, line_high);
i = 1;
total_len = 0;
s = *d->str;
while (s && (i < line_low))
if ((s = strchr(s, '\n')) != NULL) {
i++;
s++;
}
if (i < line_low || s == NULL) {
write_to_output(d, "Line(s) out of range; no buffer listing.\r\n");
return;
}
t = s;
while (s && i <= line_high)
if ((s = strchr(s, '\n')) != NULL) {
i++;
total_len++;
s++;
}
if (s) {
temp = *s;
*s = '\0';
strcat(buf, t);
*s = temp;
} else
strcat(buf, t);
/* This is kind of annoying...but some people like it. */
sprintf(buf + strlen(buf), "\r\n%d line%sshown.\r\n", total_len, (total_len != 1) ? "s " : " ");
2006-12-19 22:56:18 +00:00
page_string(d, buf, TRUE);
break;
case PARSE_LIST_NUM:
/* Note: Rv's buf, buf1, buf2, and arg variables are defined to 32k so they
* are probably ok for what we do here. */
2006-12-19 22:56:18 +00:00
*buf = '\0';
if (*string)
switch (sscanf(string, " %d - %d ", &line_low, &line_high)) {
case 0:
line_low = 1;
line_high = 999999;
break;
case 1:
line_high = line_low;
break;
} else {
line_low = 1;
line_high = 999999;
}
if (line_low < 1) {
write_to_output(d, "Line numbers must be greater than 0.\r\n");
return;
}
if (line_high < line_low) {
write_to_output(d, "That range is invalid.\r\n");
return;
}
*buf = '\0';
i = 1;
total_len = 0;
s = *d->str;
while (s && i < line_low)
if ((s = strchr(s, '\n')) != NULL) {
i++;
s++;
}
if (i < line_low || s == NULL) {
write_to_output(d, "Line(s) out of range; no buffer listing.\r\n");
return;
}
t = s;
while (s && i <= line_high)
if ((s = strchr(s, '\n')) != NULL) {
i++;
total_len++;
s++;
temp = *s;
*s = '\0';
sprintf(buf, "%s%4d: ", buf, (i - 1));
strcat(buf, t);
*s = temp;
t = s;
}
if (s && t) {
temp = *s;
*s = '\0';
strcat(buf, t);
*s = temp;
} else if (t)
strcat(buf, t);
page_string(d, buf, TRUE);
break;
case PARSE_INSERT:
half_chop(string, buf, buf2);
if (*buf == '\0') {
write_to_output(d, "You must specify a line number before which to insert text.\r\n");
return;
}
line_low = atoi(buf);
strcat(buf2, "\r\n");
i = 1;
*buf = '\0';
if ((s = *d->str) == NULL) {
write_to_output(d, "Buffer is empty, nowhere to insert.\r\n");
return;
}
if (line_low > 0) {
while (s && (i < line_low))
if ((s = strchr(s, '\n')) != NULL) {
i++;
s++;
}
if (i < line_low || s == NULL) {
write_to_output(d, "Line number out of range; insert aborted.\r\n");
return;
}
temp = *s;
*s = '\0';
if ((strlen(*d->str) + strlen(buf2) + strlen(s + 1) + 3) > d->max_str) {
*s = temp;
write_to_output(d, "Insert text pushes buffer over maximum size, insert aborted.\r\n");
return;
}
if (*d->str && **d->str)
strcat(buf, *d->str);
*s = temp;
strcat(buf, buf2);
if (s && *s)
strcat(buf, s);
RECREATE(*d->str, char, strlen(buf) + 3);
strcpy(*d->str, buf);
write_to_output(d, "Line inserted.\r\n");
} else {
write_to_output(d, "Line number must be higher than 0.\r\n");
return;
}
break;
case PARSE_EDIT:
half_chop(string, buf, buf2);
if (*buf == '\0') {
write_to_output(d, "You must specify a line number at which to change text.\r\n");
return;
}
line_low = atoi(buf);
strcat(buf2, "\r\n");
i = 1;
*buf = '\0';
if ((s = *d->str) == NULL) {
write_to_output(d, "Buffer is empty, nothing to change.\r\n");
return;
}
if (line_low > 0) {
/* Loop through the text counting \n characters until we get to the line. */
2006-12-19 22:56:18 +00:00
while (s && i < line_low)
if ((s = strchr(s, '\n')) != NULL) {
i++;
s++;
}
/* Make sure that there was a THAT line in the text. */
2006-12-19 22:56:18 +00:00
if (s == NULL || i < line_low) {
write_to_output(d, "Line number out of range; change aborted.\r\n");
return;
}
/* If s is the same as *d->str that means I'm at the beginning of the
* message text and I don't need to put that into the changed buffer. */
2006-12-19 22:56:18 +00:00
if (s != *d->str) {
/* First things first .. we get this part into the buffer. */
2006-12-19 22:56:18 +00:00
temp = *s;
*s = '\0';
/* Put the first 'good' half of the text into storage. */
2006-12-19 22:56:18 +00:00
strcat(buf, *d->str);
*s = temp;
}
/* Put the new 'good' line into place. */
2006-12-19 22:56:18 +00:00
strcat(buf, buf2);
if ((s = strchr(s, '\n')) != NULL) {
/* This means that we are at the END of the line, we want out of there,
* but we want s to point to the beginning of the line. AFTER the line
* we want edited. */
2006-12-19 22:56:18 +00:00
s++;
/* Now put the last 'good' half of buffer into storage. */
2006-12-19 22:56:18 +00:00
strcat(buf, s);
}
/* Check for buffer overflow. */
2006-12-19 22:56:18 +00:00
if (strlen(buf) > d->max_str) {
write_to_output(d, "Change causes new length to exceed buffer maximum size, aborted.\r\n");
return;
}
/* Change the size of the REAL buffer to fit the new text. */
2006-12-19 22:56:18 +00:00
RECREATE(*d->str, char, strlen(buf) + 3);
strcpy(*d->str, buf);
write_to_output(d, "Line changed.\r\n");
} else {
write_to_output(d, "Line number must be higher than 0.\r\n");
return;
}
break;
default:
write_to_output(d, "Invalid option.\r\n");
mudlog(BRF, LVL_IMPL, TRUE, "SYSERR: invalid command passed to parse_edit_action");
2006-12-19 22:56:18 +00:00
return;
}
}
/* Re-formats message type formatted char *. (for strings edited with d->str)
* (mostly olc and mail). */
int format_text(char **ptr_string, int mode, struct descriptor_data *d, unsigned int maxlen, int low, int high)
{
int line_chars, cap_next = TRUE, cap_next_next = FALSE, color_chars = 0, i, pass_line = 0;
char *flow, *start = NULL, temp;
char formatted[MAX_STRING_LENGTH] = "";
char str[MAX_STRING_LENGTH];
/* Fix memory overrun. */
if (d->max_str > MAX_STRING_LENGTH) {
log("SYSERR: format_text: max_str is greater than buffer size.");
return 0;
}
/* XXX: Want to make sure the string doesn't grow either... */
if ((flow = *ptr_string) == NULL)
return 0;
strcpy(str, flow);
for (i = 0; i < low - 1; i++) {
start = strtok(str, "\n");
if (!start) {
write_to_output(d, "There aren't that many lines!\r\n");
return 0;
}
strcat(formatted, strcat(start, "\n"));
flow = strstr(flow, "\n");
strcpy(str, ++flow);
}
if (IS_SET(mode, FORMAT_INDENT)) {
strcat(formatted, " ");
line_chars = 3;
} else {
line_chars = 0;
}
while (*flow && i < high) {
while (*flow && strchr("\n\r\f\t\v ", *flow)) {
if (*flow == '\n' && !pass_line)
2006-12-19 22:56:18 +00:00
if (i++ >= high) {
pass_line = 1;
2006-12-19 22:56:18 +00:00
break;
}
flow++;
}
if (*flow) {
start = flow;
while (*flow && !strchr("\n\r\f\v .?!", *flow)) {
if (*flow == '\t') {
if (*(flow + 1) == '\t')
color_chars++;
else
color_chars += 2;
flow++;
}
flow++;
}
if (cap_next_next) {
cap_next_next = FALSE;
cap_next = TRUE;
}
/* This is so that if we stopped on a sentence, we move off the sentence
* delimiter. */
while (strchr(".!?", *flow)) {
cap_next_next = TRUE;
flow++;
}
/* Special case: if we're at the end of the last line, and the last
* character is a delimiter, the flow++ above will have *flow pointing
* to the \r (or \n) character after the delimiter. Thus *flow will be
* non-null, and an extra (blank) line might be added erroneously. We
* fix it by skipping the newline characters in between. - Welcor */
if (strchr("\n\r", *flow)) {
*flow = '\0'; /* terminate 'start' string */
flow++; /* we know this is safe */
if (*flow == '\n' && i++ >= high)
pass_line = 1;
while (*flow && strchr("\n\r", *flow) && !pass_line) {
flow++; /* skip to next non-delimiter */
if (*flow == '\n' && i++ >= high)
pass_line = 1;
}
temp = *flow; /* save this char */
} else {
temp = *flow;
*flow = '\0';
}
if (line_chars + strlen(start) + 1 - color_chars > PAGE_WIDTH) {
strcat(formatted, "\r\n");
line_chars = 0;
color_chars = count_color_chars(start);
}
if (!cap_next) {
if (line_chars > 0) {
strcat(formatted, " ");
line_chars++;
}
} else {
cap_next = FALSE;
CAP(start);
}
line_chars += strlen(start);
strcat(formatted, start);
*flow = temp;
}
if (cap_next_next && *flow) {
if (line_chars + 3 - color_chars > PAGE_WIDTH) {
strcat(formatted, "\r\n");
line_chars = 0;
color_chars = count_color_chars(start);
} else if (*flow == '\"' || *flow == '\'') {
char buf[MAX_STRING_LENGTH];
sprintf(buf, "%c ", *flow);
strcat(formatted, buf);
flow++;
line_chars++;
} else {
strcat(formatted, " ");
line_chars += 2;
}
}
}
if (*flow)
strcat(formatted, "\r\n");
strcat(formatted, flow);
if (!*flow)
strcat(formatted, "\r\n");
if (strlen(formatted) + 1 > maxlen)
formatted[maxlen - 1] = '\0';
RECREATE(*ptr_string, char, MIN(maxlen, strlen(formatted) + 1));
strcpy(*ptr_string, formatted);
return 1;
2006-12-19 22:56:18 +00:00
}
int replace_str(char **string, char *pattern, char *replacement, int rep_all, unsigned int max_size)
{
char *replace_buffer = NULL;
char *flow, *jetsam, temp;
int len, i;
if ((strlen(*string) - strlen(pattern)) + strlen(replacement) > max_size)
return -1;
CREATE(replace_buffer, char, max_size);
i = 0;
jetsam = *string;
flow = *string;
*replace_buffer = '\0';
if (rep_all) {
while ((flow = (char *)strstr(flow, pattern)) != NULL) {
i++;
temp = *flow;
*flow = '\0';
if ((strlen(replace_buffer) + strlen(jetsam) + strlen(replacement)) > max_size) {
i = -1;
break;
}
strcat(replace_buffer, jetsam);
strcat(replace_buffer, replacement);
*flow = temp;
flow += strlen(pattern);
jetsam = flow;
}
strcat(replace_buffer, jetsam);
} else {
if ((flow = (char *)strstr(*string, pattern)) != NULL) {
i++;
flow += strlen(pattern);
len = ((char *)flow - (char *)*string) - strlen(pattern);
strncpy(replace_buffer, *string, len);
strcat(replace_buffer, replacement);
strcat(replace_buffer, flow);
}
}
if (i <= 0)
return 0;
else {
RECREATE(*string, char, strlen(replace_buffer) + 3);
strcpy(*string, replace_buffer);
}
free(replace_buffer);
return i;
}
#endif