PTLib  Version 2.14.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cli.h
Go to the documentation of this file.
1 /*
2  * cli.h
3  *
4  * Command line interpreter
5  *
6  * Copyright (C) 2006-2008 Post Increment
7  *
8  * The contents of this file are subject to the Mozilla Public License
9  * Version 1.0 (the "License"); you may not use this file except in
10  * compliance with the License. You may obtain a copy of the License at
11  * http://www.mozilla.org/MPL/
12  *
13  * Software distributed under the License is distributed on an "AS IS"
14  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
15  * the License for the specific language governing rights and limitations
16  * under the License.
17  *
18  * The Original Code is WOpenMCU
19  *
20  * The Initial Developer of the Original Code is Post Increment
21  *
22  * Contributor(s): Craig Southeren (craigs@postincrement.com)
23  * Robert Jongbloed (robertj@voxlucida.com.au)
24  *
25  * Portions of this code were written by Post Increment (http://www.postincrement.com)
26  * with the assistance of funding from US Joint Forces Command Joint Concept Development &
27  * Experimentation (J9) http://www.jfcom.mil/about/abt_j9.htm
28  *
29  * Further assistance for enhancements from Imagicle spa
30  *
31  * $Revision: 32045 $
32  * $Author: rjongbloed $
33  * $Date: 2014-06-03 16:39:21 +1000 (Tue, 03 Jun 2014) $
34  */
35 
36 #ifndef PTLIB_CLI_H
37 #define PTLIB_CLI_H
38 
39 #include <ptlib.h>
40 
41 #if P_CLI
42 
43 #include <ptlib/sockets.h>
44 #include <ptclib/vartype.h>
45 
46 #include <list>
47 
48 
60 class PCLI : public PObject
61 {
62  PCLASSINFO(PCLI, PObject);
63  public:
64  class Context;
65 
68  class Context : public PIndirectChannel
69  {
70  public:
75  Context(
76  PCLI & cli
77  );
78 
82  virtual ~Context();
84 
101  virtual PBoolean Write(
102  const void * buf,
103  PINDEX len
104  );
106 
111  bool Start();
112 
116  void Stop();
117 
122  bool Run();
123 
129  virtual void OnStart();
130 
136  virtual void OnStop();
137 
140  virtual bool WritePrompt();
141 
145  virtual bool ReadAndProcessInput();
146 
150  virtual bool ProcessInput(int ch);
151 
157  virtual bool EchoInput(char ch);
158 
165  virtual void OnCompletedLine();
167 
172  PCLI & GetCLI() const { return m_cli; }
173 
176  bool IsProcessingCommand() const { return m_state == e_ProcessingCommand; }
178 
179  protected:
180  PDECLARE_NOTIFIER(PThread, Context, ThreadMain);
181  bool InternalMoveCursor(bool left, PINDEX count);
182  bool InternalEchoCommandLine(PINDEX echoPosition, PINDEX moveLeftCount);
183  bool InternalMoveHistoryCommand(int direction);
184 
185  PCLI & m_cli;
186  PString m_commandLine;
187  PINDEX m_editPosition;
188  bool m_ignoreNextEOL;
189  PStringList m_commandHistory;
190  PINDEX m_historyPosition;
191  PThread * m_thread;
192 
193  enum State {
194  e_Username,
195  e_Password,
196  e_CommandEntry,
197  e_ProcessingCommand
198  } m_state;
199  PString m_enteredUsername;
200  };
201 
204  class Arguments : public PArgList
205  {
206  public:
209  Arguments(
210  Context & context,
211  const PString & rawLine
212  );
214 
219  Context & WriteUsage();
220 
223  Context & WriteError(
224  const PString & error = PString::Empty()
225  );
227 
232  Context & GetContext() const { return m_context; }
234 
235  protected:
236  Context & m_context;
237  PString m_usage;
238 
239  friend class PCLI;
240  };
241 
242 
247  PCLI(
248  const char * prompt = NULL
249  );
250 
254  virtual ~PCLI();
256 
267  virtual bool Start(
268  bool runInBackground = true
269  );
270 
275  virtual void Stop();
276 
282  Context * StartContext(
283  PChannel * channel,
284  bool autoDelete = true,
285  bool runInBackground = true
286  ) { return StartContext(channel, channel, autoDelete, autoDelete, runInBackground); }
287  Context * StartContext(
288  PChannel * readChannel,
289  PChannel * writeChannel,
290  bool autoDeleteRead = true,
291  bool autoDeleteWrite = true,
292  bool runInBackground = true
293  );
294 
298  virtual Context * StartForeground();
299 
305  bool Run(
306  PChannel & channel
307  ) { return Run(&channel, &channel, false, false); }
308  bool Run(
309  PChannel * channel,
310  bool autoDelete = true
311  ) { return Run(channel, channel, autoDelete, autoDelete); }
312  bool Run(
313  PChannel * readChannel,
314  PChannel * writeChannel,
315  bool autoDeleteRead = true,
316  bool autoDeleteWrite = true
317  );
318 
324  bool RunContext(
325  Context * context
326  ) { return context != NULL && context->Run(); }
327 
331  virtual Context * CreateContext();
332 
336  virtual Context * AddContext(
337  Context * context = NULL
338  );
339 
343  virtual void RemoveContext(
344  Context * context
345  );
346 
349  virtual void GarbageCollection();
350 
358  virtual void OnReceivedLine(
359  Arguments & line
360  );
361 
374  virtual bool OnLogIn(
375  const PString & username,
376  const PString & password
377  );
378 
381  void Broadcast(
382  const PString & message
383  ) const;
384 
395  bool SetCommand(
396  const char * command,
397  const PNotifier & notifier,
398  const char * help = NULL,
399  const char * usage = NULL,
400  const char * argSpec = NULL
401  );
402 
405  bool SetCommand(
406  const char * command,
407  bool & value,
408  const char * name,
409  const char * help = NULL,
410  const PNotifier & notifier = PNotifier()
411  );
412 
415  bool SetCommand(
416  const char * command,
417  const PVarType & value,
418  const char * name,
419  const PVarType & minValue,
420  const PVarType & maxValue,
421  const char * help = NULL,
422  const PNotifier & notifier = PNotifier()
423  );
424 
425  template <typename TYPE>
426  bool SetCommand(
427  const char * command,
428  TYPE & value,
429  const char * name,
430  TYPE minValue,
431  TYPE maxValue = INT_MAX,
432  const char * help = NULL,
433  const PNotifier & notifier = PNotifier()
434  )
435  {
436  return SetCommand(command, PRefVar<TYPE>(value), name, minValue, maxValue, help, notifier);
437  }
438 
441  virtual void ShowHelp(
442  Context & context,
443  const PArgList & partial
444  );
446 
452  const PString & GetNewLine() const { return m_newLine; }
453 
457  void SetNewLine(const PString & newLine) { m_newLine = newLine; }
458 
462  bool GetRequireEcho() const { return m_requireEcho; }
463 
467  void SetRequireEcho(bool requireEcho) { m_requireEcho = requireEcho; }
468 
472  const PIntArray & GetEditCodes() const { return m_editCodes; }
473 
477  void SetEditCodes(const PIntArray & editCodes) { m_editCodes = editCodes; }
478 
482  const PIntArray & GetEraseCodes() const { return m_eraseCodes; }
483 
487  void SetEraseCodes(const PIntArray & eraseCodes) { m_eraseCodes = eraseCodes; }
488 
492  const PIntArray & GetLeftCodes() const { return m_leftCodes; }
493 
497  void SetLeftCodes(const PIntArray & leftCodes) { m_leftCodes = leftCodes; }
498 
502  const PIntArray & GetRightCodes() const { return m_rightCodes; }
503 
507  void SetRightCodes(const PIntArray & rightCodes) { m_rightCodes = rightCodes; }
508 
512  const PIntArray & GetBeginCodes() const { return m_beginCodes; }
513 
517  void SetBeginCodes(const PIntArray & beginCodes) { m_beginCodes = beginCodes; }
518 
522  const PIntArray & GetEndCodes() const { return m_endCodes; }
523 
527  void SetEndCodes(const PIntArray & endCodes) { m_endCodes = endCodes; }
528 
532  const PIntArray & GetPrevCmdCodes() const { return m_prevCmdCodes; }
533 
537  void SetPrevCmdCodes(const PIntArray & prevCmdCodes) { m_prevCmdCodes = prevCmdCodes; }
538 
542  const PIntArray & GetNextCmdCodes() const { return m_nextCmdCodes; }
543 
547  void SetNextCmdCodes(const PIntArray & nextCmdCodes) { m_nextCmdCodes = nextCmdCodes; }
548 
552  void SetAutoFillCodes(const PIntArray & autoFillCodes) { m_autoFillCodes = autoFillCodes; }
553 
557  const PIntArray & GetAutoFillCodes() const { return m_autoFillCodes; }
558 
562  const PString & GetPrompt() const { return m_prompt; }
563 
567  void SetPrompt(const PString & prompt) { m_prompt = prompt; }
568 
572  const PString & GetUsernamePrompt() const { return m_usernamePrompt; }
573 
577  void SetUsernamePrompt(const PString & prompt) { m_usernamePrompt = prompt; }
578 
582  const PString & GetPasswordPrompt() const { return m_passwordPrompt; }
583 
587  void SetPasswordPrompt(const PString & prompt) { m_passwordPrompt = prompt; }
588 
592  const PString & GetUsername() const { return m_username; }
593 
597  void SetUsername(const PString & username) { m_username = username; }
598 
602  const PString & GetPassword() const { return m_password; }
603 
607  void SetPassword(const PString & password) { m_password = password; }
608 
612  const PCaselessString & GetCommentCommand() const { return m_commentCommand; }
613 
617  void SetCommentCommand(const PCaselessString & commentCommand) { m_commentCommand = commentCommand; }
618 
622  const PCaselessString & GetExitCommand() const { return m_exitCommand; }
623 
627  void SetExitCommand(const PCaselessString & exitCommand) { m_exitCommand = exitCommand; }
628 
632  const PCaselessString & GetHelpCommand() const { return m_helpCommand; }
633 
637  void SetHelpCommand(const PCaselessString & helpCommand) { m_helpCommand = helpCommand; }
638 
643  const PString & GetHelpOnHelp() const { return m_helpOnHelp; }
644 
649  void SetHelpOnHelp(const PCaselessString & helpOnHelp) { m_helpOnHelp = helpOnHelp; }
650 
654  const PCaselessString & GetRepeatCommand() const { return m_repeatCommand; }
655 
659  void SetRepeatCommand(const PCaselessString & repeatCommand) { m_repeatCommand = repeatCommand; }
660 
664  const PCaselessString & GetHistoryCommand() const { return m_historyCommand; }
665 
669  void SetHistoryCommand(const PCaselessString & historyCommand) { m_historyCommand = historyCommand; }
670 
674  const PString & GetNoHistoryError() const { return m_noHistoryError; }
675 
679  void SetNoHistoryError(const PString & noHistoryError) { m_noHistoryError = noHistoryError; }
680 
684  const PString & GetCommandUsagePrefix() const { return m_commandUsagePrefix; }
685 
689  void SetCommandUsagePrefix(const PString & commandUsagePrefix) { m_commandUsagePrefix = commandUsagePrefix; }
690 
694  const PString & GetCommandErrorPrefix() const { return m_commandErrorPrefix; }
695 
699  void SetCommandErrorPrefix(const PString & commandErrorPrefix) { m_commandErrorPrefix = commandErrorPrefix; }
700 
704  const PString & GetUnknownCommandError() const { return m_unknownCommandError; }
705 
709  void SetUnknownCommandError(const PString & unknownCommandError) { m_unknownCommandError = unknownCommandError; }
710 
714  const PString & GetAmbiguousCommandError() const { return m_ambiguousCommandError; }
715 
719  void SetAmbiguousCommandError(const PString & ambiguousCommandError) { m_ambiguousCommandError = ambiguousCommandError; }
720 
724  const PCaselessString & GetScriptCommand() const { return m_scriptCommand; }
725 
729  void SetScriptCommand(const PCaselessString & scriptCommand) { m_scriptCommand = scriptCommand; }
730 
734  const PString & GetNoScriptError() const { return m_noScriptError; }
735 
739  void SetNoScriptError(const PString & noScriptError) { m_noScriptError = noScriptError; }
741 
742 
743  protected:
744  PString m_newLine;
745  bool m_requireEcho;
746  PIntArray m_editCodes;
747  PIntArray m_eraseCodes;
748  PIntArray m_leftCodes;
749  PIntArray m_rightCodes;
750  PIntArray m_beginCodes;
751  PIntArray m_endCodes;
752  PIntArray m_prevCmdCodes;
753  PIntArray m_nextCmdCodes;
754  PIntArray m_autoFillCodes;
755  PString m_prompt;
756  PString m_usernamePrompt;
757  PString m_passwordPrompt;
758  PString m_username;
759  PString m_password;
760  PCaselessString m_commentCommand;
761  PCaselessString m_exitCommand;
762  PCaselessString m_helpCommand;
763  PString m_helpOnHelp;
764  PCaselessString m_repeatCommand;
765  PCaselessString m_historyCommand;
766  PString m_noHistoryError;
767  PString m_commandUsagePrefix;
768  PString m_commandErrorPrefix;
769  PString m_unknownCommandError;
770  PString m_ambiguousCommandError;
771  PCaselessString m_scriptCommand;
772  PString m_noScriptError;
773 
774  struct InternalCommand
775  {
776  InternalCommand(const PNotifier & notifier, const char * help, const char * usage, const char * argSpec, const char * varName);
777  InternalCommand(const InternalCommand & other);
778  ~InternalCommand();
779  bool IsMatch(const PArgList & args, bool partial = false) const;
780  bool operator<(const InternalCommand & other) const;
781 
782  PStringArray m_words;
783  PString m_command;
784  PNotifier m_notifier;
785  PString m_help;
786  PString m_usage;
787  PString m_argSpec;
788  PString m_varName;
789  PVarType * m_variable;
790  PVarType * m_minimum;
791  PVarType * m_maximum;
792  };
793  typedef std::set<InternalCommand> Commands_t;
794  Commands_t m_commands;
795  bool InternalSetCommand(const char * commands, const InternalCommand & info);
796 
797  virtual void OnSetBooleanCommand(Arguments & args, const InternalCommand & cmd);
798  virtual void OnSetIntegerCommand(Arguments & args, const InternalCommand & cmd);
799 
800  typedef std::list<Context *> ContextList_t;
801  ContextList_t m_contextList;
802  PMutex m_contextMutex;
803 };
804 
805 
808 class PCLIStandard : public PCLI
809 {
810  public:
815  PCLIStandard(
816  const char * prompt = NULL
817  );
819 
825  virtual Context * StartForeground();
827 
833  bool RunScript(
834  PChannel & channel
835  ) { return RunScript(&channel, false); }
836  bool RunScript(
837  PChannel * channel,
838  bool autoDelete = true
839  );
841 };
842 
843 
848 class PCLISocket : public PCLI
849 {
850  public:
853  PCLISocket(
854  WORD port = 0,
855  const char * prompt = NULL,
856  bool singleThreadForAll = false
857  );
858  ~PCLISocket();
860 
867  virtual bool Start(
868  bool runInBackground = true
869  );
870 
878  virtual void Stop();
879 
883  virtual Context * AddContext(
884  Context * context = NULL
885  );
886 
890  virtual void RemoveContext(
891  Context * context
892  );
894 
899  bool Listen(
900  WORD port = 0
901  );
902 
905  WORD GetPort() const { return m_listenSocket.GetPort(); }
907 
908  protected:
909  PDECLARE_NOTIFIER(PThread, PCLISocket, ThreadMain);
910  bool HandleSingleThreadForAll();
911  bool HandleIncoming();
912  virtual PTCPSocket * CreateSocket();
913 
914  bool m_singleThreadForAll;
915 
916  PTCPSocket m_listenSocket;
917  PThread * m_thread;
918 
919  typedef std::map<PSocket *, Context *> ContextMap_t;
920  ContextMap_t m_contextBySocket;
921 };
922 
923 
924 #if P_TELNET
925 
929 class PCLITelnet : public PCLISocket
930 {
931  public:
934  PCLITelnet(
935  WORD port = 0,
936  const char * prompt = NULL,
937  bool singleThreadForAll = false
938  );
940 
941  protected:
942  virtual PTCPSocket * CreateSocket();
943 };
944 #endif // P_TELNET
945 
946 
947 #if P_CURSES
948 
953 class PCLICurses : public PCLI
954 {
955  public:
958  PCLICurses();
959  ~PCLICurses();
961 
967  virtual Context * StartForeground();
968 
972  virtual Context * CreateContext();
974 
975  void GetScreenSize(
976  unsigned & rows,
977  unsigned & cols
978  ) { rows = m_maxRows; cols = m_maxCols; }
979 
980  P_DECLARE_ENUM(Borders,
981  NoBorder,
982  FullBorder,
983  BorderAbove,
984  BorderBelow,
985  BorderLeft,
986  BorderRight
987  );
988 
989  class Window : public PChannel
990  {
991  protected:
992  PCLICurses & m_owner;
993  Borders m_border;
994  bool m_focus;
995  bool m_pageMode;
996  unsigned m_pagedRows;
997 
998  Window(PCLICurses & owner, Borders border);
999 
1000  public:
1001  // Overrides from PChannel
1002  virtual PBoolean Write(const void * data, PINDEX length);
1003 
1004  // New functions
1005  virtual bool FillChar(
1006  unsigned row,
1007  unsigned col,
1008  char ch,
1009  unsigned count
1010  ) = 0;
1011 
1012  virtual void SetPosition(
1013  unsigned row,
1014  unsigned col
1015  ) = 0;
1016  virtual void GetPosition(
1017  unsigned & row,
1018  unsigned & col
1019  ) = 0;
1020 
1021  virtual void SetSize(
1022  unsigned rows,
1023  unsigned cols,
1024  Borders border = NumBorders
1025  ) = 0;
1026  virtual void GetSize(
1027  unsigned & rows,
1028  unsigned & cols,
1029  bool includeBorder
1030  ) = 0;
1031 
1032  virtual void SetCursor(
1033  unsigned row,
1034  unsigned col
1035  ) = 0;
1036  virtual void GetCursor(
1037  unsigned & row,
1038  unsigned & col
1039  ) = 0;
1040 
1041  virtual void Refresh() = 0;
1042  virtual void Clear() = 0;
1043  virtual void Scroll(int n = 1) = 0;
1044 
1045  void SetPageMode(
1046  bool on = true
1047  );
1048 
1049  bool GetPageMode() const { return m_pageMode; }
1050 
1051  virtual void SetFocus();
1052  bool HasFocus() const { return m_focus; }
1053  };
1054 
1058  Window & NewWindow(
1059  unsigned row,
1060  unsigned col,
1061  unsigned rows,
1062  unsigned cols,
1063  Borders border = NoBorder
1064  );
1065 
1066  void RemoveWindow(
1067  Window & wnd
1068  );
1069 
1070  void RemoveWindow(
1071  PINDEX idx
1072  );
1073 
1074  PINDEX GetWindowCount() const { return m_windows.GetSize(); }
1075 
1076  Window * GetWindow(
1077  PINDEX idx
1078  ) { return dynamic_cast<Window *>(m_windows.GetAt(idx)); }
1079 
1080  Window & operator[](PINDEX idx) const { return m_windows[idx]; }
1081 
1082  Window * GetFocusWindow() const;
1083 
1084  virtual void Refresh();
1085 
1086  virtual bool WaitPage();
1087 
1091  const PString & GetPageWaitPrompt() const { return m_pageWaitPrompt; }
1092 
1096  void SetPageWaitPrompt(const PString & prompt) { m_pageWaitPrompt = prompt; }
1097 
1098  protected:
1099  void Construct();
1100 
1101  PString m_pageWaitPrompt;
1102 
1103  PArray<Window> m_windows;
1104  unsigned m_maxRows;
1105  unsigned m_maxCols;
1106 };
1107 #endif // P_CURSES
1108 
1109 #endif // P_CLI
1110 
1111 #endif // PTLIB_CLI_H
1112 
1113 
1114 // End Of File ///////////////////////////////////////////////////////////////