Dynamic buffering snippet for page_string and other uses: A word of warning: This is not for the faint hearted. If you are not confident in your C programming skills or at least willing to try to stretch your own coding abilities do not try this. If this is not done right it can easily result in huge memory leaks, Seg faults, or worse. As always, make a full backup of your working MUD source before you make any changes. This will be split up into two main parts, preparation and implementation. Preparation is the basic set up to get the buffering system into place and implementation is the more general instructions of how to use the system in various places where you want dynamic string buffering. If you use this I request two things, give me credit and drop me an email telling me how it works for you. If you have any questions regarding this snippet please don't hesitate to ask me. Regards, Peter PREPARATION: utils.h: In the Memory Utils section add the following... /* Dynamic string buffer macros. */ #define DYN_DEFINE \ char* dynbuf = 0; \ size_t dynbuf_size #define DYN_CREATE \ dynbuf_size = MAX_STRING_LENGTH; \ CREATE(dynbuf, char, dynbuf_size); #define DYN_RESIZE(sbuf) \ if (strlen(dynbuf) + strlen((sbuf)) >= dynbuf_size) { \ dynbuf_size += MAX_STRING_LENGTH; \ RECREATE(dynbuf, char, dynbuf_size); \ } \ strcat(dynbuf, (sbuf)); Next find the following... #if !defined(TRUE) #define TRUE (!FALSE) #endif and change it to this... #if defined(TRUE) #undef TRUE #endif #define TRUE 1 comm.h: find the prototype for page_string and add the following immediately following it... /* values for keep_internal... FALSE Buffer is read only and will not be modifed so it does not need to be copied. TRUE Buffer is re-usable and needs to be copied before use. */ #define DYN_BUFFER 2 /* Buffer is dynamically allocated and does not need to be copied, but does need to be freed. */ modify.c: In the page_string function find the following... if (keep_internal) { d->showstr_head = str_dup(str); paginate_string(d->showstr_head, d); } else paginate_string(str, d); and change it to this... if (keep_internal) { if (keep_internal == DYN_BUFFER) d->showstr_head = str; else d->showstr_head = str_dup(str); paginate_string(d->showstr_head, d); } else paginate_string(str, d); Okay, that should complete the preparation stage (hopefully I didn't leave anything out). IMPLEMENTATION: This is the hard part cause it requires yo to do wome thinking on your own. What I'll do is go over what each of the macros added to utils.h does and give examples on a snippet pulled directly off the Ceramic Mouse site as well as on the do_levels function. These will be in the standard + and - diff notation we all have grown to love and cherish ;) ... DYN_DEFINE: This simply adds the necessary defines to the function to support the dynamic buffering. DYN_CREATE: This will initialize the variables associated with the dynamic buffering and allocate the initial memory for it. DYN_RESIZE(sbuf): This adds (sbuf) to the end of the dynamic variable, allocating more memory for it if necessary. DYN_BUFFER: Use this when calling page_string. It will tell page_string to use this buffer directly instead of copying the string to a new buffer and also to free the buffer when it is finished. Note: This uses a sort of hack to pass off a value of 2 to a function that expects either true or false. Fortunately, this is C and not C++ as were it C++ (and keep_internal was defined as bool) the 2 would be converted to true and there would be no way to tell the difference. free(dynbuf): This will free up the space allocated by DYN_CREATE. Use it ONLY after DYN_CREATE if you want to abort without paging the string. Failure to do this will result in a memory leak while using it in the wrong place will more than likely cause a seg fault. Example 1: Haddixx's File Viewer Snippet: ACMD(do_file) { FILE *req_file; int cur_line = 0, num_lines = 0, req_lines = 0, i, j; int l; char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH]; + DYN_DEFINE; struct file_struct { char *cmd; char level; char *file; } fields[] = { { "none", LVL_IMPL, "Does Nothing" }, { "bug", LVL_IMPL, "../lib/misc/bugs"}, { "typo", LVL_BUILDER, "../lib/misc/typos"}, { "ideas", LVL_IMPL, "../lib/misc/ideas"}, { "xnames", LVL_IMPL, "../lib/misc/xnames"}, { "levels", LVL_MINOR, "../log/levels" }, { "rip", LVL_MINOR, "../log/rip" }, { "players", LVL_MINOR, "../log/newplayers" }, { "rentgone", LVL_MINOR, "../log/rentgone" }, { "godcmds", LVL_IMPL, "../log/godcmds" }, { "syslog", LVL_IMPL, "../syslog" }, { "crash", LVL_IMPL, "../syslog.CRASH" }, { "\n", 0, "\n" } }; skip_spaces(&argument); if (!*argument) { strcpy(buf, "USAGE: file