/************************************************************************ Realms of Aurealis James Rhone aka Vall of RoA help.c See OLHC description below. ******** 100% completely original code ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** 100% completely original code ******** All rights reserved henceforth. Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. RoA is based on both Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well as the RoA license. *** Read, Learn, Understand, Improve *** *************************************************************************/ /* Online Help Creation (OLHC) The following code makes online editting of help files possible using the same menu and selection format that the rest of RoAOLC uses. Builders can add help topics on the fly as well as the corresponding help file itself and make it available for immediate use by anyone connected to the MUD. NOTE: This is not quite as elegant as I would like it, but I rushed to get it done for a class :P */ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "utils.h" #include "comm.h" #include "handler.h" #include "acmd.h" #include "db.h" #include "mudlimits.h" #include "interpreter.h" #include "roaolc.h" #include "global.h" #include "exshell.h" // external vars extern struct roa_help_data roa_help[]; extern struct roa_help_data roa_wizhelp[]; // global vars int helpcount = 0; // internal functions void helpedit_top_menu(chdata *ch, char *input_str); void helpedit_confirm_quit(chdata *ch, char *input_str); void helpedit_confirm_save(chdata *ch, char *input_str); void wizhelpedit_top_menu(chdata *ch, char *input_str); void wizhelpedit_confirm_quit(chdata *ch, char *input_str); void wizhelpedit_confirm_save(chdata *ch, char *input_str); /* do_help_conversion takes standard circle2.2 help_table and converts it into a collection of seperate text files and places them in the lib/help directory, you must have a lib/help dir :) NOTE these conversion procedures . . . while a bit sloppy, are intended to only be used _once_ to convert stock help files... */ ACMD(do_help_conversion) { FILE *fp; char fname[300]; char ht[85000]; /* help file no bigger than 85k!! */ char *tmp; int i; if (IS_NPC(ch)) return; *buf = *buf1 = '\0'; sprintf(fname, "text/help_table"); huge_file_to_string(fname, ht); send_to_char("Original help_table loaded into memory.\n\r",ch); tmp = ht; while(*tmp) { /* read first line, to lower it, put in underscores */ for (i = 0 ; *tmp != '\n'; tmp++, i++) { if (isspace(*tmp)) *tmp = '_'; *tmp = LOWER(*tmp); buf[i] = *tmp; } buf[i] = '\0'; /* ok open this file to write to */ sprintf(fname, "help/%s", buf); if (!(fp = fopen(fname, "wt"))) { send_to_char("Error in help_conversion, db.c.\n\r",ch); return; } /* send headers to character and to the index buf1 */ send_to_char(buf, ch); send_to_char("\n\r",ch); strcat(buf1, buf); strcat(buf1, "\n"); /* now upcase the header */ for (i=0; buf[i]; i++) buf[i] = UPPER(buf[i]); /* write title to file in upper case */ fprintf(fp, "%s\n",buf); tmp++; /* bump tmp to past eol */ for (i = 0; *tmp != '#'; tmp++, i++) buf[i] = *tmp; buf[i] = '\0'; fprintf(fp, "%s\n", buf); fclose(fp); if (*(tmp+1) == '~') /* end of ht buffer */ break; for ( ; *tmp != '\n'; tmp++) ; tmp ++; } send_to_char("Help files converted.\n\r",ch); if (!(fp = fopen("help/HELP_INDEX", "wt"))) { send_to_char("Error opening HELP_INDEX.\n\r",ch); return; } fprintf(fp, "%s\n",buf1); fclose(fp); send_to_char("HELP_INDEX created.\n\r",ch); return; } /* same thing for wizhelp */ /* NOTE these conversion procedures . . . while a bit sloppy, are intended to only be used once to convert wizhelp files... */ ACMD(do_wizhelp_conversion) { FILE *fp; char fname[300]; char ht[85000]; /* help file no bigger than 85k!! */ char *tmp; int i; if (IS_NPC(ch)) return; /* NOTE !! change for the name of yer wizhelp.doc or whatever */ sprintf(fname, "text/wiz_table"); huge_file_to_string(fname, ht); send_to_char("Original wizhelp_table loaded into memory.\n\r",ch); *buf = *buf1 = '\0'; tmp = ht; while(*tmp) { /* read first line, to lower it, put in underscores */ for (i = 0 ; *tmp != '\n'; tmp++, i++) { if (isspace(*tmp)) *tmp = '_'; *tmp = LOWER(*tmp); buf[i] = *tmp; } buf[i] = '\0'; /* ok open this file to write to */ sprintf(fname, "wizhelp/%s", buf); if (!(fp = fopen(fname, "wt"))) { send_to_char("Error in wizhelp_conversion, db.c.\n\r",ch); log(fname); return; } /* send headers to character and to the index buf1 */ send_to_char(buf, ch); send_to_char("\n\r",ch); strcat(buf1, buf); strcat(buf1, "\n"); for (i=0; buf[i]; i++) buf[i] = UPPER(buf[i]); /* write title to file in upper case bold */ fprintf(fp, "%s\n",buf); tmp++; /* bump tmp to past eol */ for (i = 0; *tmp != '#'; tmp++, i++) buf[i] = *tmp; buf[i] = '\0'; fprintf(fp, "%s\n", buf); fclose(fp); if (*(tmp+1) == '~') /* end of ht buffer */ break; for ( ; *tmp != '\n'; tmp++) ; tmp ++; } send_to_char("WizHelp files converted.\n\r",ch); if (!(fp = fopen("wizhelp/WIZHELP_INDEX", "wt"))) { send_to_char("Error opening WIZHELP_INDEX.\n\r",ch); return; } fprintf(fp, "%s\n",buf1); fclose(fp); send_to_char("WIZHELP_INDEX created.\n\r",ch); return; } // replaces a string's spaces with underscores void add_underscores(char *str) { char *tmp; for (tmp = str; *tmp; tmp++) if (*tmp == ' ') *tmp = '_'; } // replaces a string's underscores with spaces void wax_underscores(char *str) { char *tmp; for (tmp = str; *tmp; tmp++) if (*tmp == '_') *tmp = ' '; } // called at bootup and after a help file is editted or created void read_sort_roa_help(void) { FILE *fp; int i; // since unix sorts dir listing anyways, call it and send to a file sprintf(buf, "ls help > ROA_HELP_INDEX"); roa_system(buf); if (!(fp = fopen("ROA_HELP_INDEX", "r"))) { sprintf(buf, "SYSERR: Error opening ROA_HELP_INDEX."); mudlog(buf, BRF, LEV_IMM, FALSE); return; } // now read it in line by line and stuff each line into the roa_help array // add range check... 3/23/98 -jtrhone i = 0; while (!feof(fp) && i < MAX_HELPFILES) { fscanf(fp, "%s\n", buf); wax_underscores(buf); strcpy(roa_help[i].help, buf); i++; } fclose(fp); helpcount = i; // blank out remaining help array entries for ( ; i < MAX_HELPFILES; i++) strcpy(roa_help[i].help, ""); } // returns filename if argument match found, else NULL BOOL find_roa_help(char *commm) { int i; char *comm = commm; skip_spaces(&comm); for (i = 0; *roa_help[i].help && (i < MAX_HELPFILES); i++) if (isname(comm, roa_help[i].help)) { strcpy(comm, roa_help[i].help); add_underscores(comm); return TRUE; } return FALSE; } // loads index, appends new title, writes it... then writes the actual helpfile void add_help_entry(char *title, char *hlp) { FILE *fp; char fname[100]; if (!*title || !*hlp) { log("SYSERR: Missing title or hlp to add_help_entry."); return; } // convert title to underscores for filename add_underscores(title); killr(hlp); sprintf(fname, "help/%s",title); if (!(fp = fopen(fname, "w"))) { log("SYSERR: Error opening help file for writing."); return; } fprintf(fp, "%s", hlp); fclose(fp); // ok new help entry added to the index, now sort it read_sort_roa_help(); } /* function to confirm if someone wants to delete a helpfile */ void helpedit_confirm_delete(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Delete help file (YES/no)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (PSTR1(ch)) /* command to execute is stored here */ { if (!p || strncasecmp("no", p, strlen(p)) != 0) { /* execute remove command, and update help index */ roa_system(PSTR1(ch)); read_sort_roa_help(); send_to_char("Help file removed. Index updated.\n\r",ch); } else send_to_char("Help file not deleted.\n\r",ch); } else send_to_char("Help file not deleted, invalid filename.\n\r",ch); /* now wipe that command that ch had stored on it */ if (PSTR1(ch)) { sprintf(buf, "SYSUPD: %s freeing PSTR: %s", GET_NAME(ch), PSTR1(ch)); mudlog(buf, BUG, LEV_IMM, TRUE); } FREENULL(PSTR1(ch)); MENU_PROMPT(ch) = NULL; MENU_HANDLER(ch) = NULL; MENU_DEPTH(ch) = 0; } ACMD(do_remove_help_entry) { char *argu = argument; /* only players should call this command */ if (IS_NPC(ch)) return; if (!*argu) { send_to_char("Usage: helpdelete <topic/title>.\n\r",ch); return; } skip_spaces(&argu); if (!find_roa_help(argu)) { send_to_char("Help entry not found.\n\r",ch); return; } sprintf(buf, "rm help/%s", argu); PSTR1(ch) = str_dup(buf); /* save command to process on character */ MENU_HANDLER(ch) = helpedit_confirm_delete; MENU_DEPTH(ch) = 0; (*MENU_HANDLER(ch))(ch, NULL); } /* note, for wizhelp and help the same type of functionality is used, although its executed on a totally seperate help index and seperate help files */ /* updates and sorts the ROA_WIZHELP_INDEX in lib using unix ls */ /* called at bootup and after a help file is editted or created */ void read_sort_roa_wizhelp(void) { FILE *fp; int i; sprintf(buf, "ls wizhelp > ROA_WIZHELP_INDEX"); roa_system(buf); if (!(fp = fopen("ROA_WIZHELP_INDEX", "r"))) { sprintf(buf, "SYSERR: Error opening ROA_WIZHELP_INDEX."); mudlog(buf, BRF, LEV_IMM, FALSE); return; } // add range check... 3/23/98 -jtrhone i = 0; while (!feof(fp) && i < MAX_WIZHELPFILES) { fscanf(fp, "%s\n", buf); /* we dont want underscores in the index itself only in filename */ wax_underscores(buf); strcpy(roa_wizhelp[i].help, buf); i++; } fclose(fp); /* blank out remaining helps */ for ( ; i < MAX_WIZHELPFILES; i++) strcpy(roa_wizhelp[i].help, ""); /* voila, hack way of updating and sorting help index */ } // returns filename if argument match found else NULL BOOL find_roa_wizhelp(char *commm) { int i; char *comm = commm; skip_spaces(&comm); for (i = 0; *roa_wizhelp[i].help && (i < MAX_WIZHELPFILES); i++) if (isname(comm, roa_wizhelp[i].help)) { strcpy(comm, roa_wizhelp[i].help); add_underscores(comm); return TRUE; } return FALSE; } /* loads index, appends new title, writes it... then writes the actual helpfile */ void add_wizhelp_entry(char *title, char *hlp) { FILE *fp; char fname[100]; if (!*title || !*hlp) { log("SYSERR: Missing title or hlp to add_wizhelp_entry."); return; } /* convert title to underscores for filename */ add_underscores(title); /* write the helpfile itself to help dir */ /* first, get rid of those annoying ^M s (which are \r)*/ killr(hlp); sprintf(fname, "wizhelp/%s",title); if (!(fp = fopen(fname, "wt"))) { log("SYSERR: Error opening wizhelp file for writing."); return; } fprintf(fp, "%s", hlp); fclose(fp); read_sort_roa_wizhelp(); } void helpedit_confirm_wizdelete(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Delete wizhelp file (YES/no)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (PSTR1(ch)) /* name of help file was stored here */ { if (!p || strncasecmp("no", p, strlen(p)) != 0) { roa_system(PSTR1(ch)); read_sort_roa_wizhelp(); send_to_char("WizHelp file removed. Index updated.\n\r",ch); } else send_to_char("WizHelp file not deleted.\n\r",ch); } else send_to_char("WizHelp file not deleted, invalid filename.\n\r",ch); if (PSTR1(ch)) { sprintf(buf, "SYSUPD: %s freeing PSTR: %s", GET_NAME(ch), PSTR1(ch)); mudlog(buf, BUG, LEV_IMM, TRUE); } FREENULL(PSTR1(ch)); MENU_PROMPT(ch) = NULL; MENU_HANDLER(ch) = NULL; MENU_DEPTH(ch) = 0; } ACMD(do_remove_wizhelp_entry) { char *argu = argument; if (IS_NPC(ch)) return; if (!*argu) { send_to_char("Usage: wizhelpdelete <topic/title>.\n\r",ch); return; } skip_spaces(&argu); if (!find_roa_wizhelp(argu)) { send_to_char("WizHelp entry not found.\n\r",ch); return; } sprintf(buf, "rm wizhelp/%s", argu); PSTR1(ch) = str_dup(buf); /* save command to process on character */ MENU_HANDLER(ch) = helpedit_confirm_wizdelete; MENU_DEPTH(ch) = 0; (*MENU_HANDLER(ch))(ch, NULL); } /* following is the NEW RoA help interface, yeah more file access... and im sure there are other pitfalls to this system, but imho it beats the heck out of leavin a file pointer open and having every scrap of help info in one file... */ /* this is the actual player interface when they type help <subject> */ ACMD(do_help) { char buf[20000]; char *argu = argument; char fname[100]; int i, n; skip_spaces(&argu); /* if no argument, give them the index of all available help topics */ if (!*argu) { /* do a help index here */ sprintf(buf, "%%6%s %%BHelp Topics%%0:\n\r", longmudname); for (i=0, n=1; *roa_help[i].help; i++) { sprintf(buf2, " %-16.16s %%B|%%0", roa_help[i].help); strcat(buf, buf2); if (!(n % 4)) /* 4 topics per line */ strcat(buf, "\n\r"); n++; } strcat(buf, "\n\r"); page_string(ch->desc, buf, 1); return; } /* ok we have an argument, lets locate the matching helpfile */ /* note, find_roa_help auto converts argument to filename if found */ /* save argument in case nothing is found */ strcpy(arg, argu); if (!find_roa_help(argu)) { sprintf(buf, "Sorry, nothing could be found on %%B%s%%0.\n\r",arg); send_to_char(buf, ch); return; } sprintf(fname, "help/%s", argu); *buf = '\0'; /* ok we found an index entry, now load file into buf */ if (file_to_string(fname, buf) < 0) { send_to_char("Help file not found.\n\r",ch); return; } else /* all set, send the file to the character, paged */ page_string(ch->desc, buf, 1); } /* same process as do_help, only wizhelp files are check here */ ACMD(do_wizhelp) { char buf[20000]; char *argu = argument; char fname[100]; int i, n; skip_spaces(&argu); if (!*argu) { /* do a help index here */ sprintf(buf, "%%6%s %%BWizHelp Topics%%0:\n\r", longmudname); for (i=0, n=1; *roa_wizhelp[i].help; i++) { sprintf(buf2, " %-16.16s %%B|%%0", roa_wizhelp[i].help); strcat(buf, buf2); if (!(n % 4)) strcat(buf, "\n\r"); n++; } strcat(buf, "\n\r"); page_string(ch->desc, buf, 1); return; } /* note, find_roa_help auto converts argument to filename if found */ strcpy(arg, argu); if (!find_roa_wizhelp(argu)) { sprintf(buf, "Sorry, nothing could be found on %%B%s%%0.\n\r",arg); send_to_char(buf, ch); return; } sprintf(fname, "wizhelp/%s", argu); *buf = '\0'; if (file_to_string(fname, buf) < 0) { send_to_char("WizHelp file not found.\n\r",ch); return; } else page_string(ch->desc, buf, 1); } /* actual OLHC part of this thing... */ /* helpedit --- ONLINE edittable HELP FILES!! ra ra sis boom ba... follows the same ole OLC format and we call er OLHC... original eh? RoA -jtrhone */ /* these are the actual menuized functions for editting help files */ /* confirm that someone wants to quit editting a help file */ void helpedit_confirm_quit(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Quit editting help file (yes/NO)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p && strncasecmp("yes", p, strlen(p)) == 0) { MENU_HANDLER(ch) = helpedit_confirm_save; (*MENU_HANDLER(ch))(ch, NULL); } else { MENU_HANDLER(ch) = helpedit_top_menu; (*MENU_HANDLER(ch))(ch, NULL); } } /* confirms the save of a editted help file */ void helpedit_confirm_save(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Save editted help file (YES/no)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (PSTR1(ch) && PSTR2(ch)) { if (!p || strncasecmp("no", p, strlen(p)) != 0) { if (*PSTR1(ch) && *PSTR2(ch)) { add_help_entry(PSTR1(ch), PSTR2(ch)); sprintf(buf, "IMMUPD: %s helpeditted file [%s].", GET_NAME(ch), PSTR1(ch)); mudlog(buf, BRF, GET_LEVEL(ch), TRUE); } } } else send_to_char("Help file not saved, invalid entries.\n\r",ch); FREENULL(PSTR1(ch)); FREENULL(PSTR2(ch)); MENU_PROMPT(ch) = NULL; MENU_HANDLER(ch) = NULL; MENU_DEPTH(ch) = 0; REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING); } /* heh, for now, only have the string of the help file to edit */ /* this is the upper level menu of help editting */ void helpedit_top_menu(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; int field; /* if nothing entered yet, just show them a little menu */ if (!input_str) { sprintf(buf, "1.) %%6Help Topic%%0: %s\n\r",PSTR1(ch)); S2C(); sprintf(buf, "2.) %%6Help File%%0 :\n\r%s", PSTR2(ch)); S2C(); send_to_char("\n\r", ch); MENU_PROMPT(ch) = "Enter field number to change or 0 to end: "; return; } /* process any input they have entered */ strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) field = atoi(p); else field = 0; switch (field) { case 0: /* 0 , or the <return> key by itself means back out of menu */ MENU_HANDLER(ch) = helpedit_confirm_quit; (*MENU_HANDLER(ch))(ch, NULL); break; case 1: do_string_arg(ch, "Enter help topic:\n\r", &PSTR1(ch), ""); break; case 2: do_max_string_arg(ch, "Enter help file contents (@):\n\r", &PSTR2(ch)); break; default: send_to_char("That field cannot be changed.\n\r", ch); break; } } /* tihs is the interface which sends char into the help editting menus */ ACMD(do_help_edit) { char *argu = argument; BOOL exists = TRUE; if (IS_NPC(ch)) return; skip_spaces(&argu); if (!*argu) { send_to_char("usage: helpedit < topic(s) > \n\r", ch); return; } if (find_roa_help(argu)) send_to_char("%BWarning%0: Help topic exists.\n\r",ch); else exists = FALSE; SET_BIT(PLR_FLAGS(ch), PLR_BUILDING); /* use the char pointers on character to store the strings */ /* allocate memory for em */ /* note, these gotta be attached to the character so we can ref them without sending them as args */ /* use any char pointer that char_data points to etc etc */ /* is freed in helpedit_confirm_save */ CREATE(PSTR1(ch), char, MAX_POOFIN_LENGTH); CREATE(PSTR2(ch), char, MAX_STRING_LENGTH); strcpy(PSTR1(ch), argu); if (exists) { sprintf(buf, "help/%s",argu); if (file_to_string(buf, PSTR2(ch)) < 0) strcpy(PSTR2(ch), "Help file too large.\n\r"); } MENU_HANDLER(ch) = helpedit_top_menu; MENU_DEPTH(ch) = 0; (*MENU_HANDLER(ch))(ch, NULL); } /* now same olhc for wizhelp */ void wizhelpedit_confirm_quit(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Quit editting wizhelp file (yes/NO)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p && strncasecmp("yes", p, strlen(p)) == 0) { MENU_HANDLER(ch) = wizhelpedit_confirm_save; (*MENU_HANDLER(ch))(ch, NULL); } else { MENU_HANDLER(ch) = wizhelpedit_top_menu; (*MENU_HANDLER(ch))(ch, NULL); } } void wizhelpedit_confirm_save(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Save editted wizhelp file (YES/no)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (PSTR1(ch) && PSTR2(ch)) { if (!p || strncasecmp("no", p, strlen(p)) != 0) { if (*PSTR1(ch) && *PSTR2(ch)) { add_wizhelp_entry(PSTR1(ch), PSTR2(ch)); sprintf(buf, "IMMUPD: %s editted wizhelp [%s].", GET_NAME(ch), PSTR1(ch)); mudlog(buf, BRF, GET_LEVEL(ch), TRUE); } } } else send_to_char("WizHelp file not saved, invalid entries.\n\r",ch); if (PSTR1(ch)) { sprintf(buf, "SYSUPD: %s freeing PSTR: %s", GET_NAME(ch), PSTR1(ch)); mudlog(buf, BUG, LEV_IMM, TRUE); } FREENULL(PSTR1(ch)); FREENULL(PSTR2(ch)); MENU_PROMPT(ch) = NULL; MENU_HANDLER(ch) = NULL; MENU_DEPTH(ch) = 0; REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING); } /* heh, for now, only have the string of the help file to edit */ void wizhelpedit_top_menu(chdata *ch, char *input_str) { char buf[MAX_STRING_LENGTH]; char *p; int field; if (!input_str) { sprintf(buf, "1.) %%6WizHelp Topic%%0: %s\n\r",PSTR1(ch)); S2C(); sprintf(buf, "2.) %%6WizHelp File%%0 :\n\r%s", PSTR2(ch)); S2C(); send_to_char("\n\r", ch); MENU_PROMPT(ch) = "Enter field number to change or 0 to end: "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) field = atoi(p); else field = 0; switch (field) { case 0: MENU_HANDLER(ch) = wizhelpedit_confirm_quit; (*MENU_HANDLER(ch))(ch, NULL); break; case 1: do_string_arg(ch, "Enter wizhelp topic:\n\r", &PSTR1(ch), ""); break; case 2: do_max_string_arg(ch, "Enter wizhelp file contents (@):\n\r", &PSTR2(ch)); break; default: send_to_char("That field cannot be changed.\n\r", ch); break; } } ACMD(do_wizhelp_edit) { char *argu = argument; BOOL exists = TRUE; if (IS_NPC(ch)) return; skip_spaces(&argu); if (!*argu) { send_to_char("usage: wizhelpedit < topic(s) > \n\r", ch); return; } if ((exists = find_roa_wizhelp(argu))) send_to_char("%BWarning%0: WizHelp topic exists.\n\r",ch); SET_BIT(PLR_FLAGS(ch), PLR_BUILDING); /* is freed in wizhelpedit_confirm_save */ CREATE(PSTR1(ch), char, MAX_POOFIN_LENGTH); CREATE(PSTR2(ch), char, MAX_STRING_LENGTH); strcpy(PSTR1(ch), argu); if (exists) { sprintf(buf, "wizhelp/%s",argu); if (file_to_string(buf, PSTR2(ch)) < 0) strcpy(PSTR2(ch), "Help file too large.\n\r"); } MENU_HANDLER(ch) = wizhelpedit_top_menu; MENU_DEPTH(ch) = 0; (*MENU_HANDLER(ch))(ch, NULL); }