Welcome to the Builder Academy

Question do_commands

More
24 Jan 2018 16:38 - 24 Jan 2018 16:48 #7437 by Fizban
do_commands was created by Fizban
do_commands is showing corrupted info when the wizhelp subcommand is used with a mortal as its argument.

It doesn't appear to be an issue with do_commands itself, it seems to be an issue with the string being passed to column_list already having info in it when it is being substantiated. When you use social or commands, the pre-existing information in the string is being overwritten and thus hidden from view, but because mortals don't have any access to immortal commands, nothing is being added to the string when wizhelp is called as the subcommand so it's showing whatever content it had still stored in it.

On a brand new character wizhelp <name> shows nothing.

If the mortal uses the socials or commands, commands, then wizhelp <mortal> then shows you the info they most recently saw. If however the mortals most recent commands were something entirely different then it often shows corrupted nonsensical info, such as the name of mobs from zones the mortal has never been to, or random characters.
Code:
ACMD(do_commands) { int no, i, cmd_num; int wizhelp = 0, socials = 0; struct char_data *vict; char arg[MAX_INPUT_LENGTH]; char buf[MAX_STRING_LENGTH]; const char *commands[1000]; int overflow = sizeof(commands) / sizeof(commands[0]); if (!ch->desc) return; one_argument(argument, arg); if (*arg) { if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)) || IS_NPC(vict)) { send_to_char(ch, "Who is that?\r\n"); return; } } else vict = ch; if (subcmd == SCMD_SOCIALS) socials = 1; else if (subcmd == SCMD_WIZHELP) wizhelp = 1; sprintf(buf, "The following %s%s are available to %s:\r\n", wizhelp ? "privileged " : "", socials ? "socials" : "commands", vict == ch ? "you" : GET_NAME(vict)); /* cmd_num starts at 1, not 0, to remove 'RESERVED' */ for (no = 0, cmd_num = 1; complete_cmd_info[cmd_sort_info[cmd_num]].command[0] != '\n'; ++cmd_num) { i = cmd_sort_info[cmd_num]; if (complete_cmd_info[i].minimum_level < 0 || GET_LEVEL(vict) < complete_cmd_info[i].minimum_level) continue; if ((complete_cmd_info[i].minimum_level >= LVL_IMMORT) != wizhelp) continue; if (!wizhelp && socials != (complete_cmd_info[i].command_pointer == do_action)) continue; if (wizhelp && complete_cmd_info[i].command_pointer == do_action) continue; if (--overflow < 0) continue; /* matching command: copy to commands list */ commands[no++] = complete_cmd_info[i].command; } /* display commands list in a nice columnized format */ column_list(ch, 0, commands, no, FALSE); }

The only issue I see with do_commands itself is there's a completely useless buf char created, that has info put inside of it, but is never actually sent anywhere. I'd just remove the buf and send the string via send_to_char, but that part really isn't important as it's not related to the corrupted info winding up inside of commands.
Last edit: 24 Jan 2018 16:48 by Fizban.

Please Log in or Create an account to join the conversation.

More
24 Jan 2018 17:25 #7438 by Fizban
Replied by Fizban on topic do_commands
Code:
void column_list(struct char_data *ch, int num_cols, const char **list, int list_length, bool show_nums) { size_t max_len = 0, len = 0, temp_len; int num_per_col, col_width, r, c, i, offset = 0; char buf[MAX_STRING_LENGTH]; /* Work out the longest list item */ for (i=0; i<list_length; i++) if (max_len < strlen(list[i])) max_len = strlen(list[i]); /* auto columns case */ if (num_cols == 0) { num_cols = (IS_NPC(ch) ? 80 : GET_SCREEN_WIDTH(ch)) / (max_len + (show_nums ? 5 : 1)); } /* Ensure that the number of columns is in the range 1-10 */ num_cols = MIN(MAX(num_cols,1), 10); /* Work out the longest list item */ for (i=0; i<list_length; i++) if (max_len < strlen(list[i])) max_len = strlen(list[i]); /* Calculate the width of each column */ if (IS_NPC(ch)) col_width = 80 / num_cols; else col_width = (GET_SCREEN_WIDTH(ch)) / num_cols; if (show_nums) col_width-=4; if (col_width < 0 || (size_t)col_width < max_len) log("Warning: columns too narrow for correct output to %s in simple_column_list (utils.c)", GET_NAME(ch)); /* Calculate how many list items there should be per column */ num_per_col = (list_length / num_cols) + ((list_length % num_cols) ? 1 : 0); /* Fill 'buf' with the columnised list */ for (r=0; r<num_per_col; r++) { for (c=0; c<num_cols; c++) { offset = (c*num_per_col)+r; if (offset < list_length) { if (show_nums) temp_len = snprintf(buf+len, sizeof(buf) - len, "%2d) %-*s", offset+1, col_width, list[(offset)]); else temp_len = snprintf(buf+len, sizeof(buf) - len, "%-*s", col_width, list[(offset)]); len += temp_len; } } temp_len = snprintf(buf+len, sizeof(buf) - len, "\r\n"); len += temp_len; } if (len >= sizeof(buf)) snprintf((buf + MAX_STRING_LENGTH) - 22, 22, "\r\n*** OVERFLOW ***\r\n"); /* Send the list to the player */ page_string(ch->desc, buf, TRUE); }

Here's sample output:

Please Log in or Create an account to join the conversation.

More
24 Jan 2018 22:10 #7439 by thomas
Replied by thomas on topic do_commands
Does adding this work?
Code:
char buf[MAX_STRING_LENGTH]; + *buf='\0'; /* Work out the longest list item */

Please Log in or Create an account to join the conversation.

More
24 Jan 2018 22:54 #7440 by Fizban
Replied by Fizban on topic do_commands
That does fix the output, but isn't that just fixing the symptom rather than the actual cause?

Please Log in or Create an account to join the conversation.

More
24 Jan 2018 22:59 #7441 by WhiskyTest
Replied by WhiskyTest on topic do_commands
That fixes the problem for me

Please Log in or Create an account to join the conversation.

More
24 Jan 2018 23:53 #7442 by thomas
Replied by thomas on topic do_commands

Fizban wrote: That does fix the output, but isn't that just fixing the symptom rather than the actual cause?

No. The cause is that buf is allocated on calling the function. But while the memory is made ready to use on the stack, it isn't cleared. So, if you don't write anything to it, you get what's in it.

The correct solution is to add a NULL as the first byte before starting to treat it like a (null-terminated) string. Which this does.
The following user(s) said Thank You: WhiskyTest

Please Log in or Create an account to join the conversation.

Time to create page: 0.204 seconds