| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
#include "config.h" |
|---|
| 9 |
#include <stdlib.h> |
|---|
| 10 |
#include <string.h> |
|---|
| 11 |
#include <ctype.h> |
|---|
| 12 |
#include <stdio.h> |
|---|
| 13 |
#include "conf.h" |
|---|
| 14 |
#include "externs.h" |
|---|
| 15 |
#include "command.h" |
|---|
| 16 |
#include "htab.h" |
|---|
| 17 |
#include "help.h" |
|---|
| 18 |
#include "log.h" |
|---|
| 19 |
#include "ansi.h" |
|---|
| 20 |
#include "parse.h" |
|---|
| 21 |
#include "pueblo.h" |
|---|
| 22 |
#include "flags.h" |
|---|
| 23 |
#include "dbdefs.h" |
|---|
| 24 |
#include "mymalloc.h" |
|---|
| 25 |
#include "confmagic.h" |
|---|
| 26 |
|
|---|
| 27 |
HASHTAB help_files; |
|---|
| 28 |
|
|---|
| 29 |
static int help_init = 0; |
|---|
| 30 |
|
|---|
| 31 |
static void do_new_spitfile(dbref player, char *arg1, help_file *help_dat); |
|---|
| 32 |
static const char *string_spitfile(help_file *help_dat, char *arg1); |
|---|
| 33 |
static help_indx *help_find_entry(help_file *help_dat, const char *the_topic); |
|---|
| 34 |
static char **list_matching_entries(const char *pattern, |
|---|
| 35 |
help_file *help_dat, int *len); |
|---|
| 36 |
static void free_entry_list(char **); |
|---|
| 37 |
static const char *normalize_entry(help_file *help_dat, const char *arg1); |
|---|
| 38 |
|
|---|
| 39 |
static void help_build_index(help_file *h, int restricted); |
|---|
| 40 |
|
|---|
| 41 |
|
|---|
| 42 |
typedef struct TLIST { |
|---|
| 43 |
char topic[TOPIC_NAME_LEN + 1]; |
|---|
| 44 |
struct TLIST *next; |
|---|
| 45 |
} tlist; |
|---|
| 46 |
|
|---|
| 47 |
tlist *top = NULL; |
|---|
| 48 |
|
|---|
| 49 |
help_indx *topics = NULL; |
|---|
| 50 |
unsigned num_topics = 0; |
|---|
| 51 |
unsigned top_topics = 0; |
|---|
| 52 |
|
|---|
| 53 |
static void write_topic(long int p); |
|---|
| 54 |
|
|---|
| 55 |
COMMAND(cmd_helpcmd) |
|---|
| 56 |
{ |
|---|
| 57 |
help_file *h; |
|---|
| 58 |
|
|---|
| 59 |
h = hashfind(cmd->name, &help_files); |
|---|
| 60 |
|
|---|
| 61 |
if (!h) { |
|---|
| 62 |
notify(player, T("That command is unavailable.")); |
|---|
| 63 |
return; |
|---|
| 64 |
} |
|---|
| 65 |
|
|---|
| 66 |
if (h->admin && !Hasprivs(player)) { |
|---|
| 67 |
notify(player, T("You don't look like an admin to me.")); |
|---|
| 68 |
return; |
|---|
| 69 |
} |
|---|
| 70 |
|
|---|
| 71 |
if (wildcard(arg_left)) { |
|---|
| 72 |
int len = 0; |
|---|
| 73 |
char **entries; |
|---|
| 74 |
|
|---|
| 75 |
entries = list_matching_entries(arg_left, h, &len); |
|---|
| 76 |
if (len == 0) |
|---|
| 77 |
notify_format(player, T("No entries matching '%s' were found."), |
|---|
| 78 |
arg_left); |
|---|
| 79 |
else if (len == 1) |
|---|
| 80 |
do_new_spitfile(player, *entries, h); |
|---|
| 81 |
else { |
|---|
| 82 |
char buff[BUFFER_LEN]; |
|---|
| 83 |
char *bp; |
|---|
| 84 |
|
|---|
| 85 |
bp = buff; |
|---|
| 86 |
arr2list(entries, len, buff, &bp, ", "); |
|---|
| 87 |
*bp = '\0'; |
|---|
| 88 |
notify_format(player, T("Here are the entries which match '%s':\n%s"), |
|---|
| 89 |
arg_left, buff); |
|---|
| 90 |
} |
|---|
| 91 |
free_entry_list(entries); |
|---|
| 92 |
} else |
|---|
| 93 |
do_new_spitfile(player, arg_left, h); |
|---|
| 94 |
} |
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
void |
|---|
| 100 |
init_help_files(void) |
|---|
| 101 |
{ |
|---|
| 102 |
hashinit(&help_files, 8); |
|---|
| 103 |
help_init = 1; |
|---|
| 104 |
} |
|---|
| 105 |
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 |
|
|---|
| 111 |
|
|---|
| 112 |
|
|---|
| 113 |
|
|---|
| 114 |
void |
|---|
| 115 |
add_help_file(const char *command_name, const char *filename, int admin) |
|---|
| 116 |
{ |
|---|
| 117 |
help_file *h; |
|---|
| 118 |
|
|---|
| 119 |
if (help_init == 0) |
|---|
| 120 |
init_help_files(); |
|---|
| 121 |
|
|---|
| 122 |
if (!command_name || !filename || !*command_name || !*filename) |
|---|
| 123 |
return; |
|---|
| 124 |
|
|---|
| 125 |
|
|---|
| 126 |
h = hashfind(strupper(command_name), &help_files); |
|---|
| 127 |
if (h) { |
|---|
| 128 |
do_rawlog(LT_ERR, T("Duplicate help_command %s ignored."), command_name); |
|---|
| 129 |
return; |
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
h = mush_malloc(sizeof *h, "help_file.entry"); |
|---|
| 133 |
h->command = mush_strdup(strupper(command_name), "help_file.command"); |
|---|
| 134 |
h->file = mush_strdup(filename, "help_file.filename"); |
|---|
| 135 |
h->entries = 0; |
|---|
| 136 |
h->indx = NULL; |
|---|
| 137 |
h->admin = admin; |
|---|
| 138 |
help_build_index(h, h->admin); |
|---|
| 139 |
if (!h->indx) { |
|---|
| 140 |
mush_free(h->command, "help_file.command"); |
|---|
| 141 |
mush_free(h->file, "help_file.filename"); |
|---|
| 142 |
mush_free(h, "help_file.entry"); |
|---|
| 143 |
return; |
|---|
| 144 |
} |
|---|
| 145 |
(void) command_add(h->command, CMD_T_ANY | CMD_T_NOPARSE, NULL, 0, NULL, |
|---|
| 146 |
cmd_helpcmd); |
|---|
| 147 |
hashadd(h->command, h, &help_files); |
|---|
| 148 |
} |
|---|
| 149 |
|
|---|
| 150 |
|
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 |
|
|---|
| 156 |
void |
|---|
| 157 |
help_reindex(dbref player) |
|---|
| 158 |
{ |
|---|
| 159 |
help_file *curr; |
|---|
| 160 |
|
|---|
| 161 |
for (curr = hash_firstentry(&help_files); |
|---|
| 162 |
curr; curr = hash_nextentry(&help_files)) { |
|---|
| 163 |
if (curr->indx) { |
|---|
| 164 |
mush_free(curr->indx, "help_index"); |
|---|
| 165 |
curr->indx = NULL; |
|---|
| 166 |
curr->entries = 0; |
|---|
| 167 |
} |
|---|
| 168 |
help_build_index(curr, curr->admin); |
|---|
| 169 |
} |
|---|
| 170 |
if (player != NOTHING) { |
|---|
| 171 |
notify(player, T("Help files reindexed.")); |
|---|
| 172 |
do_rawlog(LT_WIZ, T("Help files reindexed by %s(#%d)"), Name(player), |
|---|
| 173 |
player); |
|---|
| 174 |
} else |
|---|
| 175 |
do_rawlog(LT_WIZ, T("Help files reindexed.")); |
|---|
| 176 |
} |
|---|
| 177 |
|
|---|
| 178 |
static void |
|---|
| 179 |
do_new_spitfile(dbref player, char *arg1, help_file *help_dat) |
|---|
| 180 |
{ |
|---|
| 181 |
help_indx *entry = NULL; |
|---|
| 182 |
FILE *fp; |
|---|
| 183 |
char *p, line[LINE_SIZE + 1]; |
|---|
| 184 |
char the_topic[LINE_SIZE + 2]; |
|---|
| 185 |
int default_topic = 0; |
|---|
| 186 |
size_t n; |
|---|
| 187 |
|
|---|
| 188 |
if (*arg1 == '\0') { |
|---|
| 189 |
default_topic = 1; |
|---|
| 190 |
arg1 = (char *) help_dat->command; |
|---|
| 191 |
} else if (*arg1 == '&') { |
|---|
| 192 |
notify(player, T("Help topics don't start with '&'.")); |
|---|
| 193 |
return; |
|---|
| 194 |
} |
|---|
| 195 |
if (strlen(arg1) > LINE_SIZE) |
|---|
| 196 |
*(arg1 + LINE_SIZE) = '\0'; |
|---|
| 197 |
|
|---|
| 198 |
if (help_dat->admin) { |
|---|
| 199 |
sprintf(the_topic, "&%s", arg1); |
|---|
| 200 |
} else |
|---|
| 201 |
strcpy(the_topic, arg1); |
|---|
| 202 |
|
|---|
| 203 |
if (!help_dat->indx || help_dat->entries == 0) { |
|---|
| 204 |
notify(player, T("Sorry, that command is temporarily unvailable.")); |
|---|
| 205 |
do_rawlog(LT_ERR, T("No index for %s."), help_dat->command); |
|---|
| 206 |
return; |
|---|
| 207 |
} |
|---|
| 208 |
|
|---|
| 209 |
entry = help_find_entry(help_dat, the_topic); |
|---|
| 210 |
if (!entry && default_topic) |
|---|
| 211 |
entry = help_find_entry(help_dat, (help_dat->admin ? "&help" : "help")); |
|---|
| 212 |
|
|---|
| 213 |
if (!entry) { |
|---|
| 214 |
notify_format(player, T("No entry for '%s'."), arg1); |
|---|
| 215 |
return; |
|---|
| 216 |
} |
|---|
| 217 |
|
|---|
| 218 |
if ((fp = fopen(help_dat->file, FOPEN_READ)) == NULL) { |
|---|
| 219 |
notify(player, T("Sorry, that function is temporarily unavailable.")); |
|---|
| 220 |
do_log(LT_ERR, 0, 0, T("Can't open text file %s for reading"), |
|---|
| 221 |
help_dat->file); |
|---|
| 222 |
return; |
|---|
| 223 |
} |
|---|
| 224 |
if (fseek(fp, entry->pos, 0) < 0L) { |
|---|
| 225 |
notify(player, T("Sorry, that function is temporarily unavailable.")); |
|---|
| 226 |
do_rawlog(LT_ERR, T("Seek error in file %s"), help_dat->file); |
|---|
| 227 |
return; |
|---|
| 228 |
} |
|---|
| 229 |
strcpy(the_topic, strupper(entry->topic + (*entry->topic == '&'))); |
|---|
| 230 |
|
|---|
| 231 |
if (ShowAnsi(player)) { |
|---|
| 232 |
char ansi_topic[LINE_SIZE + 10]; |
|---|
| 233 |
sprintf(ansi_topic, "%s%s%s", ANSI_HILITE, the_topic, ANSI_END); |
|---|
| 234 |
notify(player, ansi_topic); |
|---|
| 235 |
} else |
|---|
| 236 |
notify(player, the_topic); |
|---|
| 237 |
|
|---|
| 238 |
if (SUPPORT_PUEBLO) |
|---|
| 239 |
notify_noenter(player, open_tag("SAMP")); |
|---|
| 240 |
for (n = 0; n < BUFFER_LEN; n++) { |
|---|
| 241 |
if (fgets(line, LINE_SIZE, fp) == NULL) |
|---|
| 242 |
break; |
|---|
| 243 |
if (line[0] == '&') |
|---|
| 244 |
break; |
|---|
| 245 |
if (line[0] == '\n') { |
|---|
| 246 |
notify(player, " "); |
|---|
| 247 |
} else { |
|---|
| 248 |
for (p = line; *p != '\0'; p++) |
|---|
| 249 |
if (*p == '\n') |
|---|
| 250 |
*p = '\0'; |
|---|
| 251 |
notify(player, line); |
|---|
| 252 |
} |
|---|
| 253 |
} |
|---|
| 254 |
if (SUPPORT_PUEBLO) |
|---|
| 255 |
notify(player, close_tag("SAMP")); |
|---|
| 256 |
fclose(fp); |
|---|
| 257 |
if (n >= BUFFER_LEN) |
|---|
| 258 |
notify_format(player, T("%s output truncated."), help_dat->command); |
|---|
| 259 |
} |
|---|
| 260 |
|
|---|
| 261 |
|
|---|
| 262 |
static help_indx * |
|---|
| 263 |
help_find_entry(help_file *help_dat, const char *the_topic) |
|---|
| 264 |
{ |
|---|
| 265 |
help_indx *entry = NULL; |
|---|
| 266 |
|
|---|
| 267 |
if (help_dat->entries < 10) { |
|---|
| 268 |
size_t n; |
|---|
| 269 |
for (n = 0; n < help_dat->entries; n++) { |
|---|
| 270 |
if (string_prefix(help_dat->indx[n].topic, the_topic)) { |
|---|
| 271 |
entry = &help_dat->indx[n]; |
|---|
| 272 |
break; |
|---|
| 273 |
} |
|---|
| 274 |
} |
|---|
| 275 |
} else { |
|---|
| 276 |
int left = 0; |
|---|
| 277 |
int cmp; |
|---|
| 278 |
int right = help_dat->entries - 1; |
|---|
| 279 |
|
|---|
| 280 |
while (1) { |
|---|
| 281 |
int n = (left + right) / 2; |
|---|
| 282 |
|
|---|
| 283 |
if (left > right) |
|---|
| 284 |
break; |
|---|
| 285 |
|
|---|
| 286 |
cmp = strcasecmp(the_topic, help_dat->indx[n].topic); |
|---|
| 287 |
|
|---|
| 288 |
if (cmp == 0) { |
|---|
| 289 |
entry = &help_dat->indx[n]; |
|---|
| 290 |
break; |
|---|
| 291 |
} else if (cmp < 0) { |
|---|
| 292 |
|
|---|
| 293 |
if (string_prefix(help_dat->indx[n].topic, the_topic)) { |
|---|
| 294 |
int m; |
|---|
| 295 |
for (m = n - 1; m >= 0; m--) { |
|---|
| 296 |
if (!string_prefix(help_dat->indx[m].topic, the_topic)) |
|---|
| 297 |
break; |
|---|
| 298 |
} |
|---|
| 299 |
entry = &help_dat->indx[m + 1]; |
|---|
| 300 |
break; |
|---|
| 301 |
} |
|---|
| 302 |
if (left == right) |
|---|
| 303 |
break; |
|---|
| 304 |
right = n - 1; |
|---|
| 305 |
} else { |
|---|
| 306 |
if (left == right) |
|---|
| 307 |
break; |
|---|
| 308 |
left = n + 1; |
|---|
| 309 |
} |
|---|
| 310 |
} |
|---|
| 311 |
} |
|---|
| 312 |
return entry; |
|---|
| 313 |
} |
|---|
| 314 |
|
|---|
| 315 |
static void |
|---|
| 316 |
write_topic(long int p) |
|---|
| 317 |
{ |
|---|
| 318 |
tlist *cur, *nextptr; |
|---|
| 319 |
help_indx *temp; |
|---|
| 320 |
for (cur = top; cur; cur = nextptr) { |
|---|
| 321 |
nextptr = cur->next; |
|---|
| 322 |
if (num_topics >= top_topics) { |
|---|
| 323 |
top_topics += top_topics / 2 + 20; |
|---|
| 324 |
if (topics) |
|---|
| 325 |
topics = (help_indx *) realloc(topics, top_topics * sizeof(help_indx)); |
|---|
| 326 |
else |
|---|
| 327 |
topics = (help_indx *) malloc(top_topics * sizeof(help_indx)); |
|---|
| 328 |
if (!topics) { |
|---|
| 329 |
mush_panic(T("Out of memory")); |
|---|
| 330 |
} |
|---|
| 331 |
} |
|---|
| 332 |
temp = &topics[num_topics++]; |
|---|
| 333 |
temp->pos = p; |
|---|
| 334 |
strcpy(temp->topic, cur->topic); |
|---|
| 335 |
free(cur); |
|---|
| 336 |
} |
|---|
| 337 |
top = NULL; |
|---|
| 338 |
} |
|---|
| 339 |
|
|---|
| 340 |
static int WIN32_CDECL topic_cmp(const void *s1, const void *s2); |
|---|
| 341 |
static int WIN32_CDECL |
|---|
| 342 |
topic_cmp(const void *s1, const void *s2) |
|---|
| 343 |
{ |
|---|
| 344 |
const help_indx *a = s1; |
|---|
| 345 |
const help_indx *b = s2; |
|---|
| 346 |
|
|---|
| 347 |
return strcasecmp(a->topic, b->topic); |
|---|
| 348 |
|
|---|
| 349 |
} |
|---|
| 350 |
|
|---|
| 351 |
static void |
|---|
| 352 |
help_build_index(help_file *h, int restricted) |
|---|
| 353 |
{ |
|---|
| 354 |
long bigpos, pos = 0; |
|---|
| 355 |
bool in_topic; |
|---|
| 356 |
int i, lineno, ntopics; |
|---|
| 357 |
size_t n; |
|---|
| 358 |
char *s, *topic; |
|---|
| 359 |
char the_topic[TOPIC_NAME_LEN + 1]; |
|---|
| 360 |
char line[LINE_SIZE + 1]; |
|---|
| 361 |
FILE *rfp; |
|---|
| 362 |
tlist *cur; |
|---|
| 363 |
|
|---|
| 364 |
|
|---|
| 365 |
if (!h || !h->file) |
|---|
| 366 |
return; |
|---|
| 367 |
if ((rfp = fopen(h->file, FOPEN_READ)) == NULL) { |
|---|
| 368 |
do_rawlog(LT_ERR, T("Can't open %s for reading"), h->file); |
|---|
| 369 |
return; |
|---|
| 370 |
} |
|---|
| 371 |
|
|---|
| 372 |
if (restricted) |
|---|
| 373 |
do_rawlog(LT_WIZ, T("Indexing file %s (admin topics)"), h->file); |
|---|
| 374 |
else |
|---|
| 375 |
do_rawlog(LT_WIZ, T("Indexing file %s"), h->file); |
|---|
| 376 |
topics = NULL; |
|---|
| 377 |
num_topics = 0; |
|---|
| 378 |
top_topics = 0; |
|---|
| 379 |
bigpos = 0L; |
|---|
| 380 |
lineno = 0; |
|---|
| 381 |
ntopics = 0; |
|---|
| 382 |
|
|---|
| 383 |
in_topic = 0; |
|---|
| 384 |
|
|---|
| 385 |
while (fgets(line, LINE_SIZE, rfp) != NULL) { |
|---|
| 386 |
++lineno; |
|---|
| 387 |
if (ntopics == 0) { |
|---|
| 388 |
|
|---|
| 389 |
if (!line[0]) { |
|---|
| 390 |
|
|---|
| 391 |
do_rawlog(LT_ERR, T("Malformed help file %s doesn't start with &"), |
|---|
| 392 |
h->file); |
|---|
| 393 |
fclose(rfp); |
|---|
| 394 |
return; |
|---|
| 395 |
} |
|---|
| 396 |
if (isspace((unsigned char) line[0])) |
|---|
| 397 |
continue; |
|---|
| 398 |
if (line[0] != '&') { |
|---|
| 399 |
do_rawlog(LT_ERR, T("Malformed help file %s doesn't start with &"), |
|---|
| 400 |
h->file); |
|---|
| 401 |
fclose(rfp); |
|---|
| 402 |
return; |
|---|
| 403 |
} |
|---|
| 404 |
} |
|---|
| 405 |
n = strlen(line); |
|---|
| 406 |
if (line[n - 1] != '\n') { |
|---|
| 407 |
do_rawlog(LT_ERR, T("Line %d of %s: line too long"), lineno, h->file); |
|---|
| 408 |
} |
|---|
| 409 |
if (line[0] == '&') { |
|---|
| 410 |
++ntopics; |
|---|
| 411 |
if (!in_topic) { |
|---|
| 412 |
|
|---|
| 413 |
if (ntopics > 1) { |
|---|
| 414 |
write_topic(pos); |
|---|
| 415 |
} |
|---|
| 416 |
in_topic = true; |
|---|
| 417 |
} |
|---|
| 418 |
|
|---|
| 419 |
|
|---|
| 420 |
for (topic = &line[1]; |
|---|
| 421 |
(*topic == ' ' || *topic == '\t') && *topic != '\0'; topic++) ; |
|---|
| 422 |
|
|---|
| 423 |
|
|---|
| 424 |
strcpy(the_topic, ""); |
|---|
| 425 |
for (i = -1, s = topic; *s != '\n' && *s != '\0'; s++) { |
|---|
| 426 |
if (i >= TOPIC_NAME_LEN - 1) |
|---|
| 427 |
break; |
|---|
| 428 |
if (*s != ' ' || the_topic[i] != ' ') |
|---|
| 429 |
the_topic[++i] = *s; |
|---|
| 430 |
} |
|---|
| 431 |
if ((restricted && the_topic[0] == '&') |
|---|
| 432 |
|| (!restricted && the_topic[0] != '&')) { |
|---|
| 433 |
the_topic[++i] = '\0'; |
|---|
| 434 |
cur = (tlist *) malloc(sizeof(tlist)); |
|---|
| 435 |
strcpy(cur->topic, the_topic); |
|---|
| 436 |
cur->next = top; |
|---|
| 437 |
top = cur; |
|---|
| 438 |
} |
|---|
| 439 |
} else { |
|---|
| 440 |
if (in_topic) { |
|---|
| 441 |
pos = bigpos; |
|---|
| 442 |
} |
|---|
| 443 |
in_topic = false; |
|---|
| 444 |
} |
|---|
| 445 |
bigpos = ftell(rfp); |
|---|
| 446 |
} |
|---|
| 447 |
|
|---|
| 448 |
|
|---|
| 449 |
write_topic(pos); |
|---|
| 450 |
qsort(topics, num_topics, sizeof(help_indx), topic_cmp); |
|---|
| 451 |
h->entries = num_topics; |
|---|
| 452 |
h->indx = topics; |
|---|
| 453 |
add_check("help_index"); |
|---|
| 454 |
fclose(rfp); |
|---|
| 455 |
do_rawlog(LT_WIZ, T("%d topics indexed."), num_topics); |
|---|
| 456 |
return; |
|---|
| 457 |
} |
|---|
| 458 |
|
|---|
| 459 |
|
|---|
| 460 |
FUNCTION(fun_textfile) |
|---|
| 461 |
{ |
|---|
| 462 |
help_file *h; |
|---|
| 463 |
|
|---|
| 464 |
h = hashfind(strupper(args[0]), &help_files); |
|---|
| 465 |
if (!h) { |
|---|
| 466 |
safe_str(T("#-1 NO SUCH FILE"), buff, bp); |
|---|
| 467 |
return; |
|---|
| 468 |
} |
|---|
| 469 |
if (h->admin && !Hasprivs(executor)) { |
|---|
| 470 |
safe_str(T(e_perm), buff, bp); |
|---|
| 471 |
return; |
|---|
| 472 |
} |
|---|
| 473 |
|
|---|
| 474 |
if (wildcard(args[1])) { |
|---|
| 475 |
char **entries; |
|---|
| 476 |
int len = 0; |
|---|
| 477 |
entries = list_matching_entries(args[1], h, &len); |
|---|
| 478 |
if (len == 0) |
|---|
| 479 |
safe_str(T("No matching help topics."), buff, bp); |
|---|
| 480 |
else |
|---|
| 481 |
arr2list(entries, len, buff, bp, ", "); |
|---|
| 482 |
free_entry_list(entries); |
|---|
| 483 |
} else |
|---|
| 484 |
safe_str(string_spitfile(h, args[1]), buff, bp); |
|---|
| 485 |
} |
|---|
| 486 |
|
|---|
| 487 |
|
|---|
| 488 |
FUNCTION(fun_textentries) |
|---|
| 489 |
{ |
|---|
| 490 |
help_file *h; |
|---|
| 491 |
char **entries; |
|---|
| 492 |
int len = 0; |
|---|
| 493 |
const char *sep = " "; |
|---|
| 494 |
|
|---|
| 495 |
h = hashfind(strupper(args[0]), &help_files); |
|---|
| 496 |
if (!h) { |
|---|
| 497 |
safe_str(T("#-1 NO SUCH FILE"), buff, bp); |
|---|
| 498 |
return; |
|---|
| 499 |
} |
|---|
| 500 |
if (h->admin && !Hasprivs(executor)) { |
|---|
| 501 |
safe_str |
|---|