123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- alias.c
- Abstract:
- This module implements support for alias substitution in the shell.
- Author:
- Evan Green 12-Jun-2013
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "sh.h"
- #include "shparse.h"
- #include "../swlib.h"
- #include <assert.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- VOID
- ShDestroyAlias (
- PSHELL_ALIAS Alias
- );
- PSHELL_ALIAS
- ShLookupAlias (
- PSHELL Shell,
- PSTR Name,
- ULONG NameSize
- );
- BOOL
- ShPrintAlias (
- PSHELL_ALIAS Alias
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- BOOL ShDebugAlias = FALSE;
- //
- // ------------------------------------------------------------------ Functions
- //
- BOOL
- ShPerformAliasSubstitution (
- PSHELL Shell
- )
- /*++
- Routine Description:
- This routine destroys all the aliases in a shell. It is usually called
- during cleanup.
- Arguments:
- Shell - Supplies a pointer to the shell whose aliases will be cleaned up.
- Return Value:
- TRUE on success (either looking it up and substituting or looking it up and
- finding nothing).
- FALSE on failure.
- --*/
- {
- PSHELL_ALIAS Alias;
- PSHELL_LEXER_STATE Lexer;
- BOOL Result;
- Lexer = &(Shell->Lexer);
- Alias = ShLookupAlias(Shell, Lexer->TokenBuffer, Lexer->TokenBufferSize);
- if (Alias == NULL) {
- Result = TRUE;
- goto PerformAliasSubstitutionEnd;
- }
- //
- // If this alias is recursive (ie ls='ls -la') then don't take the bait.
- //
- if (Alias == Lexer->LastAlias) {
- if (ShDebugAlias != FALSE) {
- ShPrintTrace(Shell, "AliasSkipped: %s\n", Lexer->LastAlias->Name);
- }
- Result = TRUE;
- goto PerformAliasSubstitutionEnd;
- }
- assert((Alias->Value != NULL) && (Alias->ValueSize >= 1));
- if (ShDebugAlias != FALSE) {
- ShPrintTrace(Shell,
- "Aliasing '%s', replacing with '%s'\n",
- Lexer->TokenBuffer,
- Alias->Value);
- }
- //
- // If the unput character is valid, it needs to be rolled back into the
- // input too before this replacement text is spliced in. Most of the time
- // this is easy, it can just be put in some earlier space in the buffer.
- //
- if (Lexer->UnputCharacterValid != FALSE) {
- if (Lexer->InputBufferNextIndex != 0) {
- Lexer->InputBufferNextIndex -= 1;
- Lexer->InputBuffer[Lexer->InputBufferNextIndex] =
- Lexer->UnputCharacter;
- //
- // There's no space for the unput character, so bring out the heavy
- // artillery.
- //
- } else {
- Result = SwStringReplaceRegion(&(Lexer->InputBuffer),
- &(Lexer->InputBufferSize),
- &(Lexer->InputBufferCapacity),
- 0,
- 0,
- &(Lexer->UnputCharacter),
- 2);
- if (Result == FALSE) {
- goto PerformAliasSubstitutionEnd;
- }
- }
- Lexer->UnputCharacterValid = FALSE;
- }
- //
- // The substitution needs to be performed. Put the value onto the input
- // buffer. Start by expanding the buffer if needed.
- //
- Result = SwStringReplaceRegion(&(Lexer->InputBuffer),
- &(Lexer->InputBufferSize),
- &(Lexer->InputBufferCapacity),
- Lexer->InputBufferNextIndex,
- Lexer->InputBufferNextIndex,
- Alias->Value,
- Alias->ValueSize);
- if (Result == FALSE) {
- goto PerformAliasSubstitutionEnd;
- }
- //
- // Clear out this input token, as it was replaced. Also mark this alias as
- // the previous one so that if the value of this alias is recursive this
- // doesn't result in an infinite loop.
- //
- Lexer->TokenBufferSize = 0;
- Lexer->TokenType = -1;
- Lexer->LastAlias = Alias;
- Result = TRUE;
- PerformAliasSubstitutionEnd:
- return Result;
- }
- VOID
- ShDestroyAliasList (
- PSHELL Shell
- )
- /*++
- Routine Description:
- This routine destroys all the aliases in a shell. It is usually called
- during cleanup.
- Arguments:
- Shell - Supplies a pointer to the shell whose aliases will be cleaned up.
- Return Value:
- None.
- --*/
- {
- PSHELL_ALIAS Alias;
- while (LIST_EMPTY(&(Shell->AliasList)) == FALSE) {
- Alias = LIST_VALUE(Shell->AliasList.Next, SHELL_ALIAS, ListEntry);
- LIST_REMOVE(&(Alias->ListEntry));
- ShDestroyAlias(Alias);
- }
- return;
- }
- INT
- ShBuiltinAlias (
- PSHELL Shell,
- INT ArgumentCount,
- PSTR *Arguments
- )
- /*++
- Routine Description:
- This routine implements the builtin alias statement.
- Arguments:
- Shell - Supplies a pointer to the shell being run in.
- ArgumentCount - Supplies the number of arguments on the command line.
- Arguments - Supplies the array of pointers to strings representing each
- argument. Arguments are in the form name=value, where name will get
- substituted for value when it is found as the first word in a command.
- Return Value:
- 0 on success.
- 1 if an alias was not found.
- --*/
- {
- PSHELL_ALIAS Alias;
- PSTR Argument;
- INT ArgumentIndex;
- UINTN ArgumentSize;
- PLIST_ENTRY CurrentEntry;
- PSTR Equals;
- PSTR Name;
- UINTN NameSize;
- BOOL Result;
- ULONG ReturnValue;
- PSTR Value;
- UINTN ValueSize;
- Alias = NULL;
- Name = NULL;
- Value = NULL;
- //
- // If there are no arguments, then print all the aliases.
- //
- if (ArgumentCount == 1) {
- CurrentEntry = Shell->AliasList.Next;
- while (CurrentEntry != &(Shell->AliasList)) {
- Alias = LIST_VALUE(CurrentEntry, SHELL_ALIAS, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- Result = ShPrintAlias(Alias);
- if (Result == FALSE) {
- return 1;
- }
- }
- return 0;
- }
- //
- // Loop through each argument and create or print the alias.
- //
- ReturnValue = 0;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- ArgumentSize = strlen(Argument) + 1;
- Equals = strchr(Argument, '=');
- if ((Equals == NULL) || (Equals == Argument)) {
- Alias = ShLookupAlias(Shell, Argument, ArgumentSize);
- if (Alias == NULL) {
- PRINT_ERROR("Alias %s not found.\n", Argument);
- ReturnValue = 1;
- } else {
- ShPrintAlias(Alias);
- }
- Alias = NULL;
- continue;
- }
- //
- // Create or replace the alias.
- //
- NameSize = (UINTN)Equals - (UINTN)Argument + 1;
- Alias = ShLookupAlias(Shell, Argument, NameSize);
- if (Alias == NULL) {
- Alias = malloc(sizeof(SHELL_ALIAS));
- if (Alias == NULL) {
- ReturnValue = 1;
- goto BuiltinAliasEnd;
- }
- memset(Alias, 0, sizeof(SHELL_ALIAS));
- Name = SwStringDuplicate(Argument, NameSize);
- if (Name == NULL) {
- ReturnValue = 1;
- goto BuiltinAliasEnd;
- }
- Alias->Name = Name;
- Alias->NameSize = NameSize;
- }
- //
- // Create a copy of the value, and add a space onto the end of it.
- //
- ValueSize = ArgumentSize - NameSize + 1;
- assert(ValueSize >= 2);
- Value = malloc(ValueSize);
- if (Value == NULL) {
- ReturnValue = 1;
- goto BuiltinAliasEnd;
- }
- memcpy(Value, Equals + 1, ValueSize - 1);
- Value[ValueSize - 2] = ' ';
- Value[ValueSize - 1] = '\0';
- if (Alias->Value != NULL) {
- free(Alias->Value);
- }
- Alias->Value = Value;
- Alias->ValueSize = ValueSize;
- if (Alias->ListEntry.Next == NULL) {
- INSERT_BEFORE(&(Alias->ListEntry), &(Shell->AliasList));
- }
- Alias = NULL;
- Name = NULL;
- Value = NULL;
- }
- BuiltinAliasEnd:
- if (Alias != NULL) {
- free(Alias);
- }
- if (Name != NULL) {
- free(Name);
- }
- if (Value != NULL) {
- free(Value);
- }
- return ReturnValue;
- }
- INT
- ShBuiltinUnalias (
- PSHELL Shell,
- INT ArgumentCount,
- PSTR *Arguments
- )
- /*++
- Routine Description:
- This routine implements the builtin unalias statement.
- Arguments:
- Shell - Supplies a pointer to the shell being run in.
- ArgumentCount - Supplies the number of arguments on the command line.
- Arguments - Supplies the array of pointers to strings representing each
- argument. Arguments are in the form name=value, where name will get
- substituted for value when it is found as the first word in a command.
- Return Value:
- 0 on success.
- 1 if an alias was not found.
- --*/
- {
- PSHELL_ALIAS Alias;
- PSTR Argument;
- ULONG ArgumentIndex;
- INT ReturnValue;
- ReturnValue = 0;
- for (ArgumentIndex = 1; ArgumentIndex < ArgumentCount; ArgumentIndex += 1) {
- Argument = Arguments[ArgumentIndex];
- //
- // The -a flag destroys all aliases.
- //
- if (strcmp(Argument, "-a") == 0) {
- ShDestroyAliasList(Shell);
- return 0;
- }
- Alias = ShLookupAlias(Shell, Argument, strlen(Argument) + 1);
- if (Alias == NULL) {
- PRINT_ERROR("Alias %s not found.\n", Argument);
- ReturnValue = 1;
- } else {
- LIST_REMOVE(&(Alias->ListEntry));
- ShDestroyAlias(Alias);
- }
- }
- return ReturnValue;
- }
- PSHELL_ALIAS
- ShLookupAlias (
- PSHELL Shell,
- PSTR Name,
- ULONG NameSize
- )
- /*++
- Routine Description:
- This routine looks up the given name and tries to find an alias for it.
- Arguments:
- Shell - Supplies a pointer to the shell to search.
- Name - Supplies a pointer to the name to search for.
- NameSize - Supplies the size of the name buffer in bytes including the
- null terminator.
- Return Value:
- Returns a pointer to the alias matching the given name on success.
- NULL if no alias could be found matching the given name.
- --*/
- {
- PSHELL_ALIAS Alias;
- PLIST_ENTRY CurrentEntry;
- assert((Name != NULL) && (NameSize != 0));
- CurrentEntry = Shell->AliasList.Next;
- while (CurrentEntry != &(Shell->AliasList)) {
- Alias = LIST_VALUE(CurrentEntry, SHELL_ALIAS, ListEntry);
- CurrentEntry = CurrentEntry->Next;
- if (strncmp(Alias->Name, Name, NameSize - 1) == 0) {
- return Alias;
- }
- }
- return NULL;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- ShDestroyAlias (
- PSHELL_ALIAS Alias
- )
- /*++
- Routine Description:
- This routine frees a shell alias. It assumes the alias has already been
- removed from the shell's alias list.
- Arguments:
- Alias - Supplies a pointer to the alias to destroy.
- Return Value:
- None.
- --*/
- {
- if (Alias->Name != NULL) {
- free(Alias->Name);
- }
- if (Alias->Value != NULL) {
- free(Alias->Value);
- }
- free(Alias);
- return;
- }
- BOOL
- ShPrintAlias (
- PSHELL_ALIAS Alias
- )
- /*++
- Routine Description:
- This routine prints a shell alias.
- Arguments:
- Alias - Supplies a pointer to the alias to destroy.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- BOOL Result;
- PSTR Value;
- UINTN ValueSize;
- printf("%s=", Alias->Name);
- Result = ShStringFormatForReentry(Alias->Value,
- Alias->ValueSize,
- &Value,
- &ValueSize);
- if (Result == FALSE) {
- return FALSE;
- }
- printf("%s\n", Value);
- free(Value);
- return TRUE;
- }
|