ReactOS 0.4.15-dev-7670-g69b08be
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. */
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. */
55
56/* Flag specifying whether the jmp has been set. */
58
59/* Save the last signal number. */
60int 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. */
67
68extern Command gCommands[];
69extern size_t gNumCommands;
71extern FTPLibraryInfo gLib;
74extern int gNumProgramRuns;
75extern char gCopyright[];
76
77
78/* This is used as the comparison function when we sort the name list. */
79static 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. */
89void
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 */
101static int
102CommandExactSearchCmp(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 */
115static int
116CommandSubSearchCmp(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 */
156GetCommandByName(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
199void
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. */
209void
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. */
220int
221MakeArgv(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
365done:
366 retval = (int) (scp - line);
367 cargv[*cargc] = NULL;
368 return (retval);
369
370toolong:
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
380static 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. */
418void
419XferCanceller(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 */
437 longjmp(gBackToTopJmp, 1);
438#endif /* HAVE_SIGSETJMP */
439 }
440#endif
441 }
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. */
451void
452BackToTop(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)
466 }
467 if (gMayBackToTopJmp > 0) {
468#ifdef HAVE_SIGSETJMP
470#else /* HAVE_SIGSETJMP */
471 longjmp(gBackToTopJmp, 1);
472#endif /* HAVE_SIGSETJMP */
473 }
474} /* BackToTop */
475
476
477
478
479/* Some commands may want to jump back to the start too. */
480void
481Cancel(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
498void
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
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;
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();
607} /* Shell */
#define isspace(c)
Definition: acclib.h:69
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
char * strchr(const char *String, int ch)
Definition: utclib.c:501
INT cmdStart(INT argc, WCHAR **argv)
Definition: cmdStart.c:172
INT cmdStop(INT argc, WCHAR **argv)
Definition: cmdStop.c:12
#define setjmp
Definition: setjmp.h:209
_JBTYPE jmp_buf[_JBLEN]
Definition: setjmp.h:186
#define SIG_DFL
Definition: signal.h:47
#define SIGINT
Definition: signal.h:23
#define SIGPIPE
Definition: signal.h:35
#define free
Definition: debug_ros.c:5
#define NULL
Definition: types.h:112
#define Trace(x)
Definition: inflate.c:42
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
__kernel_time_t time_t
Definition: linux.h:252
#define printf
Definition: freeldr.h:94
const GLubyte * c
Definition: glext.h:8905
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLbitfield flags
Definition: glext.h:7161
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define d
Definition: ke_i.h:81
#define c
Definition: ke_i.h:80
#define sleep
Definition: syshdrs.h:37
POINT cp
Definition: magnifier.c:59
__u16 time
Definition: mkdosfs.c:8
void CloseHost(void)
Definition: main.c:153
void PrintCmdHelp(CommandPtr c)
Definition: shell.c:200
FTPConnectionInfo gConn
Definition: main.c:37
size_t gNumCommands
Definition: cmdlist.c:525
int MakeArgv(char *line, int *cargc, const char **cargv, int cargcmax, char *dbuf, size_t dbufsize, int *noglobargv, int readlineHacks)
Definition: shell.c:221
CommandPtr GetCommandByName(const char *const name, int wantExactMatch)
Definition: shell.c:156
int gGotSig
Definition: shell.c:60
int gEventNumber
Definition: shell.c:27
void PrintCmdUsage(CommandPtr c)
Definition: shell.c:210
LineList gStartupURLCdList
Definition: main.c:38
FTPLibraryInfo gLib
Definition: main.c:36
jmp_buf gCancelJmp
Definition: shell.c:45
int gMayBackToTopJmp
Definition: shell.c:57
static int CommandExactSearchCmp(const char *const key, const CommandPtr b)
Definition: shell.c:102
int gNumProgramRuns
Definition: preffw.c:14
static int CommandSortCmp(const CommandPtr a, const CommandPtr b)
Definition: shell.c:80
static int CommandSubSearchCmp(const char *const key, const CommandPtr a)
Definition: shell.c:116
CommandPtr GetCommandByIndex(const int i)
Definition: shell.c:140
int gNumInterruptions
Definition: shell.c:24
void BackToTop(int sigNum)
Definition: shell.c:452
jmp_buf gBackToTopJmp
Definition: shell.c:50
void XferCanceller(int sigNum)
Definition: shell.c:419
int gDoneApplication
Definition: shell.c:21
int gCancelCtrl
Definition: shell.c:66
static int DoCommand(const ArgvInfoPtr aip)
Definition: shell.c:381
void InitCommandList(void)
Definition: shell.c:90
int gMayCancelJmp
Definition: shell.c:54
int gStartupUrlParameterGiven
Definition: main.c:32
char gCopyright[]
Definition: version.c:17
Command gCommands[]
Definition: cmdlist.c:16
void CommandShell(void)
Definition: shell.c:499
void Cancel(int sigNum)
Definition: shell.c:481
int gRunningCommand
Definition: shell.c:63
int(* qsort_proc_t)(const void *, const void *)
Definition: util.h:8
int(* bsearch_proc_t)(const void *, const void *)
Definition: util.h:9
int sigsetjmp(sigjmp_buf buf, int savesigs)
void siglongjmp(sigjmp_buf buf, int val)
jmp_buf sigjmp_buf
Definition: port.h:324
void FTPShutdownHost(const FTPCIPtr cip)
Definition: open.c:564
#define kGlobChars
Definition: ncftp.h:357
#define NcSignal
Definition: ncftp.h:604
void AddHistory(char *line)
Definition: readln.c:699
char * Readline(char *prompt)
Definition: readln.c:671
void SetXtermTitle(const char *const fmt,...)
Definition: readln.c:718
void MakePrompt(char *dst, size_t dsize)
Definition: readln.c:802
#define exit(n)
Definition: config.h:202
int signal
Definition: except.c:82
#define memset(x, y, z)
Definition: compat.h:39
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 kAmbiguousCommand
Definition: shell.h:54
struct Command * CommandPtr
Definition: shell.h:28
#define kCmdMustBeConnected
Definition: shell.h:59
#define kCmdMustBeDisconnected
Definition: shell.h:60
#define kNoMax
Definition: shell.h:34
#define kBeepAfterCmdTime
Definition: shell.h:26
#define kNoCommand
Definition: shell.h:55
#define kNoMin
Definition: shell.h:35
Definition: shell.h:8
int cargc
Definition: shell.h:11
int noglobargv[64]
Definition: shell.h:10
const char * cargv[64]
Definition: shell.h:9
char argbuf[256]
Definition: shell.h:12
Definition: shell.h:41
int maxargs
Definition: shell.h:46
int minargs
Definition: shell.h:46
int flags
Definition: shell.h:45
CmdProc proc
Definition: shell.h:43
char host[64]
Definition: ncftp.h:136
Definition: ncftp.h:84
Definition: copy.c:22
WCHAR * name
Definition: path.c:43
Definition: parser.c:49
Definition: name.c:39
#define bsearch
void * arg
Definition: msvc.h:10
BOOL WINAPI MessageBeep(_In_ UINT uType)
#define MB_OK
Definition: winuser.h:789