Crossfire Client, Trunk  R19707
p_cmd.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
19 #ifndef CPROTO
20 /* use declarations from p_cmd.h instead of doing make proto on this file */
21 
22 #include <client.h>
23 #include <external.h>
24 #include <script.h>
25 #include <p_cmd.h>
26 
32 /* TODO This should really be under /help commands or something... */
33 
34 /* This dynamically generates a list from the ConsoleCommand list. */
35 #undef CLIENTHELP_LONG_LIST
36 
37 /*
38 long-list:
39 category
40 name - description
41 name - description
42 ...
43 
44 not long list:
45 category
46 name name name ...
47 */
48 
49 #undef HELP_USE_COLOR
50 #ifdef HELP_USE_COLOR
51 #error Oops, need to put them back.
52 #else
53 #define H1(a) draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE, a)
54 #define H2(a) draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE, a)
55 #define LINE(a) draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE, a)
56 #endif
57 
58 #define assumed_wrap get_info_width()
59 
60 /* TODO Help topics other than commands? Refer to other documents? */
61 
65 static void do_clienthelp_list(void)
66 {
67  ConsoleCommand ** commands_array;
68  ConsoleCommand * commands_copy;
69  int i;
70  CommCat current_cat = COMM_CAT_MISC;
71 #ifndef CLIENTHELP_LONG_LIST
72  char line_buf[MAX_BUF];
73  size_t line_len = 0;
74 
75  line_buf[0] = '\0';
76 #endif
77 
78  commands_array = get_cat_sorted_commands();
79 
80  /* Now we have a nice sorted list. */
81 
82  H1(" === Client Side Commands === ");
83 
84  for (i = 0; i < get_num_commands(); i++) {
85  commands_copy = commands_array[i];
86 
87  /* Should be LOG_SPAM but I'm too lazy to tweak it. */
88  /* LOG(LOG_INFO, "p_cmd::do_clienthelp_list", "%s Command %s", get_category_name(commands_copy->cat), commands_copy->name); */
89 
90  if (commands_copy->cat != current_cat) {
91  char buf[MAX_BUF];
92 
93 #ifndef CLIENTHELP_LONG_LIST
94  if (line_len > 0) {
95  LINE(line_buf);
96  line_buf[0] = '\0';
97  line_len = 0;
98  }
99 #endif
100 
101 #ifdef HELP_USE_COLOR
102  snprintf(buf, MAX_BUF - 1, "%s Commands:", get_category_name(commands_copy->cat));
103 #else
104  snprintf(buf, MAX_BUF - 1, " --- %s Commands --- ", get_category_name(commands_copy->cat));
105 #endif
106 
107  H2(buf);
108  current_cat = commands_copy->cat;
109  }
110 
111 #ifdef CLIENTHELP_LONG_LIST
112  if (commands_copy->desc != NULL) {
113  char buf[MAX_BUF];
114  snprintf(buf, MAX_BUF - 1, "%s - %s", commands_copy->name, commands_copy->desc);
115  LINE(buf);
116  } else {
117  LINE(commands_copy->name);
118  }
119 #else
120  {
121  size_t name_len;
122 
123  name_len = strlen(commands_copy->name);
124 
125  if (strlen(commands_copy->name) > MAX_BUF) {
126  LINE(commands_copy->name);
127  } else if (name_len > assumed_wrap) {
128  LINE(line_buf);
129  LINE(commands_copy->name);
130  line_len = 0;
131  } else if (line_len + name_len > assumed_wrap) {
132  LINE(line_buf);
133  strncpy(line_buf, commands_copy->name, name_len + 1);
134  line_len = name_len;
135  } else {
136  if (line_len > 0) {
137  strncat(line_buf, " ", 2);
138  line_len += 1;
139  }
140  strncat(line_buf, commands_copy->name, name_len + 1);
141  line_len += name_len;
142  }
143  }
144 #endif
145  }
146 
147 #ifndef CLIENTHELP_LONG_LIST
148  if (line_len) {
149  LINE(line_buf);
150  }
151 #endif
152 }
153 
158 static void show_help(const ConsoleCommand *cc) {
159  char buf[MAX_BUF];
160 
161  if (cc->desc != NULL) {
162  snprintf(buf, MAX_BUF - 1, "%s - %s", cc->name, cc->desc);
163  H2(buf);
164  } else {
165  snprintf(buf, MAX_BUF - 1, "Help for '%s':", cc->name);
166  H2(buf);
167  }
168 
169  if (cc->helpfunc != NULL) {
170  const char *long_help = NULL;
171  long_help = cc->helpfunc();
172 
173  if (long_help != NULL) {
174  LINE(long_help);
175  } else {
176  LINE("Extended help for this command is broken.");
177  }
178  } else {
179  LINE("No extended help is available for this command.");
180  }
181 }
182 
187 static void do_clienthelp(const char * arg)
188 {
189  const ConsoleCommand * cc;
190 
191  if (!arg || !strlen(arg)) {
193  return;
194  }
195 
196  cc = find_command(arg);
197 
198  if (cc == NULL) {
199  char buf[MAX_BUF];
200  snprintf(buf, MAX_BUF - 1, "clienthelp: Unknown command %s.", arg);
202  return;
203  }
204 
205  show_help(cc);
206 
207 }
208 
212 static const char * help_clienthelp(void)
213 {
214  return
215  "Syntax:\n"
216  "\n"
217  " clienthelp\n"
218  " clienthelp <command>\n"
219  "\n"
220  "Without any arguments, displays a list of client-side "
221  "commands.\n"
222  "\n"
223  "With arguments, displays the help for the client-side "
224  "command <command>.\n"
225  "\n"
226  "See also: serverhelp, help.";
227 }
228 
233 static void do_serverhelp(const char * arg)
234 {
235 
236  if (arg) {
237  char buf[MAX_BUF];
238  snprintf(buf, sizeof(buf), "help %s", arg);
239  /* maybe not a must send, but we probably don't want to drop it */
240  send_command(buf, -1, 1);
241  } else {
242  send_command("help", -1, 1); /* TODO make install in server branch doesn't install def_help. */
243  }
244 }
245 
249 static const char * help_serverhelp(void)
250 {
251  return
252  "Syntax:\n"
253  "\n"
254  " serverhelp\n"
255  " serverhelp <command>\n"
256  "\n"
257  "Fetches help from the server.\n"
258  "\n"
259  "Note that currently nothing can be done (without a recompile) if a "
260  "client command masks a server command.\n"
261  "\n"
262  "See also: clienthelp, help.";
263 }
264 
269 static void command_help(const char *cpnext)
270 {
271  if (cpnext) {
272  const ConsoleCommand * cc;
273  char buf[MAX_BUF];
274 
275  cc = find_command(cpnext);
276  if (cc != NULL) {
277  show_help(cc);
278  } else {
279  snprintf(buf, sizeof(buf), "help %s", cpnext);
280  /* maybe not a must send, but we probably don't want to drop it */
281  send_command(buf, -1, 1);
282  }
283  } else {
285  /* Now fetch (in theory) command list from the server.
286  TODO Protocol command - feed it to the tab completer.
287 
288  Nope! It effectivey fetches '/help commands for commands'.
289  */
290  send_command("help", -1, 1); /* TODO make install in server branch doesn't install def_help. */
291  }
292 }
293 
297 static const char * help_help(void)
298 {
299  return
300  "Syntax:\n"
301  "\n"
302  " help\n"
303  " help <topic>\n"
304  "\n"
305  "Without any arguments, displays a list of client-side "
306  "commands, and fetches the without-arguments help from "
307  "the server.\n"
308  "\n"
309  "With arguments, first checks if there's a client command "
310  "named <topic>. If there is, display it's help. If there "
311  "isn't, send the topic to the server.\n"
312  "\n"
313  "See also: clienthelp, serverhelp.";
314 }
315  /* EndOf PCmdHelpCommands
318  */
319 
320 /*
321  * Other commands.
322  */
323 
328 static void set_command_window(const char *cpnext)
329 {
330  if (!cpnext) {
332  "cwindow command requires a number parameter");
333  } else {
334  want_config[CONFIG_CWINDOW] = atoi(cpnext);
337  } else {
339  }
340  }
341 }
342 
347 static void command_foodbeep(const char *cpnext)
348 {
349  (void)cpnext; /* __UNUSED__ */
353  "Warning bell when low on food disabled");
354  } else {
357  "Warning bell when low on food enabled");
358  }
360 }
361 
366 const char * get_category_name(CommCat cat)
367 {
368  const char * cat_name;
369 
370  /* HACK Need to keep this in sync. with player.h */
371  switch(cat) {
372  case COMM_CAT_MISC:
373  cat_name = "Miscellaneous";
374  break;
375  case COMM_CAT_HELP:
376  cat_name = "Help";
377  break;
378  case COMM_CAT_INFO:
379  cat_name = "Informational";
380  break;
381  case COMM_CAT_SETUP:
382  cat_name = "Configuration";
383  break;
384  case COMM_CAT_SCRIPT:
385  cat_name = "Scripting";
386  break;
387  case COMM_CAT_DEBUG:
388  cat_name = "Debugging";
389  break;
390  default:
391  cat_name = "PROGRAMMER ERROR";
392  break;
393  }
394 
395  return cat_name;
396 }
397 
398 /*
399  * Command table.
400  *
401  * Implementation basically stolen verbatim from the server.
402  */
403 
404 /* "Typecasters" (and some forwards) */
405 
410 static void do_script_list(const char * ignored)
411 {
412  script_list();
413 }
414 
419 static void do_clearinfo(const char * ignored)
420 {
421  menu_clear();
422 }
423 
428 static void do_disconnect(const char * ignored)
429 {
431 
432  /* the gtk clients need to do some cleanup logic - otherwise,
433  * they start hogging CPU.
434  */
436  return;
437 }
438 
439 #ifdef HAVE_DMALLOC_H
440 #ifndef DMALLOC_VERIFY_NOERROR
441 #define DMALLOC_VERIFY_NOERROR 1
442 #endif
443 
447 static void do_dmalloc(const char * ignored)
448 {
449  if (dmalloc_verify(NULL)==DMALLOC_VERIFY_NOERROR)
451  "Heap checks out OK");
452  else
454  "Heap corruption detected");
455 }
456 #endif
457 
462 static void do_inv(const char * ignored)
463 {
465 }
466 
467 static void do_magicmap(const char * ignored)
468 {
469  cpl.showmagic=1;
470  draw_magic_map();
471 }
472 
477 static void do_savedefaults(const char * ignored)
478 {
479  save_defaults();
480 }
481 
486 static void do_savewinpos(const char * ignored)
487 {
488  save_winpos();
489 }
490 
495 static void do_take(const char * used)
496 {
497  command_take("take", used); /* I dunno why they want it. */
498 }
499 
504 static void do_num_free_items(const char * ignored)
505 {
506  LOG(LOG_INFO,"common::extended_command","num_free_items=%d", num_free_items());
507 }
508 
509 static void do_clienthelp(const char * arg); /* Forward. */
510 
511 /* Help "typecasters". */
512 #include "chelp.h"
513 
517 static const char * help_bind(void)
518 {
519  return HELP_BIND_LONG;
520 }
521 
525 static const char * help_unbind(void)
526 {
527  return HELP_UNBIND_LONG;
528 }
529 
533 static const char * help_magicmap(void)
534 {
535  return HELP_MAGICMAP_LONG;
536 }
537 
541 static const char * help_inv(void)
542 {
543  return HELP_INV_LONG;
544 }
545 
549 static const char * help_cwindow(void)
550 {
551  return
552  "Syntax:\n"
553  "\n"
554  " cwindow <val>\n"
555  "\n"
556  "set size of command"
557  "window (if val is exceeded"
558  "client won't send new"
559  "commands to server\n\n"
560  "(What does this mean, 'put a lid on it'?) TODO";
561 }
562 
566 static const char * help_script(void) {
567  return
568  "Syntax: script <path>\n\n"
569  "Start an executable client script located at <path>. For details on "
570  "client-side scripting, please see the Crossfire Wiki.";
571 }
572 
576 static const char * help_scripttell(void)
577 {
578  return
579  "Syntax:\n"
580  "\n"
581  " scripttell <yourname> <data>\n"
582  "\n"
583  "?";
584 }
585 
586 /* Toolkit-dependent. */
587 
591 static const char * help_savewinpos(void)
592 {
593  return
594  "Syntax:\n"
595  "\n"
596  " savewinpos\n"
597  "\n"
598  "save window positions - split windows mode only.";
599 }
600 
601 static const char * help_scriptkill(void)
602 {
603  return
604  "Syntax:\n"
605  "\n"
606  " scriptkill <name>\n"
607  "\n"
608  "Stop scripts named <name>.\n"
609  "(Not guaranteed to work?)";
610 }
611 
615 static const char * help_showweight(void)
616 {
617  return
618  "Syntax:\n"
619  "\n"
620  " showweight\n"
621  " showweight inventory\n"
622  " showweight look\n"
623  "\n"
624  "(Or any prefix of the arguments.)"
625  "Toggles if you see the weight of"
626  "items in your inventory (also if"
627  "no argument given) or your"
628  "look-window.";
629 }
630 
631 /*
632 * draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
633  "Information Commands");*
634  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
635  " inv - *recursively* print your");
636  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
637  " inventory - includes containers.");
638  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
639  " showinfo, take");
640  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
641  " help - show this message");
642  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
643  " help <command> - get more information on a");
644  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
645  " command (Server command only?)");
646  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
647  " showicon - draw status icons in");
648  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
649  " inventory window");
650  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
651  " showweight - show weight in inventory");
652  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
653  " look windows");
654  draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
655  "Scripting Commands");
656  draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
657  "Client Side Debugging Commands");
658 #ifdef HAVE_DMALLOC_H
659  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
660  " dmalloc - Check heap?");
661 #endif
662 */
663 
664 /* TODO Wrap these? Um. */
666  /* From player.h:
667  name, cat,
668  func, helpfunc,
669  long_desc
670  */
671 
672  {
673  "autorepeat", COMM_CAT_MISC,
674  set_autorepeat, NULL,
675  "toggle autorepeat" /* XXX Eh? */
676  },
677 
678  {
679  "bind", COMM_CAT_SETUP,
682  },
683 
684  {
685  "script", COMM_CAT_SCRIPT,
687  NULL
688  },
689 #ifdef HAVE_LUA
690  {
691  "lua_load", COMM_CAT_SCRIPT,
692  script_lua_load, NULL, NULL
693  },
694 
695  {
696  "lua_list", COMM_CAT_SCRIPT,
697  script_lua_list, NULL, NULL
698  },
699 
700  {
701  "lua_kill", COMM_CAT_SCRIPT,
702  script_lua_kill, NULL, NULL
703  },
704 #endif
705  {
706  "scripts", COMM_CAT_SCRIPT,
707  do_script_list, NULL,
708  "List the running scripts(?)"
709  },
710 
711  {
712  "scriptkill", COMM_CAT_SCRIPT,
714  NULL
715  },
716 
717  {
718  "scripttell", COMM_CAT_SCRIPT,
720  NULL
721  },
722 
723  {
724  "clearinfo", COMM_CAT_MISC,
725  do_clearinfo, NULL,
726  "clear the info window"
727  },
728 
729  {
730  "cwindow", COMM_CAT_SETUP,
732  NULL
733  },
734 
735  {
736  "disconnect", COMM_CAT_MISC,
737  do_disconnect, NULL,
738  "close connection to server"
739  },
740 
741 
742 #ifdef HAVE_DMALLOC_H
743  {
744  "dmalloc", COMM_CAT_DEBUG,
745  do_dmalloc, NULL,
746  NULL
747  },
748 #endif
749 
750  {
751  "foodbeep", COMM_CAT_SETUP,
752  command_foodbeep, NULL,
753  "toggle audible low on food warning"
754 
755  },
756 
757  {
758  "help", COMM_CAT_HELP,
760  NULL
761  },
762 
763  {
764  "clienthelp", COMM_CAT_HELP,
766  "Client-side command information"
767  },
768 
769  {
770  "serverhelp", COMM_CAT_HELP,
772  "Server-side command information"
773  },
774 
775  {
776  "inv", COMM_CAT_DEBUG,
777  do_inv, help_inv,
779  },
780 
781  {
782  "magicmap", COMM_CAT_MISC,
785  },
786 
787  {
788  "savedefaults", COMM_CAT_SETUP,
789  do_savedefaults, NULL,
790  HELP_SAVEDEFAULTS_SHORT /* How do we make sure showicons stays on? */
791  },
792 
793  {
794  "savewinpos", COMM_CAT_SETUP,
796  "Saves the position and sizes of windows." /* Panes? */
797  },
798 
799  {
800  "scroll", COMM_CAT_SETUP,
801  set_scroll, NULL,
802  "toggle scroll/wrap mode in info window"
803  },
804 
805  {
806  "showicon", COMM_CAT_SETUP,
807  set_show_icon, NULL,
808  "Toggles if you see the worn, locked, cursed etc state in the inventory pane."
809  },
810 
811  {
812  "showweight", COMM_CAT_SETUP,
814  "Toggles if you see item weights in inventory look windows."
815  },
816 
817  {
818  "take", COMM_CAT_MISC,
819  do_take, NULL,
820  NULL
821  },
822 
823  {
824  "unbind", COMM_CAT_SETUP,
826  NULL
827  },
828 
829  {
830  "num_free_items", COMM_CAT_DEBUG,
831  do_num_free_items, NULL,
832  "log the number of free items?"
833  },
834  {
835  "show", COMM_CAT_SETUP,
836  command_show, NULL,
837  "Change what items to show in inventory"
838  },
839 
840 };
841 
842 const int CommonCommandsSize = sizeof(CommonCommands) / sizeof(ConsoleCommand);
843 
844 #ifdef TOOLKIT_COMMANDS
845 extern ConsoleCommand ToolkitCommands[];
846 
847 extern const int ToolkitCommandsSize;
848 #endif
849 
850 /* ------------------------------------------------------------------ */
851 
853 
858 {
859  return num_commands;
860 }
861 
863 
869 static int sort_by_name(const void * a_, const void * b_)
870 {
871  ConsoleCommand * a = *((ConsoleCommand **)a_);
872  ConsoleCommand * b = *((ConsoleCommand **)b_);
873 
874  return strcmp(a->name, b->name);
875 }
876 
878 
879 /* Sort by category, then by name. */
880 
886 static int sort_by_category(const void *a_, const void *b_)
887 {
888  /* Typecasts, so it goes. */
889  ConsoleCommand * a = *((ConsoleCommand **)a_);
890  ConsoleCommand * b = *((ConsoleCommand **)b_);
891 
892  if (a->cat == b->cat) {
893  return strcmp(a->name, b->name);
894  }
895 
896  return a->cat - b->cat;
897 }
898 
902 void init_commands(void)
903 {
904  int i;
905 
906 #ifdef TOOLKIT_COMMANDS
907  init_toolkit_commands();
908 
909  /* TODO I dunno ... go through the list and print commands without helps? */
910  num_commands = CommonCommandsSize + ToolkitCommandsSize;
911 #else
912  num_commands = CommonCommandsSize;
913 #endif
914 
915  /* Make a list of (pointers to statically allocated!) all the commands.
916  We have a list; the toolkit has a
917  ToolkitCommands and ToolkitCommandsSize, initialized before calling this.
918  */
919 
920  /* XXX Leak! */
921  name_sorted_commands = g_malloc(sizeof(ConsoleCommand *) * num_commands);
922 
923  for (i = 0; i < CommonCommandsSize; i++) {
924  name_sorted_commands[i] = &CommonCommands[i];
925  }
926 
927 #ifdef TOOLKIT_COMMANDS
928  for(i = 0; i < ToolkitCommandsSize; i++) {
929  name_sorted_commands[CommonCommandsSize + i] = &ToolkitCommands[i];
930  }
931 #endif
932 
933  /* Sort them. */
934  qsort(name_sorted_commands, num_commands, sizeof(ConsoleCommand *), sort_by_name);
935 
936  /* Copy the list, then sort it by category. */
937  cat_sorted_commands = g_malloc(sizeof(ConsoleCommand *) * num_commands);
938 
939  memcpy(cat_sorted_commands, name_sorted_commands, sizeof(ConsoleCommand *) * num_commands);
940 
941  qsort(cat_sorted_commands, num_commands, sizeof(ConsoleCommand *), sort_by_category);
942 
943  /* TODO Add to the list of tab-completion items. */
944 }
945 
946 #ifndef tolower
947 #define tolower(C) (((C) >= 'A' && (C) <= 'Z')? (C) - 'A' + 'a': (C))
948 #endif
949 
954 const ConsoleCommand * find_command(const char * cmd)
955 {
956  ConsoleCommand ** asp_p = NULL, dummy;
957  ConsoleCommand * dummy_p;
958  ConsoleCommand * asp;
959  char *cp, *cmd_cpy;
960  cmd_cpy = g_strdup(cmd);
961 
962  for (cp=cmd_cpy; *cp; cp++) {
963  *cp =tolower(*cp);
964  }
965 
966  dummy.name = cmd_cpy;
967  dummy_p = &dummy;
968  asp_p = bsearch(
969  (void *)&dummy_p,
970  (void *)name_sorted_commands,
971  num_commands,
972  sizeof(ConsoleCommand *),
973  sort_by_name);
974 
975  if (asp_p == NULL) {
976  free(cmd_cpy);
977  return NULL;
978  }
979 
980  asp = *asp_p;
981 
982  /* TODO The server's find_command() searches first the commands,
983  then the emotes. We might have to do something similar someday, too. */
984  /* if (asp == NULL) search something else? */
985 
986  free(cmd_cpy);
987 
988  return asp;
989 }
990 
996 {
997  return cat_sorted_commands;
998 }
999 
1009 int handle_local_command(const char* cp, const char * cpnext)
1010 {
1011  const ConsoleCommand * cc = NULL;
1012 
1013  cc = find_command(cp);
1014 
1015  if (cc == NULL) {
1016  return FALSE;
1017  }
1018 
1019  if (cc->dofunc == NULL) {
1020  char buf[MAX_BUF];
1021 
1022  snprintf(buf, MAX_BUF - 1, "Client command %s has no implementation!", cc->name);
1024 
1025  return FALSE;
1026  }
1027 
1028  cc->dofunc(cpnext);
1029 
1030  return TRUE;
1031 }
1032 
1044 void extended_command(const char *ocommand)
1045 {
1046  const char *cp = ocommand;
1047  char *cpnext, command[MAX_BUF];
1048 
1049  if ((cpnext = strchr(cp, ' '))!=NULL) {
1050  int len = cpnext - ocommand;
1051  if (len > (MAX_BUF -1 )) {
1052  len = MAX_BUF-1;
1053  }
1054 
1055  strncpy(command, ocommand, len);
1056  command[len] = '\0';
1057  cp = command;
1058  while (*cpnext == ' ') {
1059  cpnext++;
1060  }
1061  if (*cpnext == 0) {
1062  cpnext = NULL;
1063  }
1064  }
1065  /*
1066  * Try to prevent potential client hang by trying to delete a
1067  * character when there is no character to delete.
1068  * Thus, only send quit command if there is a player to delete.
1069  */
1070  if (cpl.title[0] == '\0' && strcmp(cp, "quit") == 0){
1071  // Bail here, there isn't anything this should be doing.
1072  return;
1073  }
1074 
1075  /* cp now contains the command (everything before first space),
1076  * and cpnext contains everything after that first space. cpnext
1077  * could be NULL.
1078  */
1079 #ifdef HAVE_LUA
1080  if ( script_lua_command(cp, cpnext) ) {
1081  return;
1082  }
1083 #endif
1084 
1085  /* If this isn't a client-side command, send it to the server. */
1086  if (!handle_local_command(cp, cpnext)) {
1087  /* just send the command(s) (if `ocommand' is a compound command */
1088  /* then split it and send each part seperately */
1089  /* TODO Remove this from the server; end of commands.c. */
1090  strncpy(command, ocommand, MAX_BUF-1);
1091  command[MAX_BUF-1]=0;
1092  cp = strtok(command, ";");
1093  while ( cp ) {
1094  while( *cp == ' ' ) {
1095  cp++;
1096  } /* throw out leading spaces; server
1097  does not like them */
1098  send_command(cp, cpl.count, 0);
1099  cp = strtok(NULL, ";");
1100  }
1101  }
1102 }
1103 
1104 /* ------------------------------------------------------------------ */
1105 
1106 /* This list is used for the 'tab' completion, and nothing else.
1107  * Therefore, if it is out of date, it isn't that terrible, but
1108  * ideally it should stay somewhat up to date with regards to
1109  * the commands the server supports.
1110  */
1111 
1112 /* TODO Dynamically generate. */
1113 
1114 static const char *const commands[] = {
1115  "accuse", "afk", "apply", "applymode", "archs", "beg", "bleed", "blush",
1116  "body", "bounce", "bow", "bowmode", "brace", "build", "burp", "cackle", "cast",
1117  "chat", "chuckle", "clap", "cointoss", "cough", "cringe", "cry", "dance",
1118  "disarm", "dm", "dmhide", "drop", "dropall", "east", "examine", "explore",
1119  "fire", "fire_stop", "fix_me", "flip", "frown", "gasp", "get", "giggle",
1120  "glare", "grin", "groan", "growl", "gsay", "help", "hiccup", "hiscore", "hug",
1121  "inventory", "invoke", "killpets", "kiss", "laugh", "lick", "listen", "logs",
1122  "mapinfo", "maps", "mark", "me", "motd", "nod", "north", "northeast",
1123  "northwest", "orcknuckle", "output-count", "output-sync", "party", "peaceful",
1124  "petmode", "pickup", "players", "poke", "pout", "prepare", "printlos", "puke",
1125  "quests", "quit", "ready_skill", "rename", "reply", "resistances",
1126  "rotateshoottype", "run", "run_stop", "save", "say", "scream", "search",
1127  "search-items", "shake", "shiver", "shout", "showpets", "shrug", "shutdown",
1128  "sigh", "skills", "slap", "smile", "smirk", "snap", "sneeze", "snicker",
1129  "sniff", "snore", "sound", "south", "southeast", "southwest", "spit",
1130  "statistics", "stay", "strings", "strut", "sulk", "take", "tell", "thank",
1131  "think", "throw", "time", "title", "twiddle", "use_skill", "usekeys",
1132  "version", "wave", "weather", "west", "whereabouts", "whereami", "whistle",
1133  "who", "wimpy", "wink", "yawn",
1134 };
1135 #define NUM_COMMANDS ((int)(sizeof(commands) / sizeof(char*)))
1136 
1144 const char * complete_command(const char *command)
1145 {
1146  int i, len, display;
1147  const char *match;
1148  static char result[64];
1149  char list[500];
1150 
1151  len = strlen(command);
1152 
1153  if (len == 0) {
1154  return NULL;
1155  }
1156 
1157  display = 0;
1158  strcpy(list, "Matching commands:");
1159 
1160  /* TODO Partial match, e.g.:
1161  If the completion list was:
1162  wear
1163  wet #?
1164 
1165  If we type 'w' then hit tab, put in the e.
1166 
1167  Basically part of bash (readline?)'s behaviour.
1168  */
1169 
1170  match = NULL;
1171 
1172  /* check server side commands */
1173  for (i=0; i<NUM_COMMANDS; i++) {
1174  if (!strncmp(command, commands[i], len)) {
1175  if (display) {
1176  snprintf(list + strlen(list), 499 - strlen(list), " %s", commands[i]);
1177  } else if (match != NULL) {
1178  display = 1;
1179  snprintf(list + strlen(list), 499 - strlen(list), " %s %s", match, commands[i]);
1180  match = NULL;
1181  } else {
1182  match = commands[i];
1183  }
1184  }
1185  }
1186 
1187  /* check client side commands */
1188  for (i=0; i<CommonCommandsSize; i++) {
1189  if (!strncmp(command, CommonCommands[i].name, len)) {
1190  if (display) {
1191  snprintf(list + strlen(list), 499 - strlen(list), " %s", CommonCommands[i].name);
1192  } else if (match != NULL) {
1193  display = 1;
1194  snprintf(list + strlen(list), 499 - strlen(list), " %s %s", match, CommonCommands[i].name);
1195  match = NULL;
1196  } else {
1197  match = CommonCommands[i].name;
1198  }
1199  }
1200  }
1201 
1202  if (match == NULL) {
1203  if (display) {
1204  strncat(list, "\n", 499 - strlen(list));
1205  draw_ext_info(
1207  } else
1209  "No matching command.\n");
1210  /* No match. */
1211  return NULL;
1212  }
1213 
1214  /*
1215  * Append a space to allow typing arguments. For commands without arguments
1216  * the excess space should be stripped off automatically.
1217  */
1218  snprintf(result, sizeof(result), "%s ", match);
1219 
1220  return result;
1221 }
1222 
1223 #endif /* CPROTO */
#define HELP_BIND_SHORT
Definition: chelp.h:6
void set_autorepeat(const char *s)
A stub function that does nothing.
Definition: info.c:1345
int num_free_items(void)
Definition: item.c:458
void script_lua_list(const char *param)
#define COMMAND_WINDOW
Do not send more than this many outstanding commands to the server this is only a default value...
Definition: client.h:40
int script_lua_command(const char *command, const char *param)
int handle_local_command(const char *cp, const char *cpnext)
Tries to handle command cp (with optional params in cpnext, which may be null) as a local command...
Definition: p_cmd.c:1009
static const char * help_unbind(void)
Definition: p_cmd.c:525
void command_take(const char *command, const char *cpnext)
Definition: player.c:277
gint16 use_config[CONFIG_NUMS]
Definition: init.c:39
#define H1(a)
Definition: p_cmd.c:53
void set_show_icon(const char *s)
Definition: inventory.c:574
void script_lua_kill(const char *param)
#define HELP_MAGICMAP_SHORT
Definition: chelp.h:54
#define assumed_wrap
Definition: p_cmd.c:58
static void command_foodbeep(const char *cpnext)
Definition: p_cmd.c:347
#define H2(a)
Definition: p_cmd.c:54
#define HELP_BIND_LONG
Definition: chelp.h:7
void cleanup_connection(void)
Called from disconnect command - that closes the socket - we just need to do the gtk cleanup...
Definition: main.c:166
CommFunc dofunc
Definition: p_cmd.h:60
#define NUM_COMMANDS
Definition: p_cmd.c:1135
#define HELP_MAGICMAP_LONG
Definition: chelp.h:55
item * ob
Player object.
Definition: client.h:309
const char * get_category_name(CommCat cat)
Definition: p_cmd.c:366
static const char *const commands[]
Definition: p_cmd.c:1114
CommCat cat
Definition: p_cmd.h:59
static const char * help_showweight(void)
Definition: p_cmd.c:615
#define CONFIG_FOODBEEP
Definition: client.h:178
void init_commands(void)
Fills some internal arrays.
Definition: p_cmd.c:902
#define MSG_TYPE_CLIENT
Client originated Messages.
Definition: newclient.h:420
static void set_command_window(const char *cpnext)
Definition: p_cmd.c:328
static const char * help_savewinpos(void)
Definition: p_cmd.c:591
void close_server_connection()
Closes the connection to the server.
Definition: client.c:179
Contains external calls that the common area makes callbacks to.
#define NDI_BLACK
Definition: newclient.h:249
CommCat
Definition: p_cmd.h:44
static void do_clearinfo(const char *ignored)
Definition: p_cmd.c:419
static void do_clienthelp(const char *arg)
Definition: p_cmd.c:187
#define HELP_UNBIND_LONG
Definition: chelp.h:45
static const char * help_clienthelp(void)
Definition: p_cmd.c:212
void LOG(LogLevel level, const char *origin, const char *format,...)
Log messages of a certain importance to stderr.
Definition: misc.c:111
#define MSG_TYPE_CLIENT_ERROR
Bad things happening.
Definition: newclient.h:692
void script_init(const char *cparams)
Definition: script.c:209
#define NDI_RED
Definition: newclient.h:252
const char * desc
Definition: p_cmd.h:63
static const char * help_scripttell(void)
Definition: p_cmd.c:576
static const char * help_help(void)
Definition: p_cmd.c:297
Includes and prototypes for p_cmd.c for player-commands like '/magicmap'.
#define MSG_TYPE_CLIENT_NOTICE
Non-critical note to player.
Definition: newclient.h:689
static const char * help_serverhelp(void)
Definition: p_cmd.c:249
int send_command(const char *command, int repeat, int must_send)
Definition: player.c:200
static void do_magicmap(const char *ignored)
Definition: p_cmd.c:467
void save_winpos(void)
Save client window positions to a file unique to each layout.
Definition: config.c:1132
#define HELP_SAVEDEFAULTS_SHORT
Definition: chelp.h:59
const char * name
Definition: p_cmd.h:58
Client_Player cpl
Player object.
Definition: client.c:68
#define CONFIG_CWINDOW
Definition: client.h:161
static const char * help_scriptkill(void)
Definition: p_cmd.c:601
static const char * help_magicmap(void)
Definition: p_cmd.c:533
const int CommonCommandsSize
Definition: p_cmd.c:842
static void do_clienthelp_list(void)
Definition: p_cmd.c:65
void extended_command(const char *ocommand)
This is an extended command (ie, 'who, 'whatever, etc).
Definition: p_cmd.c:1044
gint16 want_config[CONFIG_NUMS]
Definition: init.c:39
int num_commands
Definition: p_cmd.c:852
static void do_take(const char *used)
Definition: p_cmd.c:495
static void command_help(const char *cpnext)
Definition: p_cmd.c:269
CommHelpFunc helpfunc
Definition: p_cmd.h:62
const char * complete_command(const char *command)
Player has entered 'command' and hit tab to complete it.
Definition: p_cmd.c:1144
guint32 count
Repeat count on command.
Definition: client.h:332
#define HELP_INV_SHORT
Definition: chelp.h:66
#define MAX_BUF
Definition: client-types.h:39
void script_list(void)
Definition: script.c:498
static int sort_by_category(const void *a_, const void *b_)
Definition: p_cmd.c:886
guint8 showmagic
If 0, show the normal map, otherwise show the magic map.
Definition: client.h:337
int get_num_commands(void)
Definition: p_cmd.c:857
#define HELP_INV_LONG
Definition: chelp.h:67
void save_defaults(void)
This function saves user settings chosen using the configuration popup dialog.
Definition: config.c:501
void bind_key(const char *params)
static ConsoleCommand ** name_sorted_commands
Definition: p_cmd.c:862
static ConsoleCommand CommonCommands[]
Definition: p_cmd.c:665
static void do_num_free_items(const char *ignored)
Definition: p_cmd.c:504
void print_inventory(item *op)
Definition: item.c:678
const ConsoleCommand * find_command(const char *cmd)
Definition: p_cmd.c:954
#define LINE(a)
Definition: p_cmd.c:55
void script_tell(const char *params)
Definition: script.c:951
static const char * help_bind(void)
Definition: p_cmd.c:517
void menu_clear(void)
Clears all the message panels.
Definition: info.c:1314
void script_kill(const char *params)
Definition: script.c:520
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
A message processor that accepts messages along with meta information color and type.
Definition: info.c:934
void set_show_weight(const char *s)
Definition: inventory.c:581
void command_show(const char *params)
Definition: inventory.c:608
static void do_disconnect(const char *ignored)
Definition: p_cmd.c:428
static void show_help(const ConsoleCommand *cc)
Definition: p_cmd.c:158
static void do_savewinpos(const char *ignored)
Definition: p_cmd.c:486
static void do_serverhelp(const char *arg)
Definition: p_cmd.c:233
void script_lua_load(const char *name)
void draw_magic_map(void)
Draws the magic map - basically, it is just a simple encoding of space X is color C...
Definition: magicmap.c:38
char title[MAX_BUF]
Title of character.
Definition: client.h:324
Includes various dependencies header files needed by most everything.
char * name
Definition: image.c:56
static int sort_by_name(const void *a_, const void *b_)
Definition: p_cmd.c:869
static void do_inv(const char *ignored)
Definition: p_cmd.c:462
static const char * help_script(void)
Definition: p_cmd.c:566
void unbind_key(const char *params)
Definition: keys.c:1463
static ConsoleCommand ** cat_sorted_commands
Definition: p_cmd.c:877
#define tolower(C)
Definition: p_cmd.c:947
static const char * help_inv(void)
Definition: p_cmd.c:541
static void do_script_list(const char *ignored)
Definition: p_cmd.c:410
static void do_savedefaults(const char *ignored)
Definition: p_cmd.c:477
static const char * help_cwindow(void)
Definition: p_cmd.c:549
ConsoleCommand ** get_cat_sorted_commands(void)
Returns a pointer to the head of an array of ConsoleCommands sorted by category, then by name...
Definition: p_cmd.c:995
void set_scroll(const char *s)
A stub function that does nothing.
Definition: info.c:1332