Refactor and improve shell greatly.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-04-02 16:27:36 +02:00
parent 54b80263a2
commit 1080ffa5fb
4 changed files with 1263 additions and 337 deletions

View File

@ -108,7 +108,7 @@ supported:
* Line editing.
* History.
* Background tasks ('&').
* Standard output redirection ('>').
* Standard redirection ('<', '>', '>>').
* Piping stdout from a task to stdin of another ('|').
* Stopping the currently running task (Control-C, '^C').
* Waiting for a task to complete and executing the next (';').
@ -130,13 +130,27 @@ supported:
* Go to start of line (Control-A, '^A', Home).
* Go to end of line (Control-E, '^E', End).
* Move between words (Control-arrows).
* Quotes (''') ('"').
These features are missing from the shell:
* Input redirection ('<') ('<<').
* Quotes (''') ('"').
* Proper recursive shell grammar parsing.
* Heredoc sequences.
* Command substitution ('$(ls)', '`ls`').
* Arithmetic expansion ('$((2 + 2))').
* Aliases.
* Conditions and loops ('if', 'case', 'while', 'until', 'for').
* Functions.
* Some special parameters ('$@', '$*', '$#', '$-', '$!).
* Special shell variables ('$ENV', '$IFS', '$LINENO').
* Shell prompt customization ('$PS1', '$PS2', '$PS4').
* Tilde expansion ('~/foo').
* Any but the simplest variant of Parameter Expansion.
* Proper shell wildcard support ('*/*.foo').
* Escaping newline characters.
* Ability for variables to not be exported.
* Export keyword ('export FOO', 'export BAR=bar').
* Subshells.
* Proper redirection to/from specific file descriptors.
* And much more; the shell remains hacky.
If a better shell is installed, and the shell is non-interactive, then the sh

1460
sh/sh.cpp

File diff suppressed because it is too large Load Diff

View File

@ -35,3 +35,105 @@ const char* getenv_safe(const char* name, const char* def)
const char* ret = getenv(name);
return ret ? ret : def;
}
bool array_add(void*** array_ptr,
size_t* used_ptr,
size_t* length_ptr,
void* value)
{
void** array;
memcpy(&array, array_ptr, sizeof(array)); // Strict aliasing.
if ( *used_ptr == *length_ptr )
{
// TODO: Avoid overflow.
size_t new_length = 2 * *length_ptr;
if ( !new_length )
new_length = 16;
// TODO: Avoid overflow and use reallocarray.
size_t new_size = new_length * sizeof(void*);
void** new_array = (void**) realloc(array, new_size);
if ( !new_array )
return false;
array = new_array;
memcpy(array_ptr, &array, sizeof(array)); // Strict aliasing.
*length_ptr = new_length;
}
memcpy(array + (*used_ptr)++, &value, sizeof(value)); // Strict aliasing.
return true;
}
void stringbuf_begin(struct stringbuf* buf)
{
buf->length = 0;
buf->allocated_size = 32;
if ( !(buf->string = (char*) malloc(buf->allocated_size)) )
{
buf->allocated_size = 0;
return;
}
buf->string[0] = '\0';
}
bool might_need_shell_quote(char c)
{
switch ( c )
{
case '|':
case '&':
case ';':
case '<':
case '>':
case '(':
case ')':
case '$':
case '`':
case '\\':
case '"':
case '\'':
case ' ':
case '\t':
case '*':
case '?':
case '[':
case '#':
case '~':
case '=':
case '%':
return true;
default:
return false;
}
}
void stringbuf_append_c(struct stringbuf* buf, char c)
{
if ( !buf->string )
return;
if ( buf->length + 1 == buf->allocated_size )
{
// TODO: Avoid overflow.
size_t new_allocated_size = 2 * buf->allocated_size;
char* new_string = (char*) realloc(buf->string, new_allocated_size);
if ( !new_string )
{
buf->string = NULL;
buf->length = 0;
buf->allocated_size = 0;
return;
}
buf->string = new_string;
buf->allocated_size = new_allocated_size;
}
buf->string[buf->length++] = c;
buf->string[buf->length] = '\0';
}
char* stringbuf_finish(struct stringbuf* buf)
{
if ( !buf->string )
return NULL;
return buf->string;
}

View File

@ -25,5 +25,21 @@
char* strdup_safe(const char* string);
const char* getenv_safe(const char* name, const char* def = "");
bool array_add(void*** array_ptr,
size_t* used_ptr,
size_t* length_ptr,
void* value);
bool might_need_shell_quote(char c);
struct stringbuf
{
char* string;
size_t length;
size_t allocated_size;
};
void stringbuf_begin(struct stringbuf* buf);
void stringbuf_append_c(struct stringbuf* buf, char c);
char* stringbuf_finish(struct stringbuf* buf);
#endif