VirtualBox

source: kBuild/trunk/src/kShell/kShell.c@ 49

Last change on this file since 49 was 49, checked in by bird, 22 years ago

Made it compile.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: kShell.c 49 2003-04-05 03:22:30Z bird $
2 *
3 * kShell - A mini shell.
4 *
5 * Copyright (c) 2002 knut st. osmundsen <bird@anduin.net>
6 *
7 *
8 * This file is part of kBuild.
9 *
10 * kBuild is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * kBuild is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with kBuild; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26/** @design kShell (Micro Shell)
27 *
28 * The micro shell provides the basic shell functionality kBuild need - no more,
29 * no less. It is intended to be as simple as possible.
30 *
31 * The shell commands are case sensitive - all lowercase.
32 *
33 * The shell environment variables are case sensitive or insensitive according to
34 * host os.
35 *
36 *
37 *
38 * @subsection Command Separators
39 *
40 * There is one command separator '&&'. This works like splitting the command line
41 * into several makefile lines. This splitting isn't done by the micro shell but
42 * the makefile interpreter.
43 *
44 * You might thing this is limiting, but no, you can use all the makefile command
45 * prefixes.
46 *
47 *
48 *
49 * @subsection Path Component Separator (/)
50 *
51 * The shell uses '/' as path component separator.
52 * For host OSes with the notion of drive letters or similar, ':' is
53 * used to separate the drive letter and the path.
54 *
55 *
56 *
57 * @subsection UNC paths
58 *
59 * For host OSes which supports UNC paths these are supported but for the chdir
60 * command.
61 *
62 * The Path Component Separator is still '/' for UNC paths.
63 *
64 *
65 *
66 * @subsection Wildchars
67 *
68 * '*' and '?' are accepted as wildchars.
69 *
70 * '*' means 0 or more characters. <br>
71 * '?' means 1 character.
72 *
73 * When the term 'pattern' is use in command description this means that
74 * wildchars are accepted.
75 *
76 *
77 *
78 * @subsection Quoting
79 *
80 * Use double quotes (") to quote filenames or executables containing spaces.
81 *
82 *
83 *
84 * @subsection Execute Program
85 *
86 * If the first, possibly quoted, word of a commandline if not found as an
87 * internal command will be tried executed. If no path it will be searched
88 * for in the PATH environment variable.
89 *
90 *
91 *
92 * @subsection Commands
93 *
94 * This section will describe the commands implemented by the shell.
95 *
96 *
97 *
98 * @subsubsection copy
99 * Copies one or more files to a target file or directory.
100 *
101 * <b>Syntax: copy <source file pattern> [more sources] <target> </b>
102 *
103 * Specify one or more source file patterns.
104 *
105 * Specify exactly one target. The target may be a directory or a file.
106 * If it's a file and multiple source files specified either thru pattern or
107 * multiple source file specifications, the target file will be a copy of the
108 * last one.
109 *
110 * The command fails if a source file isn't found. It also fails on read or
111 * write errors.
112 *
113 *
114 *
115 * @subsubsection copytree
116 * Copies one or more files to a target file or directory.
117 *
118 * <b>Syntax: copytree <source directory> <target directory> </b>
119 *
120 * Specify exactly one source directory.
121 *
122 * Specify exactly one target directory. The target directory path will be
123 * created if doesn't exist.
124 *
125 * The command fails if source directory isn't found. It also fails on read or
126 * write errors.
127 *
128 *
129 *
130 * @subsubsection rm
131 * Deletes one or more files.
132 *
133 * <b>Syntax: rm [file pattern] [more files] </b>
134 *
135 * Specify 0 or more file patterns for deletion.
136 *
137 * This command fails if it cannot delete a file. It will not fail if a file
138 * doesn't exist. It will neither fail if no files are specified.
139 *
140 *
141 *
142 * @subsubsection rmtree
143 * Deletes one or more directory trees.
144 *
145 * <b>Syntax: rmtree [directory pattern] [directories] </b>
146 *
147 * Specify 0 or more directory patterns for deletion.
148 *
149 * This command fails if it cannot delete a file or directory. It will not fail
150 * if a directory doesn't exist. It will neither fail if no files are specified.
151 *
152 *
153 *
154 * @subsubsection chdir
155 * Changes the current directory.
156 *
157 * This updates the .CWD macro to the new current directory path.
158 *
159 * <b>Syntax: chdir <directory> </b>
160 *
161 *
162 *
163 * @subsubsection mkdir
164 * Create directory.
165 *
166 * <b>Syntax: mkdir <directory> </b>
167 *
168 * Specify one directory to create.
169 *
170 *
171 *
172 * @subsubsection rmdir
173 * Remove directory.
174 *
175 * <b>Syntax: rmdir <directory> </b>
176 *
177 * Specify one directory to remove. The directory must be empty.
178 *
179 * This command failes if directory isn't empty. It will not fail if
180 * the directory doesn't exist.
181 *
182 *
183 *
184 * @subsubsection set
185 * Set environment variable.
186 *
187 * <b>Syntax: set <envvar>=<value> </b>
188 *
189 *
190 *
191 * @subsubsection unset
192 * Unset enviornment variable(s).
193 *
194 * <b>Syntax: unset <envvar pattern> [more envvars] </b>
195 *
196 * Specify on or more environment variable patterns.
197 *
198 *
199 *
200 * @subsubsection pushenv
201 * Pushes a set of environment variables onto the environment stack. The
202 * variables can later be popped back using the popenv command.
203 *
204 * If '*' is specified as pattern the complete enviornment is pushed and
205 * when popped it will <b>replace</b> the enviornment.
206 *
207 * <b>Syntax: pushenv <envvar pattern> [more envvars] </b>
208 * <b>Syntax: pushenv * </b>
209 *
210 *
211 *
212 * @subsubsection popenv
213 * Pop a set of environment variables from the environment stack. If a '*'
214 * push was done, we'll replace the enviornment with the variables poped off
215 * the stack.
216 *
217 * <b>Syntax: popenv </b>
218 *
219 *
220 *
221 */
222
223
224/*******************************************************************************
225* Defined Constants And Macros *
226*******************************************************************************/
227#define KSWORD_FLAGS_ESCAPE 1
228#define KSWORD_FLAGS_QUOTED 2
229#define KSWORD_FLAGS_PATTERN 4
230
231#define KSHELL_MAX_COMMAND 4096
232
233/**
234 * Test if this is an escapable character or not.
235 */
236#define KSHELL_ESCAPABLE(ch) ( (ch) == '"' \
237 || (ch) == '\'' \
238 || (ch) == '`' \
239 || (ch) == 'ï' \
240 )
241
242/**
243 * Test if this is a quote character or not.
244 */
245#define KSHELL_QUOTE(ch) ( (ch) == '"' \
246 || (ch) == '\'' \
247 || (ch) == '`' \
248 || (ch) == 'ï' \
249 )
250
251/**
252 * Test if this is a wildchar character or not.
253 */
254#define KSHELL_WILDCHAR(ch) ( (ch) == '*' || (ch) == '?' )
255
256/**
257 * the a default kShell slash.
258 */
259#define KSHELL_SLASH '/'
260
261/**
262 * Checks if the character is a slash or not.
263 */
264#define KSHELL_ISSLASH(ch) ( (ch) == KSHELL_SLASH )
265
266
267/*******************************************************************************
268* Header Files *
269*******************************************************************************/
270#include "kShell.h"
271#include <kLib/kLib.h>
272#include <kLib/kString.h>
273
274#include <string.h>
275#include <stdlib.h>
276#include <stdio.h>
277
278
279/*******************************************************************************
280* Global Variables *
281*******************************************************************************/
282typedef struct _kshellWord
283{
284 int fFlags;
285 char * pszWord;
286 unsigned cchWord;
287 const char *pszWordOrg;
288 unsigned cchWordOrg;
289} KSHELLWORD, *PKSHELLWORD;
290
291
292typedef struct _kshellWords
293{
294 unsigned cWords;
295 KSHELLWORD aWords[1];
296} KSHELLWORDS, *PKSHELLWORDS;
297
298
299/*******************************************************************************
300* Global Variables *
301*******************************************************************************/
302static const char *pszkshellCurDir = NULL;
303
304/*******************************************************************************
305* Internal Functions *
306*******************************************************************************/
307PKSHELLWORDS kshellWordsParse(const char *pszText, int cWords, PKSHELLWORDS pPrevWords);
308void kshellWordsDestroy(PKSHELLWORDS pWords);
309
310int kshellSyntaxError(const char *pszCmd, const char *pszMessage, ...);
311int kshellError(const char *pszCmd, const char *pszMessage, ...);
312
313int kshellCmd_copy(const char *pszCmd, PKSHELLWORDS pWords);
314int kshellCmd_copytree(const char *pszCmd, PKSHELLWORDS pWords);
315int kshellCmd_sync(const char *pszCmd, PKSHELLWORDS pWords);
316int kshellCmd_synctree(const char *pszCmd, PKSHELLWORDS pWords);
317int kshellCmd_rm(const char *pszCmd, PKSHELLWORDS pWords);
318int kshellCmd_rmtree(const char *pszCmd, PKSHELLWORDS pWords);
319int kshellCmd_chdir(const char *pszCmd, PKSHELLWORDS pWords);
320int kshellCmd_mkdir(const char *pszCmd, PKSHELLWORDS pWords);
321int kshellCmd_rmdir(const char *pszCmd, PKSHELLWORDS pWords);
322int kshellCmd_set(const char *pszCmd, PKSHELLWORDS pWords);
323int kshellCmd_unset(const char *pszCmd, PKSHELLWORDS pWords);
324int kshellCmd_pushenv(const char *pszCmd, PKSHELLWORDS pWords);
325int kshellCmd_popenv(const char *pszCmd, PKSHELLWORDS pWords);
326int kshellCmd_echo(const char *pszCmd, PKSHELLWORDS pWords);
327int kshellCmd_write(const char *pszCmd, PKSHELLWORDS pWords);
328int kshellCmd_ExecuteProgram(const char *pszCmd, PKSHELLWORDS pWords);
329
330
331
332/**
333 * Initiate the shell.
334 * Allow us to initiate globals.
335 *
336 * @returns 0 on success.
337 * @returns error code on error.
338 * @param fVerbose If set banner will be printed.
339 */
340int kshellInit(int fVerbose)
341{
342 if (fVerbose)
343 {
344 printf("\n"
345 "kShell v0.0.0\n"
346 "Copyright 2002 knut st. osmundsen <bird@anduin.net>\n"
347 "\n");
348 }
349 return 0;
350}
351
352
353/**
354 * Terminate the shell.
355 * Allow us to cleanup stuff.
356 */
357void kshellTerm(void)
358{
359 return;
360}
361
362
363/**
364 * Start interactive shell interface.
365 * This reads commands from stdin till 'exit' is encountered or end-of-file.
366 *
367 * @returns returncode of last command.
368 */
369int kshellInteractive(void)
370{
371 static char szCmd[KSHELL_MAX_COMMAND];
372 int rc = 0;
373
374 printf("kShell>");
375 fflush(stdout);
376 while (fgets(&szCmd[0], sizeof(szCmd), stdin))
377 {
378 char *pszEnd = &szCmd[strlen(&szCmd[0]) - 1];
379 while (pszEnd >= &szCmd[0] && (*pszEnd == '\n' || *pszEnd == '\r'))
380 *pszEnd-- = '\0';
381
382 if (!strcmp(&szCmd[0], "exit"))
383 break;
384
385 rc = kshellExecute(&szCmd[0]);
386 printf("kShell(rc=%d)>", rc);
387 fflush(stdout);
388 }
389
390 return rc;
391}
392
393/**
394 * Execute a shell command.
395 * @returns 0 on success if command.
396 * @returns Error code if command failed.
397 * @returns Return code from program.
398 * @returns 1742 (KSHELL_ERROR_PROGRAM_NOT_FOUND) if program wasn't found.
399 * @returns 1743 (KSHELL_ERROR_COMMAND_TOO_LONG) if program commandline was too long.
400 * @param pszCmd Command or program to execute.
401 */
402int kshellExecute(const char *pszCmd)
403{
404#define MAX_WORDS (~0)
405 static struct _kshellCommands
406 {
407 const char *pszCmd;
408 unsigned cWords; /* Number of words including the command it self. */
409 int (*pfnCmd)(const char *, PKSHELLWORDS);
410 } aCmds[] =
411 {
412 {"copy", MAX_WORDS, kshellCmd_copy},
413 {"copytree", 3, kshellCmd_copytree},
414 {"sync", MAX_WORDS, kshellCmd_sync},
415 {"synctree", 3, kshellCmd_synctree},
416 {"rm", MAX_WORDS, kshellCmd_rm},
417 {"rmtree", MAX_WORDS, kshellCmd_rmtree},
418 {"chdir", 2, kshellCmd_chdir},
419 {"mkdir", MAX_WORDS, kshellCmd_mkdir},
420 {"rmdir", MAX_WORDS, kshellCmd_rmdir},
421 {"set", 1, kshellCmd_set},
422 {"unset", MAX_WORDS, kshellCmd_unset},
423 {"pushenv", MAX_WORDS, kshellCmd_pushenv},
424 {"popenv", 1, kshellCmd_popenv},
425 {"echo", 2, kshellCmd_echo},
426 {"write", 2, kshellCmd_write},
427
428 /* last entry */
429 {"", 1, kshellCmd_ExecuteProgram}
430 };
431#undef MAX_WORDS
432
433 PKSHELLWORDS pWords;
434 int i;
435 int rc;
436
437
438 /*
439 * Parse out the first word.
440 */
441 pWords = kshellWordsParse(pszCmd, 1, NULL);
442 if (!pWords)
443 return KSHELL_ERROR_NOT_ENOUGH_MEMORY;
444 if (!pWords->cWords)
445 return 0;
446
447
448 /*
449 * Look for command.
450 * Note! the last entry is the default command (execute program).
451 */
452 for (i = 0; i < (sizeof(aCmds) / sizeof(aCmds[0])) - 1; i++)
453 {
454 if (!strcmp(aCmds[i].pszCmd, pWords->aWords[0].pszWord))
455 break;
456 }
457
458
459 /*
460 * Execute command.
461 */
462 if (aCmds[i].cWords > 1)
463 {
464 pWords = kshellWordsParse(pszCmd, aCmds[i].cWords, pWords);
465 if (!pWords)
466 return KSHELL_ERROR_NOT_ENOUGH_MEMORY;
467 }
468 rc = aCmds[i].pfnCmd(pszCmd, pWords);
469
470
471 return rc;
472}
473
474
475/**
476 * Parses words out of a string.
477 *
478 * @returns Pointer to a words structure.
479 * This must be destroy calling kshellWordsDestroy().
480 * @returns NULL on failure (out of memory).
481 * @param pszText Text string to parse.
482 * @param cWords Number of words to parse. Will stop after cWords.
483 * @param pPrevWords Pointer to structur of previosly parse words from pszText.
484 * Use this to continue parsing a string. The pPrevWords
485 * structure will be destroyed.
486 * If NULL we'll start from the begining.
487 */
488PKSHELLWORDS kshellWordsParse(const char *pszText, int cWords, PKSHELLWORDS pPrevWords)
489{
490 PKSHELLWORDS pWords = pPrevWords;
491
492 /*
493 * If previous work done, skip to end of that.
494 */
495 if (pPrevWords && pPrevWords->cWords)
496 {
497 pszText = pPrevWords->aWords[pPrevWords->cWords - 1].pszWordOrg
498 + pPrevWords->aWords[pPrevWords->cWords - 1].cchWordOrg;
499 cWords -= pPrevWords->cWords;
500 }
501
502 /*
503 * Parse loop
504 */
505 while (cWords-- > 0)
506 {
507 KSHELLWORD word = {0,0,0,0,0};
508 char chEnd = ' ';
509 char ch;
510
511 /*
512 * Skip blanks to find start of word.
513 */
514 while (*pszText == ' ' || *pszText == '\t')
515 pszText++;
516 if (!*pszText)
517 break;
518 word.pszWordOrg = pszText;
519
520
521 /*
522 * Quoted?
523 * Any possible quote!
524 */
525 if (KSHELL_QUOTE(*pszText))
526 {
527 chEnd = *pszText++;
528 word.fFlags |= KSWORD_FLAGS_QUOTED;
529 }
530
531
532 /*
533 * Find end of word and look for escape and pattern characters.
534 * We escape by doubling the character, not by slashing!
535 */
536 while ((ch = *pszText) != '\0' && (ch != chEnd || pszText[1] == chEnd))
537 {
538 if (ch == pszText[1] && KSHELL_ESCAPABLE(ch))
539 {
540 word.fFlags |= KSWORD_FLAGS_ESCAPE;
541 pszText++;
542 }
543 if (KSHELL_WILDCHAR(ch))
544 word.fFlags |= KSWORD_FLAGS_PATTERN;
545 pszText++;
546 }
547 if (word.fFlags & KSWORD_FLAGS_QUOTED)
548 pszText++;
549 word.cchWordOrg = pszText - word.pszWordOrg;
550
551
552 /*
553 * Make a copy of the word and unescape (if needed).
554 */
555 word.pszWord = malloc(word.cchWordOrg + 1);
556 if (!word.pszWord)
557 {
558 kshellWordsDestroy(pWords);
559 return NULL;
560 }
561
562 if (word.fFlags & KSWORD_FLAGS_ESCAPE)
563 {
564 int cch = word.cchWordOrg;
565 const char *pszSrc = word.pszWordOrg;
566 char * pszTrg = word.pszWord;
567 while (cch)
568 {
569 char ch;
570 if ((ch = *pszSrc) == pszSrc[1] && KSHELL_ESCAPABLE(ch))
571 pszSrc++;
572 *pszTrg++ = ch;
573 pszSrc++;
574 }
575 word.cchWord = pszTrg - word.pszWord;
576 *pszTrg = '\0';
577 }
578 else
579 {
580 if (word.fFlags & KSWORD_FLAGS_QUOTED)
581 {
582 word.cchWord = word.cchWordOrg - 2;
583 memcpy(word.pszWord, word.pszWordOrg + 1, word.cchWord);
584 }
585 else
586 {
587 word.cchWord = word.cchWordOrg;
588 memcpy(word.pszWord, word.pszWordOrg, word.cchWord);
589 }
590 word.pszWord[word.cchWord] = '\0';
591 }
592
593
594 /*
595 * Add to words structure.
596 */
597 if (!pWords || ((pWords->cWords + 1) % 32))
598 {
599 void *pv = realloc(pWords, sizeof(KSHELLWORDS) + ((pWords ? pWords->cWords : 0) + 32) * sizeof(KSHELLWORD));
600 if (!pv)
601 {
602 kshellWordsDestroy(pWords);
603 return NULL;
604 }
605 if (pWords)
606 pWords = pv;
607 else
608 {
609 pWords = pv;
610 pWords->cWords = 0;
611 }
612 }
613 pWords->aWords[pWords->cWords++] = word;
614 }
615
616 return pWords;
617}
618
619
620/**
621 * Destroys a words structure freeing it's memory.
622 * @param pWords Pointer to words structure to destroy.
623 */
624void kshellWordsDestroy(PKSHELLWORDS pWords)
625{
626 if (pWords)
627 {
628 int i;
629
630 for (i = 0; i < pWords->cWords; i++)
631 {
632 if (pWords->aWords[i].pszWord)
633 {
634 free(pWords->aWords[i].pszWord);
635 pWords->aWords[i].pszWord = NULL;
636 }
637 }
638
639 pWords->cWords = 0;
640 free(pWords);
641 }
642}
643
644
645/**
646 * Display an syntax message.
647 * @returns KSHELL_ERROR_SYNTAX_ERROR
648 * @param pszCmd The command name.
649 * @param pszMessage Message text.
650 */
651int kshellSyntaxError(const char *pszCmd, const char *pszMessage, ...)
652{
653 va_list args;
654 fflush(stdout);
655 fprintf(stderr, "Syntax error in '%s': ", pszCmd);
656 va_start(args, pszMessage);
657 vfprintf(stderr, pszMessage, args);
658 va_end(args);
659 fputs("\n", stderr);
660 return KSHELL_ERROR_SYNTAX_ERROR;
661}
662
663
664/**
665 * Display an generic message.
666 * @returns KSHELL_ERROR_SYNTAX_ERROR
667 * @param pszCmd The command name.
668 * @param pszMessage Message text.
669 */
670int kshellError(const char *pszCmd, const char *pszMessage, ...)
671{
672 va_list args;
673 fflush(stdout);
674
675 fprintf(stderr, "Error while '%s': ", pszCmd);
676 va_start(args, pszMessage);
677 vfprintf(stderr, pszMessage, args);
678 va_end(args);
679 fputs("\n", stderr);
680 return -1;
681}
682
683
684/**
685 * Execute program.
686 *
687 * @returns program return code.
688 * @returns 1742 (KSHELL_ERROR_PROGRAM_NOT_FOUND) if program wasn't found.
689 * @returns 1743 (KSHELL_ERROR_COMMAND_TOO_LONG) if program commandline was too long.
690 *
691 * @param pszCmd Pointer to commandline.
692 * @param pWords Pointer to 1st word in pszCmd.
693 */
694int kshellCmd_ExecuteProgram(const char *pszCmd, PKSHELLWORDS pWords)
695{
696 return -1;
697}
698
699
700/*
701 *
702 * The commands are documented externally.
703 * (Bad idea btw!)
704 *
705 */
706
707
708int kshellCmd_copy(const char *pszCmd, PKSHELLWORDS pWords)
709{
710 int iDst = pWords->cWords - 1; /* Last word is destination. */
711 KBOOL fDstDir = -1;
712 int iSrc;
713 int rc;
714
715 /*
716 * Syntax validation.
717 */
718 if (pWords->cWords < 3)
719 return kshellSyntaxError("copy", "too few arguments.");
720
721 /*
722 * Figure out if the destion is a directory or file specification.
723 */
724 if (KSHELL_ISSLASH(pWords->aWords[iDst].pszWord[pWords->aWords[iDst].cchWord - 1]))
725 {
726 fDstDir = TRUE;
727 while (KSHELL_ISSLASH(pWords->aWords[iDst].pszWord[pWords->aWords[iDst].cchWord - 1]))
728 pWords->aWords[iDst].cchWord--;
729 pWords->aWords[iDst].pszWord[pWords->aWords[iDst].cchWord] = '\0';
730 }
731 else
732 fDstDir = kDirExist(pWords->aWords[iDst].pszWord);
733
734 /*
735 * Copy sources to destination.
736 */
737 for (iSrc = 1, rc = 0; iSrc < iDst && !rc; iSrc++)
738 {
739 if (pWords->aWords[iSrc].fFlags & KSWORD_FLAGS_PATTERN)
740 {
741 /*
742 *
743 */
744 }
745 else
746 { /*
747 * Construct destination name.
748 */
749 char *pszDst;
750 KBOOL fDstFree = FALSE;
751 if (fDstDir)
752 {
753 fDstFree = TRUE;
754 pszDst = malloc(pWords->aWords[iDst].cchWord + 1 + pWords->aWords[iSrc].cchWord + 1);
755 if (pszDst)
756 return KSHELL_ERROR_NOT_ENOUGH_MEMORY;
757 kMemCpy(pszDst, pWords->aWords[iDst].pszWord, pWords->aWords[iDst].cchWord);
758 pszDst[pWords->aWords[iDst].cchWord] = KSHELL_SLASH;
759 kMemCpy(pszDst + pWords->aWords[iDst].cchWord + 1,
760 pWords->aWords[iSrc].pszWord,
761 pWords->aWords[iSrc].cchWord + 1);
762 }
763 else
764 pszDst = pWords->aWords[iDst].pszWord;
765
766 /*
767 * Do the copy.
768 */
769 #if 0 /* @todo implement this */
770 rc = kFileCopy(pWords->aWords[iSrc].pszWord, pszDst);
771 #endif
772 if (rc)
773 {
774 kshellError("copy", "failed to copy '%s' to '%s' rc=%d.",
775 pWords->aWords[iSrc].pszWord, pszDst, rc);
776 }
777
778 if (fDstFree)
779 free(pszDst);
780 }
781 }
782
783 return -1;
784}
785
786
787int kshellCmd_copytree(const char *pszCmd, PKSHELLWORDS pWords)
788{
789 return -1;
790}
791
792
793int kshellCmd_sync(const char *pszCmd, PKSHELLWORDS pWords)
794{
795 return -1;
796}
797
798
799int kshellCmd_synctree(const char *pszCmd, PKSHELLWORDS pWords)
800{
801 return -1;
802}
803
804
805int kshellCmd_rm(const char *pszCmd, PKSHELLWORDS pWords)
806{
807 return -1;
808}
809
810
811int kshellCmd_rmtree(const char *pszCmd, PKSHELLWORDS pWords)
812{
813 return -1;
814}
815
816
817int kshellCmd_chdir(const char *pszCmd, PKSHELLWORDS pWords)
818{
819 return -1;
820}
821
822
823int kshellCmd_mkdir(const char *pszCmd, PKSHELLWORDS pWords)
824{
825 return -1;
826}
827
828
829int kshellCmd_rmdir(const char *pszCmd, PKSHELLWORDS pWords)
830{
831 return -1;
832}
833
834
835int kshellCmd_set(const char *pszCmd, PKSHELLWORDS pWords)
836{
837 return -1;
838}
839
840
841int kshellCmd_unset(const char *pszCmd, PKSHELLWORDS pWords)
842{
843 return -1;
844}
845
846
847int kshellCmd_pushenv(const char *pszCmd, PKSHELLWORDS pWords)
848{
849 return -1;
850}
851
852
853int kshellCmd_popenv(const char *pszCmd, PKSHELLWORDS pWords)
854{
855 return -1;
856}
857
858
859/** @subsubsection echo
860 * Prints a message to stdout.
861 *
862 * <b>Syntax: echo <level> <message>
863 *
864 * Level is verbosity level of the message. This is compared with the
865 * KBUILD_MSG_LEVEL environment variable. The message is suppressed if the
866 * level is lower that KBUILD_MSG_LEVEL.
867 *
868 * The message is printed word for word normalize with a single space between
869 * the words. It's therefore a good thing to quote the message.
870 *
871 * The message can be empty. Then a blank line will be printed.
872 */
873int kshellCmd_echo(const char *pszCmd, PKSHELLWORDS pWords)
874{
875 int rc = KSHELL_ERROR_SYNTAX_ERROR;
876
877 /*
878 * Get the message level from the message.
879 */
880 if (pWords->cWords >= 2)
881 {
882 unsigned uMsgLevel = kStrToUDef(pWords->aWords[1].pszWord, -2, 0);
883 if (uMsgLevel != -2)
884 {
885 if (uMsgLevel <= kEnvGetUDef("KBUILD_MSG_LEVEL", 0, 0))
886 {
887 /* output all the words forcing one space separation */
888 pWords = kshellWordsParse(pszCmd, -1, pWords);
889 if (pWords)
890 {
891 int i;
892 for (i = 2; i < pWords->cWords; i++)
893 fwrite(pWords->aWords[i].pszWord, pWords->aWords[i].cchWord, 1, stdout);
894 }
895
896 /* new line */
897 fputc('\n', stdout);
898 fflush(stdout);
899 }
900 }
901 else
902 kshellSyntaxError("echo", "invalid message level!");
903 }
904 else
905 kshellSyntaxError("echo", "requires at least one argument!");
906
907 return -1;
908}
909
910
911int kshellCmd_write(const char *pszCmd, PKSHELLWORDS pWords)
912{
913 return -1;
914}
915
916
917
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette