ReactOS  0.4.12-dev-375-g61fed54
shell.c
Go to the documentation of this file.
1 /* shell.c
2  *
3  * Copyright (c) 1992-2001 by Mike Gleason.
4  * All rights reserved.
5  *
6  */
7 
8 #include "syshdrs.h"
9 
10 #include "shell.h"
11 #include "util.h"
12 #include "bookmark.h"
13 #include "cmds.h"
14 #include "readln.h"
15 #include "trace.h"
16 #include "main.h"
17 
18 /* We keep running the command line interpreter until gDoneApplication
19  * is non-zero.
20  */
22 
23 /* Track how many times they use ^C. */
25 
26 /* Keep a count of the number of commands the user has entered. */
27 int gEventNumber = 0;
28 
29 
30 #if defined(WIN32) || defined(_WINDOWS)
31 #elif defined(HAVE_SIGSETJMP)
32 /* A command function can set this to have a user generated signal
33  * cause execution to jump here.
34  */
36 
37 /* This is used by the shell so that an unexpected signal can have
38  * execution come back to the main shell prompt.
39  */
41 #else /* HAVE_SIGSETJMP */
42 /* A command function can set this to have a user generated signal
43  * cause execution to jump here.
44  */
46 
47 /* This is used by the shell so that an unexpected signal can have
48  * execution come back to the main shell prompt.
49  */
51 #endif /* HAVE_SIGSETJMP */
52 
53 /* Flag specifying whether the jmp has been set. */
54 int gMayCancelJmp = 0;
55 
56 /* Flag specifying whether the jmp has been set. */
58 
59 /* Save the last signal number. */
60 int gGotSig = 0;
61 
62 /* If the shell is running one of our commands, this is set to non-zero. */
64 
65 /* If set, we need to abort the current session. */
66 int gCancelCtrl = 0;
67 
68 extern Command gCommands[];
69 extern size_t gNumCommands;
70 extern int gStartupUrlParameterGiven;
71 extern FTPLibraryInfo gLib;
74 extern int gNumProgramRuns;
75 extern char gCopyright[];
76 
77 
78 /* This is used as the comparison function when we sort the name list. */
79 static int
81 {
82  return (strcmp((*a).name, (*b).name));
83 } /* CommandSortCmp */
84 
85 
86 
87 
88 /* Sort the command list, in case it wasn't hard-coded that way. */
89 void
91 {
93 } /* InitCommandList */
94 
95 
96 
97 
98 /* This is used as the comparison function when we lookup something
99  * in the command list, and when we want an exact match.
100  */
101 static int
102 CommandExactSearchCmp(const char *const key, const CommandPtr b)
103 {
104  return (strcmp(key, (*b).name));
105 } /* CommandExactSearchCmp */
106 
107 
108 
109 
110 /* This is used as the comparison function when we lookup something
111  * in the command list, and when the key can be just the first few
112  * letters of one or more commands. So a key of "qu" might would match
113  * "quit" and "quote" for example.
114  */
115 static int
116 CommandSubSearchCmp(const char *const key, const CommandPtr a)
117 {
118  register const char *kcp, *cp;
119  int d;
120 
121  for (cp = (*a).name, kcp = key; ; ) {
122  if (*kcp == 0)
123  break;
124  d = *kcp++ - *cp++;
125  if (d)
126  return d;
127  }
128  return (0);
129 } /* CommandSubSearchCmp */
130 
131 
132 
133 
134 /* This returns a pointer to a Command, if the name supplied was long
135  * enough to be a unique name. We return a 0 CommandPtr if we did not
136  * find any matches, a -1 CommandPtr if we found more than one match,
137  * or the unique CommandPtr.
138  */
141 {
142  if ((i < 0) || (i >= (int) gNumCommands))
143  return (kNoCommand);
144  return (&gCommands[i]);
145 } /* GetCommandByIndex */
146 
147 
148 
149 
150 /* This returns a pointer to a Command, if the name supplied was long
151  * enough to be a unique name. We return a 0 CommandPtr if we did not
152  * find any matches, a -1 CommandPtr if we found more than one match,
153  * or the unique CommandPtr.
154  */
156 GetCommandByName(const char *const name, int wantExactMatch)
157 {
158  CommandPtr canp, canp2;
159 
160  /* First check for an exact match. Otherwise if you if asked for
161  * 'cd', it would match both 'cd' and 'cdup' and return an
162  * ambiguous name error, despite having the exact name for 'cd.'
163  */
165 
166  if (canp == kNoCommand && !wantExactMatch) {
167  /* Now see if the user typed an abbreviation unique enough
168  * to match only one name in the list.
169  */
171 
172  if (canp != kNoCommand) {
173  /* Check the entry above us and see if the name we're looking
174  * for would match that, too.
175  */
176  if (canp != &gCommands[0]) {
177  canp2 = canp - 1;
178  if (CommandSubSearchCmp(name, canp2) == 0)
179  return kAmbiguousCommand;
180  }
181  /* Check the entry below us and see if the name we're looking
182  * for would match that one.
183  */
184  if (canp != &gCommands[gNumCommands - 1]) {
185  canp2 = canp + 1;
186  if (CommandSubSearchCmp(name, canp2) == 0)
187  return kAmbiguousCommand;
188  }
189  }
190  }
191  return canp;
192 } /* GetCommandByName */
193 
194 
195 
196 
197 /* Print the help string for the command specified. */
198 
199 void
201 {
202  (void) printf("%s: %s.\n", c->name, c->help);
203 } /* PrintCmdHelp */
204 
205 
206 
207 
208 /* Print the usage string for the command specified. */
209 void
211 {
212  if (c->usage != NULL)
213  (void) printf("Usage: %s %s\n", c->name, c->usage);
214 } /* PrintCmdUsage */
215 
216 
217 
218 
219 /* Parse a command line into an array of arguments. */
220 int
221 MakeArgv(char *line, int *cargc, const char **cargv, int cargcmax, char *dbuf, size_t dbufsize, int *noglobargv, int readlineHacks)
222 {
223  int c;
224  int retval;
225  char *dlim;
226  char *dcp;
227  char *scp;
228  char *arg;
229 
230  *cargc = 0;
231  scp = line;
232  dlim = dbuf + dbufsize - 1;
233  dcp = dbuf;
234 
235  for (*cargc = 0; *cargc < cargcmax; ) {
236  /* Eat preceding junk. */
237  for ( ; ; scp++) {
238  c = *scp;
239  if (c == '\0')
240  goto done;
241  if (isspace(c))
242  continue;
243  if ((c == ';') || (c == '\n')) {
244  scp++;
245  goto done;
246  }
247  break;
248  }
249 
250  arg = dcp;
251  cargv[*cargc] = arg;
252  noglobargv[*cargc] = 0;
253  (*cargc)++;
254 
255  /* Special hack so that "!cmd" is always split into "!" "cmd" */
256  if ((*cargc == 1) && (*scp == '!')) {
257  if (scp[1] == '!') {
258  scp[1] = '\0';
259  } else if ((scp[1] != '\0') && (!isspace((int) scp[1]))) {
260  cargv[0] = "!";
261  scp++;
262  arg = dcp;
263  cargv[*cargc] = arg;
264  noglobargv[*cargc] = 0;
265  (*cargc)++;
266  }
267  }
268 
269  /* Add characters to the new argument. */
270  for ( ; ; ) {
271  c = *scp;
272  if (c == '\0')
273  break;
274  if (isspace(c))
275  break;
276  if ((c == ';') || (c == '\n')) {
277  break;
278  }
279 
280  scp++;
281 
282  if (c == '\'') {
283  for ( ; ; ) {
284  c = *scp++;
285  if (c == '\0') {
286  if (readlineHacks != 0)
287  break;
288  /* Syntax error */
289  (void) fprintf(stderr, "Error: Unbalanced quotes.\n");
290  return (-1);
291  }
292  if (c == '\'')
293  break;
294 
295  /* Add char. */
296  if (dcp >= dlim)
297  goto toolong;
298  *dcp++ = c;
299 
300  if (strchr(kGlobChars, c) != NULL) {
301  /* User quoted glob characters,
302  * so mark this argument for
303  * noglob.
304  */
305  noglobargv[*cargc - 1] = 1;
306  }
307  }
308  } else if (c == '"') {
309  for ( ; ; ) {
310  c = *scp++;
311  if (c == '\0') {
312  if (readlineHacks != 0)
313  break;
314  /* Syntax error */
315  (void) fprintf(stderr, "Error: Unbalanced quotes.\n");
316  return (-1);
317  }
318  if (c == '"')
319  break;
320 
321  /* Add char. */
322  if (dcp >= dlim)
323  goto toolong;
324  *dcp++ = c;
325 
326  if (strchr(kGlobChars, c) != NULL) {
327  /* User quoted glob characters,
328  * so mark this argument for
329  * noglob.
330  */
331  noglobargv[*cargc - 1] = 1;
332  }
333  }
334  } else
335 #if defined(WIN32) || defined(_WINDOWS)
336  if (c == '|') {
337 #else
338  if (c == '\\') {
339 #endif
340  /* Add next character, verbatim. */
341  c = *scp++;
342  if (c == '\0')
343  break;
344 
345  /* Add char. */
346  if (dcp >= dlim)
347  goto toolong;
348  *dcp++ = c;
349  } else {
350  /* Add char. */
351  if (dcp >= dlim)
352  goto toolong;
353  *dcp++ = c;
354  }
355  }
356 
357  *dcp++ = '\0';
358  }
359 
360  (void) fprintf(stderr, "Error: Argument list too long.\n");
361  *cargc = 0;
362  cargv[*cargc] = NULL;
363  return (-1);
364 
365 done:
366  retval = (int) (scp - line);
367  cargv[*cargc] = NULL;
368  return (retval);
369 
370 toolong:
371  (void) fprintf(stderr, "Error: Line too long.\n");
372  *cargc = 0;
373  cargv[*cargc] = NULL;
374  return (-1);
375 } /* MakeArgv */
376 
377 
378 
379 
380 static int
382 {
383  CommandPtr cmdp;
384  int flags;
385  int cargc, cargcm1;
386 
387  cmdp = GetCommandByName(aip->cargv[0], 0);
388  if (cmdp == kAmbiguousCommand) {
389  (void) printf("%s: ambiguous command name.\n", aip->cargv[0]);
390  return (-1);
391  } else if (cmdp == kNoCommand) {
392  (void) printf("%s: no such command.\n", aip->cargv[0]);
393  return (-1);
394  }
395 
396  cargc = aip->cargc;
397  cargcm1 = cargc - 1;
398  flags = cmdp->flags;
399 
400  if (((flags & kCmdMustBeConnected) != 0) && (gConn.connected == 0)) {
401  (void) printf("%s: must be connected to do that.\n", aip->cargv[0]);
402  } else if (((flags & kCmdMustBeDisconnected) != 0) && (gConn.connected != 0)) {
403  (void) printf("%s: must be disconnected to do that.\n", aip->cargv[0]);
404  } else if ((cmdp->minargs != kNoMin) && (cmdp->minargs > cargcm1)) {
405  PrintCmdUsage(cmdp);
406  } else if ((cmdp->maxargs != kNoMax) && (cmdp->maxargs < cargcm1)) {
407  PrintCmdUsage(cmdp);
408  } else {
409  (*cmdp->proc)(cargc, aip->cargv, cmdp, aip);
410  }
411  return (0);
412 } /* DoCommand */
413 
414 
415 
416 
417 /* Allows the user to cancel a data transfer. */
418 void
419 XferCanceller(int sigNum)
420 {
421  gGotSig = sigNum;
422  if (gConn.cancelXfer > 0) {
423 #if defined(WIN32) || defined(_WINDOWS)
425 #else
426  /* User already tried it once, they
427  * must think it's locked up.
428  *
429  * Jump back to the top, and
430  * close down the current session.
431  */
432  gCancelCtrl = 1;
433  if (gMayBackToTopJmp > 0) {
434 #ifdef HAVE_SIGSETJMP
436 #else /* HAVE_SIGSETJMP */
438 #endif /* HAVE_SIGSETJMP */
439  }
440 #endif
441  }
442  gConn.cancelXfer++;
443 } /* XferCanceller */
444 
445 
446 
447 #if defined(WIN32) || defined(_WINDOWS)
448 #else
449 
450 /* Allows the user to cancel a long operation and get back to the shell. */
451 void
452 BackToTop(int sigNum)
453 {
454  gGotSig = sigNum;
455  if (sigNum == SIGPIPE) {
456  if (gRunningCommand == 1) {
457  (void) fprintf(stderr, "Unexpected broken pipe.\n");
458  gRunningCommand = 0;
459  } else {
460  SetXtermTitle("RESTORE");
461  exit(1);
462  }
463  } else if (sigNum == SIGINT) {
464  if (gRunningCommand == 0)
465  gDoneApplication = 1;
466  }
467  if (gMayBackToTopJmp > 0) {
468 #ifdef HAVE_SIGSETJMP
470 #else /* HAVE_SIGSETJMP */
472 #endif /* HAVE_SIGSETJMP */
473  }
474 } /* BackToTop */
475 
476 
477 
478 
479 /* Some commands may want to jump back to the start too. */
480 void
481 Cancel(int sigNum)
482 {
483  if (gMayCancelJmp != 0) {
484  gGotSig = sigNum;
485  gMayCancelJmp = 0;
486 #ifdef HAVE_SIGSETJMP
488 #else /* HAVE_SIGSETJMP */
489  longjmp(gCancelJmp, 1);
490 #endif /* HAVE_SIGSETJMP */
491  }
492 } /* Cancel */
493 
494 #endif
495 
496 
497 
498 void
500 {
501  int tUsed, bUsed;
502  ArgvInfo ai;
503  char prompt[64];
504  char *lineRead;
505 #if defined(WIN32) || defined(_WINDOWS)
506 #else
507  int sj;
508 #endif
510 
511  /* Execution may jump back to this point to restart the shell. */
512 #if defined(WIN32) || defined(_WINDOWS)
513 
514 #elif defined(HAVE_SIGSETJMP)
515  sj = sigsetjmp(gBackToTopJmp, 1);
516 #else /* HAVE_SIGSETJMP */
517  sj = setjmp(gBackToTopJmp);
518 #endif /* HAVE_SIGSETJMP */
519 
520 #if defined(WIN32) || defined(_WINDOWS)
521 #else
522  if (sj != 0) {
523  Trace(0, "Caught signal %d, back at top.\n", gGotSig);
524  if (gGotSig == SIGALRM) {
525  (void) printf("\nRemote host was not responding, closing down the session.");
527  } else{
528  (void) printf("\nInterrupted.\n");
529  if (gCancelCtrl != 0) {
530  gCancelCtrl = 0;
531  (void) printf("Closing down the current FTP session: ");
533  (void) sleep(1);
534  (void) printf("done.\n");
535  }
536  }
537  }
538 
539  gMayBackToTopJmp = 1;
540 #endif
541 
542 
543  ++gEventNumber;
544 
545  while (gDoneApplication == 0) {
546 #if defined(WIN32) || defined(_WINDOWS)
547 #else
550  (void) NcSignal(SIGALRM, BackToTop);
551 #endif
552 
553  MakePrompt(prompt, sizeof(prompt));
554 
555  if (gConn.connected == 0) {
556  SetXtermTitle("DEFAULT");
557  } else {
558  SetXtermTitle("%s - NcFTP", gConn.host);
559  }
560 
561  lineRead = Readline(prompt);
562  if (lineRead == NULL) {
563  /* EOF, Control-D */
564  (void) printf("\n");
565  break;
566  }
567  Trace(0, "> %s\n", lineRead);
568  AddHistory(lineRead);
569  for (tUsed = 0;;) {
570  (void) memset(&ai, 0, sizeof(ai));
571  bUsed = MakeArgv(lineRead + tUsed, &ai.cargc, ai.cargv,
572  (int) (sizeof(ai.cargv) / sizeof(char *)),
573  ai.argbuf, sizeof(ai.argbuf),
574  ai.noglobargv, 0);
575  if (bUsed <= 0)
576  break;
577  tUsed += bUsed;
578  if (ai.cargc == 0)
579  continue;
580  gRunningCommand = 1;
581  (void) time(&cmdStart);
582  if (DoCommand(&ai) < 0) {
583  (void) time(&cmdStop);
584  gRunningCommand = 0;
585  break;
586  }
587  (void) time(&cmdStop);
588  gRunningCommand = 0;
589  if ((cmdStop - cmdStart) > kBeepAfterCmdTime) {
590  /* Let the user know that a time-consuming
591  * operation has completed.
592  */
593 #if defined(WIN32) || defined(_WINDOWS)
595 #else
596  (void) fprintf(stderr, "\007");
597 #endif
598  }
599  ++gEventNumber;
600  }
601 
602  free(lineRead);
603  }
604 
605  CloseHost();
606  gMayBackToTopJmp = 0;
607 } /* Shell */
#define isspace(c)
Definition: acclib.h:69
jmp_buf sigjmp_buf
Definition: port.h:324
CommandPtr GetCommandByName(const char *const name, int wantExactMatch)
Definition: shell.c:156
#define sleep
Definition: syshdrs.h:37
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:47
int gDoneApplication
Definition: shell.c:21
char argbuf[256]
Definition: shell.h:12
int gEventNumber
Definition: shell.c:27
const char * cargv[64]
Definition: shell.h:9
int gCancelCtrl
Definition: shell.c:66
WCHAR * name
Definition: path.c:44
#define kAmbiguousCommand
Definition: shell.h:54
void PrintCmdUsage(CommandPtr c)
Definition: shell.c:210
#define free
Definition: debug_ros.c:5
#define kNoCommand
Definition: shell.h:55
int gGotSig
Definition: shell.c:60
int gRunningCommand
Definition: shell.c:63
INT cmdStart(INT argc, WCHAR **argv)
Definition: cmdStart.c:163
void * arg
Definition: msvc.h:12
#define SIGINT
Definition: signal.h:23
Definition: shell.h:41
__u16 time
Definition: mkdosfs.c:366
#define SIG_DFL
Definition: signal.h:47
void BackToTop(int sigNum)
Definition: shell.c:452
GLenum GLclampf GLint i
Definition: glfuncs.h:14
char host[64]
Definition: ncftp.h:136
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
int gNumProgramRuns
Definition: preffw.c:14
void __cdecl qsort(_Inout_updates_bytes_(_NumOfElements *_SizeOfElements) void *_Base, _In_ size_t _NumOfElements, _In_ size_t _SizeOfElements, _In_ int(__cdecl *_PtFuncCompare)(const void *, const void *))
#define kCmdMustBeConnected
Definition: shell.h:59
void SetXtermTitle(const char *const fmt,...)
Definition: readln.c:718
smooth NULL
Definition: ftsmooth.c:416
int minargs
Definition: shell.h:46
Definition: parser.c:48
Command gCommands[]
Definition: cmdlist.c:16
static int DoCommand(const ArgvInfoPtr aip)
Definition: shell.c:381
#define kCmdMustBeDisconnected
Definition: shell.h:60
int(* qsort_proc_t)(const void *, const void *)
Definition: util.h:8
int longjmp(jmp_buf buf, int retval)
FTPLibraryInfo gLib
Definition: main.c:36
void siglongjmp(sigjmp_buf buf, int val)
int noglobargv[64]
Definition: shell.h:10
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
void Cancel(int sigNum)
Definition: shell.c:481
#define d
Definition: ke_i.h:81
#define kBeepAfterCmdTime
Definition: shell.h:26
static int CommandSortCmp(const CommandPtr a, const CommandPtr b)
Definition: shell.c:80
int MakeArgv(char *line, int *cargc, const char **cargv, int cargcmax, char *dbuf, size_t dbufsize, int *noglobargv, int readlineHacks)
Definition: shell.c:221
int sigsetjmp(sigjmp_buf buf, int savesigs)
const GLubyte * c
Definition: glext.h:8905
FTPConnectionInfo gConn
Definition: main.c:37
void InitCommandList(void)
Definition: shell.c:90
int cargc
Definition: shell.h:11
GLbitfield flags
Definition: glext.h:7161
#define SIGPIPE
Definition: signal.h:35
char line[200]
Definition: main.c:97
int signal
Definition: xcptfil.c:12
Definition: ncftp.h:84
#define kGlobChars
Definition: ncftp.h:357
jmp_buf gBackToTopJmp
Definition: shell.c:50
static int CommandExactSearchCmp(const char *const key, const CommandPtr b)
Definition: shell.c:102
void MakePrompt(char *dst, size_t dsize)
Definition: readln.c:802
int maxargs
Definition: shell.h:46
void CommandShell(void)
Definition: shell.c:499
CmdProc proc
Definition: shell.h:43
#define Trace(x)
Definition: zutil.h:197
Definition: shell.h:8
INT cmdStop(INT argc, WCHAR **argv)
Definition: cmdStop.c:12
static int CommandSubSearchCmp(const char *const key, const CommandPtr a)
Definition: shell.c:116
int gMayCancelJmp
Definition: shell.c:54
jmp_buf gCancelJmp
Definition: shell.c:45
#define NcSignal
Definition: ncftp.h:604
BOOL WINAPI MessageBeep(_In_ UINT)
int flags
Definition: shell.h:45
void CloseHost(void)
Definition: main.c:153
int(* bsearch_proc_t)(const void *, const void *)
Definition: util.h:9
__kernel_time_t time_t
Definition: linux.h:252
char gCopyright[]
Definition: version.c:17
LineList gStartupURLCdList
Definition: main.c:38
#define kNoMin
Definition: shell.h:35
#define MB_OK
Definition: winuser.h:784
void XferCanceller(int sigNum)
Definition: shell.c:419
#define setjmp
Definition: setjmp.h:183
char * strchr(const char *String, int ch)
Definition: utclib.c:501
POINT cp
Definition: magnifier.c:60
Definition: name.c:36
#define kNoMax
Definition: shell.h:34
#define c
Definition: ke_i.h:80
void AddHistory(char *line)
Definition: readln.c:699
FILE * stderr
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
struct Command * CommandPtr
Definition: shell.h:28
long jmp_buf[100]
Definition: of.h:11
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
void exit(int exitcode)
Definition: _exit.c:33
int gNumInterruptions
Definition: shell.c:24
#define memset(x, y, z)
Definition: compat.h:39
size_t gNumCommands
Definition: cmdlist.c:525
int gStartupUrlParameterGiven
Definition: main.c:32
void PrintCmdHelp(CommandPtr c)
Definition: shell.c:200
int gMayBackToTopJmp
Definition: shell.c:57
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
CommandPtr GetCommandByIndex(const int i)
Definition: shell.c:140
char * Readline(char *prompt)
Definition: readln.c:671
Definition: path.c:42
#define printf
Definition: config.h:203
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:29
#define bsearch