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