Crossfire Client, Trunk  R19593
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_metaserver(const char * ignored)
478 {
480  metaserver_show(FALSE);
481  } else
484  "Unable to get metaserver information.");
485 }
486 
491 static void do_savedefaults(const char * ignored)
492 {
493  save_defaults();
494 }
495 
500 static void do_savewinpos(const char * ignored)
501 {
502  save_winpos();
503 }
504 
509 static void do_take(const char * used)
510 {
511  command_take("take", used); /* I dunno why they want it. */
512 }
513 
518 static void do_num_free_items(const char * ignored)
519 {
520  LOG(LOG_INFO,"common::extended_command","num_free_items=%d", num_free_items());
521 }
522 
523 static void do_clienthelp(const char * arg); /* Forward. */
524 
525 /* Help "typecasters". */
526 #include "chelp.h"
527 
531 static const char * help_bind(void)
532 {
533  return HELP_BIND_LONG;
534 }
535 
539 static const char * help_unbind(void)
540 {
541  return HELP_UNBIND_LONG;
542 }
543 
547 static const char * help_magicmap(void)
548 {
549  return HELP_MAGICMAP_LONG;
550 }
551 
555 static const char * help_inv(void)
556 {
557  return HELP_INV_LONG;
558 }
559 
563 static const char * help_cwindow(void)
564 {
565  return
566  "Syntax:\n"
567  "\n"
568  " cwindow <val>\n"
569  "\n"
570  "set size of command"
571  "window (if val is exceeded"
572  "client won't send new"
573  "commands to server\n\n"
574  "(What does this mean, 'put a lid on it'?) TODO";
575 }
576 
580 static const char * help_script(void) {
581  return
582  "Syntax: script <path>\n\n"
583  "Start an executable client script located at <path>. For details on "
584  "client-side scripting, please see the Crossfire Wiki.";
585 }
586 
590 static const char * help_scripttell(void)
591 {
592  return
593  "Syntax:\n"
594  "\n"
595  " scripttell <yourname> <data>\n"
596  "\n"
597  "?";
598 }
599 
600 /* Toolkit-dependent. */
601 
605 static const char * help_savewinpos(void)
606 {
607  return
608  "Syntax:\n"
609  "\n"
610  " savewinpos\n"
611  "\n"
612  "save window positions - split windows mode only.";
613 }
614 
618 static const char * help_metaserver(void)
619 {
620  /* TODO Add command_escape() where appropriate. On the other
621  hand, that can lead to a meaningless syntax-display API.*/
622 
623  return
624  "Syntax:\n"
625  "\n"
626  " metaserver\n"
627  "\n"
628  "Get updated list of servers "
629  "from the metaserver and show it."
630  "This is the same information that the client "
631  "uses to show a list of servers when it starts.\n"
632  "\n"
633  "Warning: This command may freeze the client until it gets the list.";
634 }
635 
639 static const char * help_scriptkill(void)
640 {
641  return
642  "Syntax:\n"
643  "\n"
644  " scriptkill <name>\n"
645  "\n"
646  "Stop scripts named <name>.\n"
647  "(Not guaranteed to work?)";
648 }
649 
653 static const char * help_showweight(void)
654 {
655  return
656  "Syntax:\n"
657  "\n"
658  " showweight\n"
659  " showweight inventory\n"
660  " showweight look\n"
661  "\n"
662  "(Or any prefix of the arguments.)"
663  "Toggles if you see the weight of"
664  "items in your inventory (also if"
665  "no argument given) or your"
666  "look-window.";
667 }
668 
669 /*
670 * draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
671  "Information Commands");*
672  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
673  " inv - *recursively* print your");
674  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
675  " inventory - includes containers.");
676  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
677  " showinfo, take");
678  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
679  " help - show this message");
680  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
681  " help <command> - get more information on a");
682  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
683  " command (Server command only?)");
684  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
685  " showicon - draw status icons in");
686  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
687  " inventory window");
688  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
689  " showweight - show weight in inventory");
690  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
691  " look windows");
692  draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
693  "Scripting Commands");
694  draw_ext_info(NDI_NAVY, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
695  "Client Side Debugging Commands");
696 #ifdef HAVE_DMALLOC_H
697  draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
698  " dmalloc - Check heap?");
699 #endif
700 */
701 
702 /* TODO Wrap these? Um. */
704  /* From player.h:
705  name, cat,
706  func, helpfunc,
707  long_desc
708  */
709 
710  {
711  "autorepeat", COMM_CAT_MISC,
712  set_autorepeat, NULL,
713  "toggle autorepeat" /* XXX Eh? */
714  },
715 
716  {
717  "bind", COMM_CAT_SETUP,
720  },
721 
722  {
723  "script", COMM_CAT_SCRIPT,
725  NULL
726  },
727 #ifdef HAVE_LUA
728  {
729  "lua_load", COMM_CAT_SCRIPT,
730  script_lua_load, NULL, NULL
731  },
732 
733  {
734  "lua_list", COMM_CAT_SCRIPT,
735  script_lua_list, NULL, NULL
736  },
737 
738  {
739  "lua_kill", COMM_CAT_SCRIPT,
740  script_lua_kill, NULL, NULL
741  },
742 #endif
743  {
744  "scripts", COMM_CAT_SCRIPT,
745  do_script_list, NULL,
746  "List the running scripts(?)"
747  },
748 
749  {
750  "scriptkill", COMM_CAT_SCRIPT,
752  NULL
753  },
754 
755  {
756  "scripttell", COMM_CAT_SCRIPT,
758  NULL
759  },
760 
761  {
762  "clearinfo", COMM_CAT_MISC,
763  do_clearinfo, NULL,
764  "clear the info window"
765  },
766 
767  {
768  "cwindow", COMM_CAT_SETUP,
770  NULL
771  },
772 
773  {
774  "disconnect", COMM_CAT_MISC,
775  do_disconnect, NULL,
776  "close connection to server"
777  },
778 
779 
780 #ifdef HAVE_DMALLOC_H
781  {
782  "dmalloc", COMM_CAT_DEBUG,
783  do_dmalloc, NULL,
784  NULL
785  },
786 #endif
787 
788  {
789  "foodbeep", COMM_CAT_SETUP,
790  command_foodbeep, NULL,
791  "toggle audible low on food warning"
792 
793  },
794 
795  {
796  "help", COMM_CAT_HELP,
798  NULL
799  },
800 
801  {
802  "clienthelp", COMM_CAT_HELP,
804  "Client-side command information"
805  },
806 
807  {
808  "serverhelp", COMM_CAT_HELP,
810  "Server-side command information"
811  },
812 
813  {
814  "inv", COMM_CAT_DEBUG,
815  do_inv, help_inv,
817  },
818 
819  {
820  "magicmap", COMM_CAT_MISC,
823  },
824 
825  {
826  "metaserver", COMM_CAT_INFO,
828  "Print 'metaserver information'. Warning - your client will pause."
829  },
830 
831  {
832  "savedefaults", COMM_CAT_SETUP,
833  do_savedefaults, NULL,
834  HELP_SAVEDEFAULTS_SHORT /* How do we make sure showicons stays on? */
835  },
836 
837  {
838  "savewinpos", COMM_CAT_SETUP,
840  "Saves the position and sizes of windows." /* Panes? */
841  },
842 
843  {
844  "scroll", COMM_CAT_SETUP,
845  set_scroll, NULL,
846  "toggle scroll/wrap mode in info window"
847  },
848 
849  {
850  "showicon", COMM_CAT_SETUP,
851  set_show_icon, NULL,
852  "Toggles if you see the worn, locked, cursed etc state in the inventory pane."
853  },
854 
855  {
856  "showweight", COMM_CAT_SETUP,
858  "Toggles if you see item weights in inventory look windows."
859  },
860 
861  {
862  "take", COMM_CAT_MISC,
863  do_take, NULL,
864  NULL
865  },
866 
867  {
868  "unbind", COMM_CAT_SETUP,
870  NULL
871  },
872 
873  {
874  "num_free_items", COMM_CAT_DEBUG,
875  do_num_free_items, NULL,
876  "log the number of free items?"
877  },
878  {
879  "show", COMM_CAT_SETUP,
880  command_show, NULL,
881  "Change what items to show in inventory"
882  },
883 
884 };
885 
886 const int CommonCommandsSize = sizeof(CommonCommands) / sizeof(ConsoleCommand);
887 
888 #ifdef TOOLKIT_COMMANDS
889 extern ConsoleCommand ToolkitCommands[];
890 
891 extern const int ToolkitCommandsSize;
892 #endif
893 
894 /* ------------------------------------------------------------------ */
895 
897 
902 {
903  return num_commands;
904 }
905 
907 
913 static int sort_by_name(const void * a_, const void * b_)
914 {
915  ConsoleCommand * a = *((ConsoleCommand **)a_);
916  ConsoleCommand * b = *((ConsoleCommand **)b_);
917 
918  return strcmp(a->name, b->name);
919 }
920 
922 
923 /* Sort by category, then by name. */
924 
930 static int sort_by_category(const void *a_, const void *b_)
931 {
932  /* Typecasts, so it goes. */
933  ConsoleCommand * a = *((ConsoleCommand **)a_);
934  ConsoleCommand * b = *((ConsoleCommand **)b_);
935 
936  if (a->cat == b->cat) {
937  return strcmp(a->name, b->name);
938  }
939 
940  return a->cat - b->cat;
941 }
942 
946 void init_commands(void)
947 {
948  int i;
949 
950 #ifdef TOOLKIT_COMMANDS
951  init_toolkit_commands();
952 
953  /* TODO I dunno ... go through the list and print commands without helps? */
954  num_commands = CommonCommandsSize + ToolkitCommandsSize;
955 #else
956  num_commands = CommonCommandsSize;
957 #endif
958 
959  /* Make a list of (pointers to statically allocated!) all the commands.
960  We have a list; the toolkit has a
961  ToolkitCommands and ToolkitCommandsSize, initialized before calling this.
962  */
963 
964  /* XXX Leak! */
965  name_sorted_commands = g_malloc(sizeof(ConsoleCommand *) * num_commands);
966 
967  for (i = 0; i < CommonCommandsSize; i++) {
968  name_sorted_commands[i] = &CommonCommands[i];
969  }
970 
971 #ifdef TOOLKIT_COMMANDS
972  for(i = 0; i < ToolkitCommandsSize; i++) {
973  name_sorted_commands[CommonCommandsSize + i] = &ToolkitCommands[i];
974  }
975 #endif
976 
977  /* Sort them. */
978  qsort(name_sorted_commands, num_commands, sizeof(ConsoleCommand *), sort_by_name);
979 
980  /* Copy the list, then sort it by category. */
981  cat_sorted_commands = g_malloc(sizeof(ConsoleCommand *) * num_commands);
982 
983  memcpy(cat_sorted_commands, name_sorted_commands, sizeof(ConsoleCommand *) * num_commands);
984 
985  qsort(cat_sorted_commands, num_commands, sizeof(ConsoleCommand *), sort_by_category);
986 
987  /* TODO Add to the list of tab-completion items. */
988 }
989 
990 #ifndef tolower
991 #define tolower(C) (((C) >= 'A' && (C) <= 'Z')? (C) - 'A' + 'a': (C))
992 #endif
993 
998 const ConsoleCommand * find_command(const char * cmd)
999 {
1000  ConsoleCommand ** asp_p = NULL, dummy;
1001  ConsoleCommand * dummy_p;
1002  ConsoleCommand * asp;
1003  char *cp, *cmd_cpy;
1004  cmd_cpy = g_strdup(cmd);
1005 
1006  for (cp=cmd_cpy; *cp; cp++) {
1007  *cp =tolower(*cp);
1008  }
1009 
1010  dummy.name = cmd_cpy;
1011  dummy_p = &dummy;
1012  asp_p = bsearch(
1013  (void *)&dummy_p,
1014  (void *)name_sorted_commands,
1015  num_commands,
1016  sizeof(ConsoleCommand *),
1017  sort_by_name);
1018 
1019  if (asp_p == NULL) {
1020  free(cmd_cpy);
1021  return NULL;
1022  }
1023 
1024  asp = *asp_p;
1025 
1026  /* TODO The server's find_command() searches first the commands,
1027  then the emotes. We might have to do something similar someday, too. */
1028  /* if (asp == NULL) search something else? */
1029 
1030  free(cmd_cpy);
1031 
1032  return asp;
1033 }
1034 
1040 {
1041  return cat_sorted_commands;
1042 }
1043 
1053 int handle_local_command(const char* cp, const char * cpnext)
1054 {
1055  const ConsoleCommand * cc = NULL;
1056 
1057  cc = find_command(cp);
1058 
1059  if (cc == NULL) {
1060  return FALSE;
1061  }
1062 
1063  if (cc->dofunc == NULL) {
1064  char buf[MAX_BUF];
1065 
1066  snprintf(buf, MAX_BUF - 1, "Client command %s has no implementation!", cc->name);
1068 
1069  return FALSE;
1070  }
1071 
1072  cc->dofunc(cpnext);
1073 
1074  return TRUE;
1075 }
1076 
1088 void extended_command(const char *ocommand)
1089 {
1090  const char *cp = ocommand;
1091  char *cpnext, command[MAX_BUF];
1092 
1093  if ((cpnext = strchr(cp, ' '))!=NULL) {
1094  int len = cpnext - ocommand;
1095  if (len > (MAX_BUF -1 )) {
1096  len = MAX_BUF-1;
1097  }
1098 
1099  strncpy(command, ocommand, len);
1100  command[len] = '\0';
1101  cp = command;
1102  while (*cpnext == ' ') {
1103  cpnext++;
1104  }
1105  if (*cpnext == 0) {
1106  cpnext = NULL;
1107  }
1108  }
1109  /*
1110  * Try to prevent potential client hang by trying to delete a
1111  * character when there is no character to delete.
1112  * Thus, only send quit command if there is a player to delete.
1113  */
1114  if (cpl.title[0] == '\0' && strcmp(cp, "quit") == 0){
1115  // Bail here, there isn't anything this should be doing.
1116  return;
1117  }
1118 
1119  /* cp now contains the command (everything before first space),
1120  * and cpnext contains everything after that first space. cpnext
1121  * could be NULL.
1122  */
1123 #ifdef HAVE_LUA
1124  if ( script_lua_command(cp, cpnext) ) {
1125  return;
1126  }
1127 #endif
1128 
1129  /* If this isn't a client-side command, send it to the server. */
1130  if (!handle_local_command(cp, cpnext)) {
1131  /* just send the command(s) (if `ocommand' is a compound command */
1132  /* then split it and send each part seperately */
1133  /* TODO Remove this from the server; end of commands.c. */
1134  strncpy(command, ocommand, MAX_BUF-1);
1135  command[MAX_BUF-1]=0;
1136  cp = strtok(command, ";");
1137  while ( cp ) {
1138  while( *cp == ' ' ) {
1139  cp++;
1140  } /* throw out leading spaces; server
1141  does not like them */
1142  send_command(cp, cpl.count, 0);
1143  cp = strtok(NULL, ";");
1144  }
1145  }
1146 }
1147 
1148 /* ------------------------------------------------------------------ */
1149 
1150 /* This list is used for the 'tab' completion, and nothing else.
1151  * Therefore, if it is out of date, it isn't that terrible, but
1152  * ideally it should stay somewhat up to date with regards to
1153  * the commands the server supports.
1154  */
1155 
1156 /* TODO Dynamically generate. */
1157 
1158 static const char *const commands[] = {
1159  "accuse", "afk", "apply", "applymode", "archs", "beg", "bleed", "blush",
1160  "body", "bounce", "bow", "bowmode", "brace", "build", "burp", "cackle", "cast",
1161  "chat", "chuckle", "clap", "cointoss", "cough", "cringe", "cry", "dance",
1162  "disarm", "dm", "dmhide", "drop", "dropall", "east", "examine", "explore",
1163  "fire", "fire_stop", "fix_me", "flip", "frown", "gasp", "get", "giggle",
1164  "glare", "grin", "groan", "growl", "gsay", "help", "hiccup", "hiscore", "hug",
1165  "inventory", "invoke", "killpets", "kiss", "laugh", "lick", "listen", "logs",
1166  "mapinfo", "maps", "mark", "me", "motd", "nod", "north", "northeast",
1167  "northwest", "orcknuckle", "output-count", "output-sync", "party", "peaceful",
1168  "petmode", "pickup", "players", "poke", "pout", "prepare", "printlos", "puke",
1169  "quests", "quit", "ready_skill", "rename", "reply", "resistances",
1170  "rotateshoottype", "run", "run_stop", "save", "say", "scream", "search",
1171  "search-items", "shake", "shiver", "shout", "showpets", "shrug", "shutdown",
1172  "sigh", "skills", "slap", "smile", "smirk", "snap", "sneeze", "snicker",
1173  "sniff", "snore", "sound", "south", "southeast", "southwest", "spit",
1174  "statistics", "stay", "strings", "strut", "sulk", "take", "tell", "thank",
1175  "think", "throw", "time", "title", "twiddle", "use_skill", "usekeys",
1176  "version", "wave", "weather", "west", "whereabouts", "whereami", "whistle",
1177  "who", "wimpy", "wink", "yawn",
1178 };
1179 #define NUM_COMMANDS ((int)(sizeof(commands) / sizeof(char*)))
1180 
1188 const char * complete_command(const char *command)
1189 {
1190  int i, len, display;
1191  const char *match;
1192  static char result[64];
1193  char list[500];
1194 
1195  len = strlen(command);
1196 
1197  if (len == 0) {
1198  return NULL;
1199  }
1200 
1201  display = 0;
1202  strcpy(list, "Matching commands:");
1203 
1204  /* TODO Partial match, e.g.:
1205  If the completion list was:
1206  wear
1207  wet #?
1208 
1209  If we type 'w' then hit tab, put in the e.
1210 
1211  Basically part of bash (readline?)'s behaviour.
1212  */
1213 
1214  match = NULL;
1215 
1216  /* check server side commands */
1217  for (i=0; i<NUM_COMMANDS; i++) {
1218  if (!strncmp(command, commands[i], len)) {
1219  if (display) {
1220  snprintf(list + strlen(list), 499 - strlen(list), " %s", commands[i]);
1221  } else if (match != NULL) {
1222  display = 1;
1223  snprintf(list + strlen(list), 499 - strlen(list), " %s %s", match, commands[i]);
1224  match = NULL;
1225  } else {
1226  match = commands[i];
1227  }
1228  }
1229  }
1230 
1231  /* check client side commands */
1232  for (i=0; i<CommonCommandsSize; i++) {
1233  if (!strncmp(command, CommonCommands[i].name, len)) {
1234  if (display) {
1235  snprintf(list + strlen(list), 499 - strlen(list), " %s", CommonCommands[i].name);
1236  } else if (match != NULL) {
1237  display = 1;
1238  snprintf(list + strlen(list), 499 - strlen(list), " %s %s", match, CommonCommands[i].name);
1239  match = NULL;
1240  } else {
1241  match = CommonCommands[i].name;
1242  }
1243  }
1244  }
1245 
1246  if (match == NULL) {
1247  if (display) {
1248  strncat(list, "\n", 499 - strlen(list));
1249  draw_ext_info(
1251  } else
1253  "No matching command.\n");
1254  /* No match. */
1255  return NULL;
1256  }
1257 
1258  /*
1259  * Append a space to allow typing arguments. For commands without arguments
1260  * the excess space should be stripped off automatically.
1261  */
1262  snprintf(result, sizeof(result), "%s ", match);
1263 
1264  return result;
1265 }
1266 
1267 #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:1053
static const char * help_unbind(void)
Definition: p_cmd.c:539
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:575
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:165
CommFunc dofunc
Definition: p_cmd.h:60
#define NUM_COMMANDS
Definition: p_cmd.c:1179
#define HELP_MAGICMAP_LONG
Definition: chelp.h:55
item * ob
Player object.
Definition: client.h:309
void metaserver_show(int show_selection)
Show the metaservers to the player.
Definition: metaserver.c:904
const char * get_category_name(CommCat cat)
Definition: p_cmd.c:366
static const char *const commands[]
Definition: p_cmd.c:1158
CommCat cat
Definition: p_cmd.h:59
static const char * help_showweight(void)
Definition: p_cmd.c:653
#define CONFIG_FOODBEEP
Definition: client.h:178
void init_commands(void)
Fills some internal arrays.
Definition: p_cmd.c:946
#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:605
void close_server_connection()
Closes the connection to the server.
Definition: client.c:181
int meta_port
Definition: client.c:58
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:590
static const char * help_metaserver(void)
Definition: p_cmd.c:618
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
char * meta_server
Definition: client.c:50
Client_Player cpl
Player object.
Definition: client.c:70
static void do_metaserver(const char *ignored)
Definition: p_cmd.c:477
#define CONFIG_CWINDOW
Definition: client.h:161
static const char * help_scriptkill(void)
Definition: p_cmd.c:639
static const char * help_magicmap(void)
Definition: p_cmd.c:547
const int CommonCommandsSize
Definition: p_cmd.c:886
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:1088
gint16 want_config[CONFIG_NUMS]
Definition: init.c:39
int num_commands
Definition: p_cmd.c:896
static void do_take(const char *used)
Definition: p_cmd.c:509
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:1188
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:43
void script_list(void)
Definition: script.c:498
static int sort_by_category(const void *a_, const void *b_)
Definition: p_cmd.c:930
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:901
#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:906
static ConsoleCommand CommonCommands[]
Definition: p_cmd.c:703
static void do_num_free_items(const char *ignored)
Definition: p_cmd.c:518
void print_inventory(item *op)
Definition: item.c:678
const ConsoleCommand * find_command(const char *cmd)
Definition: p_cmd.c:998
#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:531
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:583
void command_show(const char *params)
Definition: inventory.c:613
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:500
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
int metaserver_get_info(char *metaserver, int meta_port)
This contacts the metaserver and gets the list of servers.
Definition: metaserver.c:886
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:913
static void do_inv(const char *ignored)
Definition: p_cmd.c:462
static const char * help_script(void)
Definition: p_cmd.c:580
void unbind_key(const char *params)
Definition: keys.c:1463
static ConsoleCommand ** cat_sorted_commands
Definition: p_cmd.c:921
#define tolower(C)
Definition: p_cmd.c:991
static const char * help_inv(void)
Definition: p_cmd.c:555
static void do_script_list(const char *ignored)
Definition: p_cmd.c:410
static void do_savedefaults(const char *ignored)
Definition: p_cmd.c:491
static const char * help_cwindow(void)
Definition: p_cmd.c:563
#define MSG_TYPE_CLIENT_METASERVER
Metaserver messages.
Definition: newclient.h:690
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:1039
void set_scroll(const char *s)
A stub function that does nothing.
Definition: info.c:1332