PTLib  Version 2.18.8
 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 
32 #ifndef PTLIB_CLI_H
33 #define PTLIB_CLI_H
34 
35 #include <ptlib.h>
36 
37 #if P_CLI
38 
39 #include <ptlib/sockets.h>
40 #include <ptclib/vartype.h>
41 
42 #include <list>
43 
44 
56 class PCLI : public PObject
57 {
58  PCLASSINFO(PCLI, PObject);
59  public:
60  class Context;
61 
64  class Context : public PIndirectChannel
65  {
66  public:
71  Context(
72  PCLI & cli
73  );
74 
78  virtual ~Context();
80 
97  virtual PBoolean Write(
98  const void * buf,
99  PINDEX len
100  );
102 
107  bool Start();
108 
112  void Stop();
113 
118  bool Run();
119 
125  virtual void OnStart();
126 
132  virtual void OnStop();
133 
136  virtual bool WritePrompt();
137 
141  virtual bool ReadAndProcessInput();
142 
146  virtual bool ProcessInput(int ch);
147 
153  virtual bool EchoInput(char ch);
154 
161  virtual void OnCompletedLine();
162 
165  virtual bool GetTerminalSize(
166  unsigned & rows,
167  unsigned & columns
168  );
169 
171  virtual void Broadcast(
172  const PString & message
173  );
175 
180  PCLI & GetCLI() const { return m_cli; }
181 
184  bool IsProcessingCommand() const { return m_state == e_ProcessingCommand; }
186 
187  protected:
188  PDECLARE_NOTIFIER(PThread, Context, ThreadMain);
189  bool InternalMoveCursor(bool left, PINDEX count);
190  bool InternalEchoCommandLine(PINDEX echoPosition, PINDEX moveLeftCount);
191  bool InternalMoveHistoryCommand(int direction);
192  bool InternalWrite(const char * str, PINDEX len, PINDEX & written);
193 
194  PCLI & m_cli;
195  PString m_commandLine;
196  PINDEX m_editPosition;
197  bool m_ignoreNextEOL;
198  PStringList m_commandHistory;
199  PINDEX m_historyPosition;
200  PThread * m_thread;
201  int m_pagedLines;
202 
203  enum State {
204  e_Username,
205  e_Password,
206  e_CommandEntry,
207  e_ProcessingCommand
208  } m_state;
209  PString m_enteredUsername;
210  };
211 
214  class Arguments : public PArgList
215  {
216  public:
219  Arguments(
220  Context & context,
221  const PString & rawLine
222  );
224 
229  Context & WriteUsage();
230 
233  Context & WriteError(
234  const PString & error = PString::Empty()
235  );
237 
242  Context & GetContext() const { return m_context; }
244 
245  protected:
246  Context & m_context;
247  PString m_usage;
248 
249  friend class PCLI;
250  };
251 
252 
257  PCLI(
258  const char * prompt = NULL
259  );
260 
264  virtual ~PCLI();
266 
277  virtual bool Start(
278  bool runInBackground = true
279  );
280 
285  virtual void Stop();
286 
292  Context * StartContext(
293  PChannel * channel,
294  bool autoDelete = true,
295  bool runInBackground = true
296  ) { return StartContext(channel, channel, autoDelete, autoDelete, runInBackground); }
297  Context * StartContext(
298  PChannel * readChannel,
299  PChannel * writeChannel,
300  bool autoDeleteRead = true,
301  bool autoDeleteWrite = true,
302  bool runInBackground = true
303  );
304 
308  virtual Context * StartForeground();
309 
315  bool Run(
316  PChannel & channel
317  ) { return Run(&channel, &channel, false, false); }
318  bool Run(
319  PChannel * channel,
320  bool autoDelete = true
321  ) { return Run(channel, channel, autoDelete, autoDelete); }
322  bool Run(
323  PChannel * readChannel,
324  PChannel * writeChannel,
325  bool autoDeleteRead = true,
326  bool autoDeleteWrite = true
327  );
328 
334  bool RunContext(
335  Context * context
336  ) { return context != NULL && context->Run(); }
337 
341  virtual Context * CreateContext();
342 
346  virtual Context * AddContext(
347  Context * context = NULL
348  );
349 
353  virtual void RemoveContext(
354  Context * context
355  );
356 
359  virtual void GarbageCollection();
360 
368  virtual void OnReceivedLine(
369  Arguments & line
370  );
371 
384  virtual bool OnLogIn(
385  const PString & username,
386  const PString & password
387  );
388 
391  void Broadcast(
392  const PString & message
393  ) const;
394 
405  bool SetCommand(
406  const char * command,
407  const PNotifier & notifier,
408  const char * help = NULL,
409  const char * usage = NULL,
410  const char * argSpec = NULL
411  );
412 
415  bool SetCommand(
416  const char * command,
417  bool & value,
418  const char * name,
419  const char * help = NULL,
420  const PNotifier & notifier = PNotifier()
421  );
422 
425  bool SetCommand(
426  const char * command,
427  const PVarType & value,
428  const char * name,
429  const PVarType & minValue,
430  const PVarType & maxValue,
431  const char * help = NULL,
432  const PNotifier & notifier = PNotifier()
433  );
434 
435  template <typename TYPE>
436  bool SetCommand(
437  const char * command,
438  TYPE & value,
439  const char * name,
440  TYPE minValue,
441  TYPE maxValue = INT_MAX,
442  const char * help = NULL,
443  const PNotifier & notifier = PNotifier()
444  )
445  {
446  return SetCommand(command, PRefVar<TYPE>(value), name, minValue, maxValue, help, notifier);
447  }
448 
451  virtual void ShowHelp(
452  Context & context,
453  const PArgList & partial
454  );
456 
462  const PString & GetNewLine() const { return m_newLine; }
463 
467  void SetNewLine(const PString & newLine);
468 
472  bool GetRequireEcho() const { return m_requireEcho; }
473 
477  void SetRequireEcho(bool requireEcho) { m_requireEcho = requireEcho; }
478 
482  const PIntArray & GetEditCodes() const { return m_editCodes; }
483 
487  void SetEditCodes(const PIntArray & editCodes) { m_editCodes = editCodes; }
488 
492  const PIntArray & GetEraseCodes() const { return m_eraseCodes; }
493 
497  void SetEraseCodes(const PIntArray & eraseCodes) { m_eraseCodes = eraseCodes; }
498 
502  const PIntArray & GetLeftCodes() const { return m_leftCodes; }
503 
507  void SetLeftCodes(const PIntArray & leftCodes) { m_leftCodes = leftCodes; }
508 
512  const PIntArray & GetRightCodes() const { return m_rightCodes; }
513 
517  void SetRightCodes(const PIntArray & rightCodes) { m_rightCodes = rightCodes; }
518 
522  const PIntArray & GetBeginCodes() const { return m_beginCodes; }
523 
527  void SetBeginCodes(const PIntArray & beginCodes) { m_beginCodes = beginCodes; }
528 
532  const PIntArray & GetEndCodes() const { return m_endCodes; }
533 
537  void SetEndCodes(const PIntArray & endCodes) { m_endCodes = endCodes; }
538 
542  const PIntArray & GetPrevCmdCodes() const { return m_prevCmdCodes; }
543 
547  void SetPrevCmdCodes(const PIntArray & prevCmdCodes) { m_prevCmdCodes = prevCmdCodes; }
548 
552  const PIntArray & GetNextCmdCodes() const { return m_nextCmdCodes; }
553 
557  void SetNextCmdCodes(const PIntArray & nextCmdCodes) { m_nextCmdCodes = nextCmdCodes; }
558 
562  void SetAutoFillCodes(const PIntArray & autoFillCodes) { m_autoFillCodes = autoFillCodes; }
563 
567  const PIntArray & GetAutoFillCodes() const { return m_autoFillCodes; }
568 
572  const PString & GetPrompt() const { return m_prompt; }
573 
577  void SetPrompt(const PString & prompt) { m_prompt = prompt; }
578 
582  const PString & GetUsernamePrompt() const { return m_usernamePrompt; }
583 
587  void SetUsernamePrompt(const PString & prompt) { m_usernamePrompt = prompt; }
588 
592  const PString & GetPasswordPrompt() const { return m_passwordPrompt; }
593 
597  void SetPasswordPrompt(const PString & prompt) { m_passwordPrompt = prompt; }
598 
602  const PString & GetUsername() const { return m_username; }
603 
607  void SetUsername(const PString & username) { m_username = username; }
608 
612  const PString & GetPassword() const { return m_password; }
613 
617  void SetPassword(const PString & password) { m_password = password; }
618 
622  const PCaselessString & GetCommentCommand() const { return m_commentCommand; }
623 
627  void SetCommentCommand(const PCaselessString & commentCommand) { m_commentCommand = commentCommand; }
628 
632  const PCaselessString & GetExitCommand() const { return m_exitCommand; }
633 
637  void SetExitCommand(const PCaselessString & exitCommand) { m_exitCommand = exitCommand; }
638 
642  const PCaselessString & GetHelpCommand() const { return m_helpCommand; }
643 
647  void SetHelpCommand(const PCaselessString & helpCommand) { m_helpCommand = helpCommand; }
648 
653  const PString & GetHelpOnHelp() const { return m_helpOnHelp; }
654 
659  void SetHelpOnHelp(const PCaselessString & helpOnHelp) { m_helpOnHelp = helpOnHelp; }
660 
664  const PCaselessString & GetRepeatCommand() const { return m_repeatCommand; }
665 
669  void SetRepeatCommand(const PCaselessString & repeatCommand) { m_repeatCommand = repeatCommand; }
670 
674  const PCaselessString & GetHistoryCommand() const { return m_historyCommand; }
675 
679  void SetHistoryCommand(const PCaselessString & historyCommand) { m_historyCommand = historyCommand; }
680 
684  const PString & GetNoHistoryError() const { return m_noHistoryError; }
685 
689  void SetNoHistoryError(const PString & noHistoryError) { m_noHistoryError = noHistoryError; }
690 
694  const PString & GetCommandUsagePrefix() const { return m_commandUsagePrefix; }
695 
699  void SetCommandUsagePrefix(const PString & commandUsagePrefix) { m_commandUsagePrefix = commandUsagePrefix; }
700 
704  const PString & GetCommandErrorPrefix() const { return m_commandErrorPrefix; }
705 
709  void SetCommandErrorPrefix(const PString & commandErrorPrefix) { m_commandErrorPrefix = commandErrorPrefix; }
710 
714  const PString & GetUnknownCommandError() const { return m_unknownCommandError; }
715 
719  void SetUnknownCommandError(const PString & unknownCommandError) { m_unknownCommandError = unknownCommandError; }
720 
724  const PString & GetAmbiguousCommandError() const { return m_ambiguousCommandError; }
725 
729  void SetAmbiguousCommandError(const PString & ambiguousCommandError) { m_ambiguousCommandError = ambiguousCommandError; }
730 
734  const PCaselessString & GetScriptCommand() const { return m_scriptCommand; }
735 
739  void SetScriptCommand(const PCaselessString & scriptCommand) { m_scriptCommand = scriptCommand; }
740 
744  const PString & GetNoScriptError() const { return m_noScriptError; }
745 
749  void SetNoScriptError(const PString & noScriptError) { m_noScriptError = noScriptError; }
750 
755  int GetPagerLines() const { return m_pagerLines; }
756 
761  void SetPagerLines(int lines) { m_pagerLines = lines; }
762 
766  const PString & GetPageWaitPrompt() const { return m_pagerWaitPrompt; }
767 
771  void SetPageWaitPrompt(const PString & prompt) { m_pagerWaitPrompt = prompt; }
772 
776  const PString & GetPagerCommand() const { return m_pagerCommand; }
777 
781  void SetPagerCommand(const PString & cmd) { m_pagerCommand = cmd; }
783 
784 
785  protected:
786  PString m_newLine;
787  bool m_requireEcho;
788  PIntArray m_editCodes;
789  PIntArray m_eraseCodes;
790  PIntArray m_leftCodes;
791  PIntArray m_rightCodes;
792  PIntArray m_beginCodes;
793  PIntArray m_endCodes;
794  PIntArray m_prevCmdCodes;
795  PIntArray m_nextCmdCodes;
796  PIntArray m_autoFillCodes;
797  PString m_prompt;
798  PString m_usernamePrompt;
799  PString m_passwordPrompt;
800  PString m_username;
801  PString m_password;
802  PCaselessString m_commentCommand;
803  PCaselessString m_exitCommand;
804  PCaselessString m_helpCommand;
805  PString m_helpOnHelp;
806  PCaselessString m_repeatCommand;
807  PCaselessString m_historyCommand;
808  PString m_noHistoryError;
809  PString m_commandUsagePrefix;
810  PString m_commandErrorPrefix;
811  PString m_unknownCommandError;
812  PString m_ambiguousCommandError;
813  PCaselessString m_scriptCommand;
814  PString m_noScriptError;
815  int m_pagerLines;
816  PString m_pagerWaitPrompt;
817  PCaselessString m_pagerCommand;
818 
819  virtual bool InternalPageWait(Context & context);
820 
821  struct InternalCommand
822  {
823  InternalCommand(const PNotifier & notifier, const char * help, const char * usage, const char * argSpec, const char * varName);
824  InternalCommand(const InternalCommand & other);
825  ~InternalCommand();
826  bool IsMatch(const PArgList & args, bool partial = false) const;
827  bool operator<(const InternalCommand & other) const;
828 
829  PStringArray m_words;
830  PString m_command;
831  PNotifier m_notifier;
832  PString m_help;
833  PString m_usage;
834  PString m_argSpec;
835  PString m_varName;
836  PVarType * m_variable;
837  PVarType * m_minimum;
838  PVarType * m_maximum;
839  };
840  typedef std::set<InternalCommand> Commands_t;
841  Commands_t m_commands;
842  bool InternalSetCommand(const char * commands, const InternalCommand & info);
843 
844  virtual void OnSetBooleanCommand(Arguments & args, const InternalCommand & cmd);
845  virtual void OnSetIntegerCommand(Arguments & args, const InternalCommand & cmd);
846 
847  typedef std::list<Context *> ContextList_t;
848  ContextList_t m_contextList;
849  PDECLARE_MUTEX(m_contextMutex);
850 };
851 
852 
855 class PCLIStandard : public PCLI
856 {
857  public:
862  PCLIStandard(
863  const char * prompt = NULL
864  );
866 
872  virtual Context * StartForeground();
874 
880  bool RunScript(
881  PChannel & channel
882  ) { return RunScript(&channel, false); }
883  bool RunScript(
884  PChannel * channel,
885  bool autoDelete = true
886  );
888 };
889 
890 
895 class PCLISocket : public PCLI
896 {
897  public:
900  PCLISocket(
901  WORD port = 0,
902  const char * prompt = NULL,
903  bool singleThreadForAll = false
904  );
905  ~PCLISocket();
907 
914  virtual bool Start(
915  bool runInBackground = true
916  );
917 
925  virtual void Stop();
926 
930  virtual Context * AddContext(
931  Context * context = NULL
932  );
933 
937  virtual void RemoveContext(
938  Context * context
939  );
941 
946  bool Listen(
947  WORD port = 0
948  );
949 
952  WORD GetPort() const { return m_listenSocket.GetPort(); }
954 
955  protected:
956  PDECLARE_NOTIFIER(PThread, PCLISocket, ThreadMain);
957  bool HandleSingleThreadForAll();
958  bool HandleIncoming();
959  virtual PTCPSocket * CreateSocket();
960 
961  bool m_singleThreadForAll;
962 
963  PTCPSocket m_listenSocket;
964  PThread * m_thread;
965 
966  typedef std::map<PSocket *, Context *> ContextMap_t;
967  ContextMap_t m_contextBySocket;
968 };
969 
970 
971 #if P_TELNET
972 
976 class PCLITelnet : public PCLISocket
977 {
978  public:
981  PCLITelnet(
982  WORD port = 0,
983  const char * prompt = NULL,
984  bool singleThreadForAll = false
985  );
987 
988  protected:
989  virtual PTCPSocket * CreateSocket();
990 };
991 #endif // P_TELNET
992 
993 
994 #if P_CURSES
995 
1000 class PCLICurses : public PCLI
1001 {
1002  public:
1005  PCLICurses();
1006  ~PCLICurses();
1008 
1014  virtual Context * StartForeground();
1015 
1019  virtual Context * CreateContext();
1021 
1022  void GetScreenSize(
1023  unsigned & rows,
1024  unsigned & cols
1025  ) { rows = m_maxRows; cols = m_maxCols; }
1026 
1027  P_DECLARE_ENUM(Borders,
1028  NoBorder,
1029  FullBorder,
1030  BorderAbove,
1031  BorderBelow,
1032  BorderLeft,
1033  BorderRight
1034  );
1035 
1036  class Window : public PChannel
1037  {
1038  protected:
1039  PCLICurses & m_owner;
1040  Borders m_border;
1041  bool m_focus;
1042 
1043  Window(PCLICurses & owner, Borders border);
1044 
1045  public:
1046  // Overrides from PChannel
1047  virtual PString GetName() const { return "CursesWindow"; }
1048  virtual PBoolean Write(const void * data, PINDEX length);
1049 
1050  // New functions
1051  virtual bool FillChar(
1052  unsigned row,
1053  unsigned col,
1054  char ch,
1055  unsigned count
1056  ) = 0;
1057 
1058  virtual void SetPosition(
1059  unsigned row,
1060  unsigned col
1061  ) = 0;
1062  virtual void GetPosition(
1063  unsigned & row,
1064  unsigned & col
1065  ) = 0;
1066 
1067  virtual void SetSize(
1068  unsigned rows,
1069  unsigned cols,
1070  Borders border = NumBorders
1071  ) = 0;
1072  virtual void GetSize(
1073  unsigned & rows,
1074  unsigned & cols,
1075  bool includeBorder
1076  ) = 0;
1077 
1078  virtual void SetCursor(
1079  unsigned row,
1080  unsigned col
1081  ) = 0;
1082  virtual void GetCursor(
1083  unsigned & row,
1084  unsigned & col
1085  ) = 0;
1086 
1087  virtual void Refresh() = 0;
1088  virtual void Clear() = 0;
1089  virtual void Scroll(int n = 1) = 0;
1090 
1091  virtual void SetFocus();
1092  bool HasFocus() const { return m_focus; }
1093  };
1094 
1098  Window & NewWindow(
1099  unsigned row,
1100  unsigned col,
1101  unsigned rows,
1102  unsigned cols,
1103  Borders border = NoBorder
1104  );
1105 
1106  void RemoveWindow(
1107  Window & wnd
1108  );
1109 
1110  void RemoveWindow(
1111  PINDEX idx
1112  );
1113 
1114  PINDEX GetWindowCount() const { return m_windows.GetSize(); }
1115 
1116  Window * GetWindow(
1117  PINDEX idx
1118  ) { return dynamic_cast<Window *>(m_windows.GetAt(idx)); }
1119 
1120  Window & operator[](PINDEX idx) const { return m_windows[idx]; }
1121 
1122  Window * GetFocusWindow() const;
1123 
1124  virtual void Refresh();
1125 
1126  protected:
1127  void Construct();
1128 
1129  virtual bool InternalPageWait(Context & context);
1130 
1131  PArray<Window> m_windows;
1132  unsigned m_maxRows;
1133  unsigned m_maxCols;
1134 };
1135 #endif // P_CURSES
1136 
1137 #endif // P_CLI
1138 
1139 #endif // PTLIB_CLI_H
1140 
1141 
1142 // End Of File ///////////////////////////////////////////////////////////////
#define PCLASSINFO(cls, par)
Declare all the standard PTLib class information.
Definition: object.h:2164
Class specialisation for PNotifierTemplate&lt;P_INT_PTR&gt;
This is a channel that operates indirectly through another channel(s).
Definition: indchan.h:45
This class is a variation of a string that ignores case.
Definition: pstring.h:2012
This is an array collection class of PString objects.
Definition: pstring.h:2365
#define PDECLARE_MUTEX(...)
Definition: mutex.h:200
Abstract class defining I/O channel semantics.
Definition: channel.h:103
#define P_DECLARE_ENUM(name, first,...)
This declares a standard enumeration (enum) of symbols with ++ and – operators.
Definition: object.h:248
bool PBoolean
Definition: object.h:174
PNotifierTemplate< P_INT_PTR > PNotifier
Definition: notifier.h:145
The character string class.
Definition: pstring.h:108
A socket that uses the TCP transport on the Internet Protocol.
Definition: tcpsock.h:40
This class allows the parsing of a set of program arguments.
Definition: args.h:41
This class defines a thread of execution in the system.
Definition: thread.h:66
This is a list collection class of PString objects.
Definition: pstring.h:2562
static const PString & Empty()
Return an empty string.
This template class maps the PArrayObjects to a specific object type.
Definition: array.h:925
#define PDECLARE_NOTIFIER(notifierType, notifiee, func)
Declare PNotifier derived class with P_INT_PTR parameter. Uses PDECLARE_NOTIFIER_EXT macro...
Definition: notifier.h:202
Ultimate parent class for all objects in the class library.
Definition: object.h:2204