2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
8 /******************************************************************************
24 Start a shell (interactive or background).
28 COMMAND -- command line to execute
30 FROM -- script to invoke before user interaction
37 The script file is not a script in execute sense (as you may not use any
38 .key, .bra or .ket and similar things).
42 shell FROM S:Startup-Sequence
44 Starts a shell and executes the startup script.
54 The prompt support is not using SetCurrentDirName() as this function
55 has improper limitations. More or less the same goes for GetProgramName().
57 ******************************************************************************/
62 * Break support (and +(0L) before execution) -- CreateNewProc()?
63 * Script file execution capabilities (if script bit set)
64 * $ must be taken care of differently than it is now so that things
65 like cd SYS:Olle/$pelle works
70 #include <aros/debug.h>
72 #include <exec/memory.h>
73 #include <exec/libraries.h>
74 #include <proto/exec.h>
76 #include <dos/dosextens.h>
78 #include <dos/filesystem.h>
80 #include <dos/stdio.h>
81 #include <proto/dos.h>
82 #include <proto/alib.h>
83 #include <proto/utility.h>
84 #include <utility/tagitem.h>
88 #include <aros/asmcall.h>
92 #include <aros/debug.h>
94 #define SH_GLOBAL_SYSBASE 1
95 #define SH_GLOBAL_DOSBASE 1
96 #include <aros/shcommands.h>
100 #define min(a,b) ((a) < (b)) ? (a) : (b)
102 #define COMMANDSTR_LEN (256 + 2) /* Maximum length of a 'command' */
103 #define FILENAME_LEN 256 /* Maximum length of a redirection filename */
117 STRPTR commandStr
; /* The command to execute */
118 STRPTR outFileName
; /* Redirection file for > or >> */
119 STRPTR inFileName
; /* Redirection file for < */
134 BPTR oldHomeDir
; /* shared lock on program file's parent directory */
137 BOOL residentCommand
; /* The last command executed was resident */
138 BOOL script
; /* This command has the script bit set */
143 struct CommandLineInterface
*cli
;
148 /* Function: convertLine
150 * Action: Parses a command line and returns a filtered version (removing
151 * redirections, incorporating embedded commands, taking care of
152 * variable references and aliases.
154 * Input: struct CSource *filtered -- output command string
155 * struct CSource *cs -- input string
156 * struct Redirection *rd -- state
158 * Output: BOOL -- FALSE if there was some error, TRUE otherwise
160 BOOL
convertLine(struct CSource
*filtered
, struct CSource
*cs
,
161 struct Redirection
*rd
);
164 /* Function: getCommand
168 * Input: struct CSource *filtered -- output buffer
169 * struct CSource *cs -- input string
170 * struct Redirection *rd -- state
172 * Output: BOOL -- FALSE if there was some error, TRUE otherwise
174 BOOL
getCommand(struct CSource
*filtered
, struct CSource
*cs
,
175 struct Redirection
*rd
);
179 /* Function: executeLine
181 * Action: Execute one line of commands
183 * Input: STRPTR command -- command
184 * STRPTR commandArgs -- arguments of the 'command'
185 * struct Redirection *rd -- state
187 * Output: LONG -- error code or 0 if everything went OK
189 LONG
executeLine(STRPTR command
, STRPTR commandArgs
, struct Redirection
*rd
);
192 /* Function: readLine
194 * Action: Read one line of a stream into a buffer.
196 * Input: struct CommandLine *cl -- the result will be stored
198 * BPTR inputStream -- stream to read the line from
200 * Note: This routine deals with buffering internally so "infinite" command
201 * lines are supported. You may specify NULL as the cl->line. The
202 * cl->line buffer may be disposed of by calling FreeVec().
204 * Output: BOOL -- FALSE if error, TRUE if everything went OK
206 BOOL
readLine(struct CommandLine
*cl
, BPTR inputStream
);
209 /* Function: checkLine
211 * Action: Parse a command line and do consistency checks
213 * Input: struct Redirection *rd -- state
214 * struct CommandLine *cl -- the command line
216 * Output: BOOL -- FALSE if error, TRUE if everything went OK
218 BOOL
checkLine(struct Redirection
*rd
, struct CommandLine
*cl
);
221 /* Function: releaseFiles
223 * Action: Deallocate file resources used for redirecion and reinstall
224 * standard input and output streams.
226 * Input: struct Redirection *rd -- state
230 void releaseFiles(struct Redirection
*rd
);
233 /* Function: appendString
235 * Action: Add a string to the filtered command line
237 * Input: struct CSource *cs -- output stream (command line)
238 * STRPTR from -- string to append
239 * LONG size -- number of chars to copy
241 * Output: BOOL -- success/failure indicator
243 BOOL
appendString(struct CSource
*cs
, STRPTR from
, LONG size
);
246 /* Function: printFlush
248 * Action: Do a formatted print that will instantly be displayed.
250 * Input: STRPTR fmt -- format string
253 * Output: BOOL -- success/failure indicator
255 #define printFlush(format...) do {Printf(format); Flush(Output());} while (0)
257 /* Function: interact
259 * Action: Execute a commandfile and then perform standard shell user
262 * Input: STRPTR script -- command file to execute before interacting
265 * Output: LONG -- error code
270 /* Function: loadCommand
272 * Action: Load a command, searching the paths, C: and the resident lists.
274 * Input: STRPTR commandName -- the command to load
275 * struct ShellState *ss -- state
277 * Output: BPTR -- segment of the loaded command or NULL if there was an
280 BPTR
loadCommand(STRPTR commandName
, struct ShellState
*ss
);
283 /* Function: unloadCommand
285 * Action: Free the resources held by a (loaded) command.
287 * Input: BPTR commandSeg -- segment of the program to
289 * struct ShellState *ss -- state
293 void unloadCommand(BPTR commandSeg
, struct ShellState
*ss
);
296 /* Function: Redirection_release
298 * Action: Release resources allocated in the state
300 * Input: struct Redirection *rd -- state
304 void Redirection_release(struct Redirection
*rd
);
307 /* Function: Redirection_init
309 * Action: Initialize a state structure
311 * Input: struct Redirection *rd -- state
313 * Output: BOOL -- success/failure indicator
315 BOOL
Redirection_init(struct Redirection
*rd
);
320 * Action: Set the current command (standard) path.
322 * Input: BPTR lock -- a lock on the directory
324 * Notes: This will set the current directory name via
325 * SetCurrentDirName() eventhough this is not used later.
329 static void setPath(BPTR lock
);
332 /* Function: printPath
334 * Action: Print the current command path to Output().
338 * Notes: Used for Prompt purposes.
342 static void printPath(void);
345 /* Function: printPrompt
347 * Action: Print the prompt to indicate that user input is viable.
353 static void printPrompt(void);
356 /*****************************************************************************/
357 void setupResidentCommands(void);
358 #define PROCESS(x) ((struct Process *)(x))
360 AROS_SH1(Shell
, 41.1,
361 AROS_SHA(STRPTR
, ,COMMAND
,/F
,NULL
))
365 LONG error
= RETURN_OK
;
367 D(bug("Executing shell\n"));
369 UtilityBase
= (struct UtilityBase
*)OpenLibrary("utility.library", 39);
370 if (!UtilityBase
) return RETURN_FAIL
;
372 setupResidentCommands();
377 if (strcmp(FindTask(NULL
)->tc_Node
.ln_Name
, "Boot Shell") == 0)
380 if(SHArg(COMMAND
) && SHArg(COMMAND
)[0])
382 struct Redirection rd
;
383 struct CommandLine cl
= {SHArgLine(),
385 strlen(SHArg(COMMAND
))};
387 if(Redirection_init(&rd
))
389 D(bug("Running command %s\n", SHArg(COMMAND
)));
390 error
= checkLine(&rd
, &cl
);
391 Redirection_release(&rd
);
394 D(bug("Command done\n"));
401 D(bug("Exiting shell\n"));
408 struct UtilityBase
*UtilityBase
;
410 void setupResidentCommands(void)
417 /* First we execute the script, then we interact with the user */
420 ULONG cliNumber
= PROCESS(FindTask(NULL
))->pr_TaskNum
;
422 BOOL moreLeft
= FALSE
;
424 if (!cli
->cli_Background
)
426 SetVBuf(Output(), NULL
, BUF_FULL
, -1);
427 if (strcmp(FindTask(NULL
)->tc_Node
.ln_Name
, "Boot Shell") == 0)
431 "AROS - The Amiga® Research Operating System\n"
432 "Copyright © 1995-2003, The AROS Development Team. All rights reserved.\n"
433 "AROS is licensed under the terms of the AROS Public License (APL),\n"
434 "a copy of which you should have received with this distribution.\n"
435 "Visit http://www.aros.org/ for more information.\n"
440 IPTR data
[] = {(IPTR
)cliNumber
};
442 VPrintf("New Shell process %ld\n", data
);
444 SetVBuf(Output(), NULL
, BUF_LINE
, -1);
449 struct CommandLine cl
= { NULL
, 0, 0 };
450 struct Redirection rd
;
452 if(Redirection_init(&rd
))
454 if (cli
->cli_Interactive
)
457 moreLeft
= readLine(&cl
, cli
->cli_CurrentInput
);
458 error
= checkLine(&rd
, &cl
);
460 Redirection_release(&rd
);
466 if (!cli
->cli_Interactive
)
468 Close(cli
->cli_CurrentInput
);
470 if (AROS_BSTR_strlen(cli
->cli_CommandFile
))
472 DeleteFile(AROS_BSTR_ADDR(cli
->cli_CommandFile
));
473 AROS_BSTR_setstrlen(cli
->cli_CommandFile
, 0);
476 if (!cli
->cli_Background
)
478 cli
->cli_CurrentInput
= cli
->cli_StandardInput
;
479 cli
->cli_Interactive
= TRUE
;
488 if (cli
->cli_Interactive
) printFlush("Process %ld ending\n", cliNumber
);
494 /* Close redirection files and install regular input and output streams */
495 void releaseFiles(struct Redirection
*rd
)
497 if (rd
->newIn
) Close(rd
->newIn
);
500 if (rd
->newOut
) Close(rd
->newOut
);
509 /* Take care of one command line */
510 BOOL
checkLine(struct Redirection
*rd
, struct CommandLine
*cl
)
512 /* The allocation is taken care of by appendString */
513 struct CSource filtered
= { NULL
, 0, 0 };
514 struct CSource cs
= { cl
->line
, strlen(cl
->line
), 0 };
518 lv
= FindVar("echo", LV_VAR
);
521 /* AmigaDOS' shell is content also with echo being set to anything
522 that begins with "on" in order to trigger commands echoing on,
523 it doesn't really have to be set to just "on". */
525 if (strncasecmp(lv
->lv_Value
, "on", 2) == 0)
527 /* Ok, commands echoing is on. */
532 D(bug("Calling convertLine(), line = %s\n", cl
->line
));
534 if(convertLine(&filtered
, &cs
, rd
))
536 D(bug("Position %i\n", filtered
.CS_CurChr
));
539 appendString(&filtered
, "\n\0", 2);
541 /* Consistency checks */
542 if(rd
->haveOutRD
&& rd
->haveAppRD
)
544 PutStr("Cannot combine > with >>\n");
548 /* Only a comment? */
555 /* stegerg: Set redirection to default in/out handles */
559 D(bug("Redirecting output to file %s\n", rd
->outFileName
));
561 rd
->newOut
= Open(rd
->outFileName
, MODE_NEWFILE
);
563 if(BADDR(rd
->newOut
) == NULL
)
565 PrintFault(IoErr(), rd
->outFileName
);
569 D(bug("Output stream opened\n"));
570 SelectOutput(rd
->newOut
);
575 rd
->newOut
= Open(rd
->outFileName
, (FMF_MODE_OLDFILE
| FMF_CREATE
| FMF_APPEND
) & ~FMF_AMIGADOS
);
577 if(BADDR(rd
->newOut
) == NULL
)
579 PrintFault(IoErr(), rd
->outFileName
);
583 D(bug("Output stream opened (append)\n"));
584 SelectOutput(rd
->newOut
);
589 rd
->newIn
= Open(rd
->inFileName
, MODE_OLDFILE
/*FMF_READ*/);
591 if(BADDR(rd
->newIn
) == NULL
)
593 PrintFault(IoErr(), rd
->inFileName
);
597 D(bug("Input stream opened\n"));
598 SelectInput(rd
->newIn
);
601 D(bug("Calling executeLine()\n"));
603 /* OK, we've got a command. Let's execute it! */
604 executeLine(rd
->commandStr
, filtered
.CS_Buffer
, rd
);
606 SelectInput(cli
->cli_StandardInput
);
607 SelectOutput(cli
->cli_StandardOutput
);
612 PutStr("Erroneous command line.\n");
616 FreeVec(filtered
.CS_Buffer
);
618 if (cli
->cli_Interactive
)
627 /* The shell has the following semantics when it comes to command lines:
628 Redirection (<,>,>>) may be written anywhere (except before the command
629 itself); the following item (as defined by ReadItem() is the redirection
630 file. The first item of the command line is the command to be executed.
631 This may be an alias, that is there is a Local LV_ALIAS variable that
632 should be substituted for the command text. Aliasing only applies to
633 commands and not to options, for instance. Variables (set by SetEnv or Set)
634 may be referenced by prepending a '$' to the variable name. */
636 BOOL
convertLine(struct CSource
*filtered
, struct CSource
*cs
,
637 struct Redirection
*rd
)
640 #define item cs->CS_Buffer[cs->CS_CurChr]
641 #define from cs->CS_Buffer
642 #define advance(x) cs->CS_CurChr += x;
648 D(bug("Str: %s\n", cs
->CS_Buffer
+cs
->CS_CurChr
));
650 while(item
== ' ' || item
== '\t')
656 appendString(filtered
, temp
, 1);
660 /* Are we done yet? */
661 if(item
== '\n' || item
== ';' || item
== '\0')
666 BPTR pipefhs
[2] = {0, 0};
668 struct TagItem tags
[] =
670 { SYS_Input
, (IPTR
) NULL
},
671 { SYS_Output
, SYS_DupStream
},
672 { SYS_Error
, SYS_DupStream
},
673 { SYS_Asynch
, TRUE
},
674 { NP_StackSize
, Cli()->cli_DefaultStack
* CLI_DEFAULTSTACK_UNIT
},
678 /* Prevent command lines like "Prompt> | Olle echo Oepir" */
684 /* There must be something after a pipe... */
687 i
= cs
->CS_CurChr
+ 1;
688 cs
->CS_Buffer
[i
] == ' ' || cs
->CS_Buffer
[i
] == '\t';
692 if(cs
->CS_Buffer
[i
] == '\n' || cs
->CS_Buffer
[i
] == ';' || cs
->CS_Buffer
[i
] == '\0')
694 SetIoErr(ERROR_LINE_TOO_LONG
); /* what kind of error must we report? */
698 D(bug("commannd = %S\n", &item
+1));
702 if (SystemTagList(&item
+1, tags
) == -1)
707 if (Pipe("PIPEFS:", &pipefhs
[0], &pipefhs
[1]) != DOSTRUE
)
710 tags
[0].ti_Data
= (IPTR
)pipefhs
[0];
712 if (SystemTagList(&item
+1, tags
) == -1)
720 rd
->oldOut
= SelectOutput(pipefhs
[1]);
721 rd
->newOut
= pipefhs
[1];
727 /* Prevent command lines like "Prompt> <Olle type" */
731 /* Multiple redirections not allowed */
736 result
= ReadItem(rd
->inFileName
, FILENAME_LEN
, cs
);
738 D(bug("Found input redirection\n"));
740 if(result
== ITEM_ERROR
|| result
== ITEM_NOTHING
)
747 /* Prevent command lines like "Prompt> >>Olle echo Oepir" */
755 /* Multiple redirections not allowed */
760 result
= ReadItem(rd
->outFileName
, FILENAME_LEN
, cs
);
762 D(bug("Found append redirection\n"));
764 if(result
== ITEM_ERROR
|| result
== ITEM_NOTHING
)
767 rd
->haveAppRD
= TRUE
;
771 /* Multiple redirections not allowed */
775 result
= ReadItem(rd
->outFileName
, FILENAME_LEN
, cs
);
777 D(bug("Found output redirection\n"));
779 if(result
== ITEM_ERROR
|| result
== ITEM_NOTHING
)
782 rd
->haveOutRD
= TRUE
;
786 /* Possible environment variable usage */
788 LONG size
= cs
->CS_CurChr
;
791 result
= ReadItem(avBuffer
, sizeof(avBuffer
), cs
);
793 D(bug("Found variable\n"));
795 if(result
== ITEM_ERROR
|| ITEM_NOTHING
)
800 (GetVar(avBuffer
, varBuffer
, sizeof(varBuffer
),
801 GVF_GLOBAL_ONLY
| LV_VAR
) != -1) &&
802 !(varBuffer
[0] == '$' && !strcmp(varBuffer
+1, avBuffer
))
805 struct CSource varCs
= { varBuffer
, sizeof(varBuffer
), 0 };
807 D(bug("Real variable! Value = %s\n", varBuffer
));
809 if(convertLine(filtered
, &varCs
, rd
) == FALSE
)
813 /* If this "variable" wasn't defined, we use the '$' as a
816 D(bug("No real variable\n"));
820 cs
->CS_CurChr
= size
;
821 getCommand(filtered
, cs
, rd
);
824 appendString(filtered
, cs
->CS_Buffer
+ size
,
825 cs
->CS_CurChr
- size
);
831 /* This is a regular character -- that is, we have a command */
834 D(bug("Found possible command\n"));
836 getCommand(filtered
, cs
, rd
);
841 LONG size
= cs
->CS_CurChr
;
843 // P(kprintf("Checking argument\n"));
845 result
= ReadItem(argBuffer
, sizeof(argBuffer
), cs
);
847 // D(bug("Found possible argument\n"));
849 if(result
== ITEM_ERROR
|| ITEM_NOTHING
)
852 appendString(filtered
, from
+ size
, cs
->CS_CurChr
- size
);
856 D(bug("Found argument %s\n", argBuffer
));
861 D(bug("Exiting convertLine()\n"));
869 BOOL
getCommand(struct CSource
*filtered
, struct CSource
*cs
,
870 struct Redirection
*rd
)
874 rd
->haveCommand
= TRUE
;
876 D(bug("Command found!\n"));
878 result
= ReadItem(rd
->commandStr
, COMMANDSTR_LEN
, cs
);
880 if(result
== ITEM_ERROR
|| result
== ITEM_NOTHING
)
883 /* Is this command an alias? */
884 if(GetVar(rd
->commandStr
, avBuffer
, sizeof(avBuffer
),
885 GVF_LOCAL_ONLY
| LV_ALIAS
) != -1)
887 struct CSource aliasCs
= { avBuffer
, sizeof(avBuffer
), 0 };
889 result
= ReadItem(rd
->commandStr
, COMMANDSTR_LEN
, &aliasCs
);
891 D(bug("Found alias! value = %s\n", avBuffer
));
893 if(result
== ITEM_ERROR
|| result
== ITEM_NOTHING
)
896 /* We don't check if the alias was an alias as that might
897 lead to infinite loops (alias Copy Copy) */
899 /* Make a recursive call to take care of the rest of the
901 return convertLine(filtered
, &aliasCs
, rd
);
904 D(bug("Command = %s\n", rd
->commandStr
));
913 #define __extendSize 512 /* How much to increase buffer if it's full */
916 BOOL
readLine(struct CommandLine
*cl
, BPTR inputStream
)
922 letter
= inputStream
? FGetC(inputStream
) : EOF
;
924 D(bug("Read character %c (%d)\n", letter
, letter
));
926 /* -2 to skip test for boundary for terminating '\n\0' */
927 if(cl
->position
> (cl
->size
- 2))
929 STRPTR newString
= AllocVec(cl
->size
+ __extendSize
, MEMF_ANY
);
931 D(bug("Allocated new buffer %p\n", newString
));
934 CopyMem(cl
->line
, newString
, cl
->size
);
936 cl
->size
+= __extendSize
;
938 cl
->line
= newString
;
941 if(letter
== '\n' || letter
== EOF
)
943 D(bug("Found end of line\n"));
947 cl
->line
[cl
->position
++] = letter
;
950 /* Terminate the line with a newline and a NULL terminator */
951 cl
->line
[cl
->position
++] = '\n';
952 cl
->line
[cl
->position
++] = '\0';
954 D(bug("commandline: %s\n", cl
->line
));
963 /* Currently, there is no error checking involved */
964 BOOL
appendString(struct CSource
*cs
, STRPTR fromStr
, LONG size
)
966 /* +2 for additional null bytes, '\n', \0' */
967 while(cs
->CS_CurChr
+ size
+ 2 > (cs
->CS_Length
- cs
->CS_CurChr
))
969 STRPTR newString
= AllocVec(cs
->CS_Length
+ __extendSize
, MEMF_ANY
);
971 CopyMem(cs
->CS_Buffer
, newString
, cs
->CS_Length
);
972 cs
->CS_Length
+= __extendSize
;
973 FreeVec(cs
->CS_Buffer
);
974 cs
->CS_Buffer
= newString
;
979 cs
->CS_Buffer
[cs
->CS_CurChr
++] = *fromStr
++;
986 void unloadCommand(BPTR commandSeg
, struct ShellState
*ss
)
989 if (!cli
->cli_Module
) return;
991 if(ss
->residentCommand
)
993 struct Segment
*residentSeg
= (struct Segment
*)BADDR(commandSeg
);
997 /* Decrease usecount */
998 if(residentSeg
->seg_UC
> 0)
999 residentSeg
->seg_UC
--;
1003 ss
->residentCommand
= FALSE
;
1006 UnLoadSeg(commandSeg
);
1009 if (ss
->homeDirChanged
)
1011 UnLock(SetProgramDir(ss
->oldHomeDir
));
1012 ss
->homeDirChanged
= FALSE
;
1018 BPTR
loadCommand(STRPTR commandName
, struct ShellState
*ss
)
1021 BPTR commandSeg
= NULL
;
1023 struct Segment
*residentSeg
;
1024 BOOL absolutePath
= strpbrk(commandName
, "/:") != NULL
;
1027 /* We check the resident lists only if we do not have an absolute path */
1032 /* Check regular list first... */
1033 residentSeg
= FindSegment(commandName
, NULL
, FALSE
);
1035 if(residentSeg
== NULL
)
1037 /* ... then the system list */
1038 residentSeg
= FindSegment(commandName
, NULL
, TRUE
);
1041 if(residentSeg
!= NULL
)
1043 /* Can we use this command? */
1044 if(residentSeg
->seg_UC
== CMD_INTERNAL
|| residentSeg
->seg_UC
>= 0)
1046 if(residentSeg
->seg_UC
>= 0)
1047 residentSeg
->seg_UC
++;
1049 ss
->residentCommand
= TRUE
;
1051 return MKBADDR(residentSeg
);
1058 ss
->residentCommand
= FALSE
;
1060 D(bug("Trying to load command1: %s\n", commandName
));
1062 oldCurDir
= CurrentDir(NULL
);
1063 CurrentDir(oldCurDir
);
1065 file
= Open(commandName
, MODE_OLDFILE
);
1071 absolutePath
|| /* If this was an absolute path, we don't check the paths set by
1072 'path' or the C: multiassign */
1073 IoErr() == ERROR_OBJECT_IN_USE
/* The object might be exclusively locked */
1077 /* Search the command in the path */
1081 paths
= (BPTR
*)BADDR(cli
->cli_CommandDir
);
1082 file
== NULL
&& paths
!= NULL
;
1083 paths
= (BPTR
*)BADDR(paths
[0]) /* Go on with the next path */
1086 CurrentDir(paths
[1]);
1087 file
= Open(commandName
, MODE_OLDFILE
);
1090 /* The last resort -- the C: multiassign */
1094 file
= Open(commandName
, MODE_OLDFILE
);
1100 commandSeg
= LoadSeg(commandName
);
1105 BPTR lock
= ParentOfFH(file
);
1109 ss
->oldHomeDir
= SetProgramDir(lock
);
1110 ss
->homeDirChanged
= TRUE
;
1116 struct FileInfoBlock fib
;
1117 if (Examine(file
, &fib
) && fib
.fib_Protection
& FIBF_SCRIPT
)
1119 commandSeg
= LoadSeg("C:Execute");
1123 ss
->scriptLock
= Lock(commandName
, SHARED_LOCK
);
1127 SetIoErr(ERROR_FILE_NOT_OBJECT
);
1133 CurrentDir(oldCurDir
);
1139 /* Execute one command */
1140 LONG
executeLine(STRPTR command
, STRPTR commandArgs
, struct Redirection
*rd
)
1144 struct ShellState ss
= {FALSE
};
1150 if ss->residentCommand isn't initialized as FALSE, it's value is rather
1151 random ( loadCommand doesn't change it ) so unloadCommand almost always
1152 thinks that last Command was resident, and doesn't do an UnloadSeg...
1155 D(bug("Trying to load command: %s\nArguments: %s\n", command
,
1158 module
= loadCommand(command
, &ss
);
1160 /* Set command name even if we couldn't load the command to be able to
1161 report errors correctly */
1162 SetProgramName(command
);
1166 struct Task
*me
= FindTask(NULL
);
1167 STRPTR oldtaskname
= me
->tc_Node
.ln_Name
;
1171 BPTR seglist
= ss
.residentCommand
? ((struct Segment
*)BADDR(module
))->seg_Seg
:module
;
1173 STRPTR dst
= cmd
, src
;
1179 NameFromLock(ss
.scriptLock
, dst
, sizeof(cmd
));
1180 while (*dst
!= '\0')
1187 UnLock(ss
.scriptLock
);
1191 for (src
= commandArgs
; *src
!= '\0'; ++dst
, ++src
, ++len
)
1195 D(bug("Command loaded: len=%d, %s\n", len
, cmd
));
1197 SetIoErr(0); /* Clear error before we execute this command */
1198 SetSignal(0, SIGBREAKF_CTRL_C
);
1200 cli
->cli_Module
= seglist
;
1202 me
->tc_Node
.ln_Name
= command
;
1204 __debug_mem
= FindVar("__debug_mem", LV_VAR
) != NULL
;
1208 FreeVec(AllocVec(~0ul/2, MEMF_ANY
)); /* Flush memory */
1210 mem_before
= AvailMem(MEMF_ANY
);
1211 Printf("Available total memory before command execution: %10ld\n", mem_before
);
1214 cli
->cli_ReturnCode
= RunCommand(seglist
, cli
->cli_DefaultStack
* CLI_DEFAULTSTACK_UNIT
,
1219 FreeVec(AllocVec(~0ul/2, MEMF_ANY
)); /* Flush memory */
1221 mem_after
= AvailMem(MEMF_ANY
);
1222 Printf("Available total memory after command execution: %10ld\n", mem_after
);
1223 Printf("Memory difference (before - after): %10ld\n", mem_before
- mem_after
);
1226 me
->tc_Node
.ln_Name
= oldtaskname
;
1228 D(bug("Returned from command %s\n", command
));
1229 unloadCommand(module
, &ss
);
1231 cli
->cli_Result2
= IoErr();
1236 if(!(rd
->haveInRD
|| rd
->haveOutRD
|| rd
->haveAppRD
) && (IoErr() == ERROR_OBJECT_WRONG_TYPE
|| IoErr() == ERROR_OBJECT_NOT_FOUND
))
1238 BPTR lock
= Lock(command
, SHARED_LOCK
);
1242 struct FileInfoBlock
*fib
= AllocDosObject(DOS_FIB
, NULL
);
1246 if(Examine(lock
, fib
))
1248 if(fib
->fib_DirEntryType
> 0)
1251 lock
= CurrentDir(lock
);
1254 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
1257 FreeDosObject(DOS_FIB
, fib
);
1260 /* UnLock the old currentdir */
1267 cli
->cli_Result2
= IoErr();
1268 PrintFault(IoErr(), command
);
1272 D(bug("Done with the command...\n"));
1278 BOOL
Redirection_init(struct Redirection
*rd
)
1280 bzero(rd
, sizeof(struct Redirection
));
1282 rd
->commandStr
= AllocVec(COMMANDSTR_LEN
, MEMF_CLEAR
);
1284 rd
->outFileName
= AllocVec(FILENAME_LEN
, MEMF_CLEAR
);
1285 rd
->inFileName
= AllocVec(FILENAME_LEN
, MEMF_CLEAR
);
1287 if(rd
->commandStr
== NULL
|| rd
->outFileName
== NULL
||
1288 rd
->inFileName
== NULL
)
1290 Redirection_release(rd
);
1294 /* Preset the first bytes to "C:" to handle C: multiassigns */
1295 *rd
->commandStr
++ = 'C';
1296 *rd
->commandStr
++ = ':';
1302 void Redirection_release(struct Redirection
*rd
)
1304 /* -2 as we set pointer 2 bytes ahead to be able to use C: as a multi-
1305 assign in a smooth way */
1306 FreeVec(rd
->commandStr
- 2);
1307 FreeVec(rd
->outFileName
);
1308 FreeVec(rd
->inFileName
);
1313 static void printPath(void)
1318 for(i
= 256; ; i
+= 256)
1320 buf
= AllocVec(i
, MEMF_ANY
);
1325 if(GetCurrentDirName(buf
, i
) == DOSTRUE
)
1327 FPuts(Output(), buf
);
1334 if(IoErr() != ERROR_OBJECT_TOO_LARGE
)
1340 static void setPath(BPTR lock
)
1347 dir
= CurrentDir(NULL
);
1351 for(i
= 256; ; i
+= 256)
1353 buf
= AllocVec(i
, MEMF_ANY
);
1358 if(NameFromLock(dir
, buf
, i
))
1360 SetCurrentDirName(buf
);
1372 static void printPrompt(void)
1374 BSTR prompt
= Cli()->cli_Prompt
;
1375 LONG length
= AROS_BSTR_strlen(prompt
);
1378 for(i
= 0; i
< length
; i
++)
1380 if(AROS_BSTR_getchar(prompt
, i
) == '%')
1387 switch(AROS_BSTR_getchar(prompt
, i
))
1391 Printf("%ld", PROCESS(FindTask(NULL
))->pr_TaskNum
);
1395 Printf("%ld", Cli()->cli_ReturnCode
);
1402 FPutC(Output(), '%');
1403 FPutC(Output(), AROS_BSTR_getchar(prompt
, i
));
1408 FPutC(Output(), AROS_BSTR_getchar(prompt
, i
));