#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <wchar.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <pwd.h>
#include <dirent.h>
#include <signal.h>
#include "fallback.h"
#include "util.h"
#include "common.h"
#include "wutil.h"
#include "proc.h"
#include "parser.h"
#include "parser_keywords.h"
#include "tokenizer.h"
#include "exec.h"
#include "wildcard.h"
#include "function.h"
#include "builtin.h"
#include "env.h"
#include "expand.h"
#include "reader.h"
#include "sanity.h"
#include "env_universal.h"
#include "event.h"
#include "intern.h"
#include "parse_util.h"
#include "halloc.h"
#include "halloc_util.h"
#include "path.h"
Data Structures | |
| struct | block_lookup_entry |
| Datastructure to describe a block type, like while blocks, command substitution blocks, etc. More... | |
| struct | profile_element_t |
| Struct used to keep track of profiling data for a command. More... | |
Defines | |
| #define | BLOCK_MAX_COUNT 64 |
| Maximum number of block levels in code. | |
| #define | MAX_RECURSION_DEPTH 128 |
| Maximum number of function calls, i.e. | |
| #define | UNKNOWN_BUILTIN_ERR_MSG _(L"Unknown builtin '%ls'") |
| Error message for unknown builtin. | |
| #define | EXEC_ERR_MSG _(L"This command can not be used in a pipeline") |
| Error message for improper use of the exec builtin. | |
| #define | TOK_ERR_MSG _( L"Tokenizer error: '%ls'") |
| Error message for tokenizer error. | |
| #define | COND_ERR_MSG _( L"An additional command is required" ) |
| Error message for short circuit command error. | |
| #define | RECURSION_ERR_MSG _( L"Maximum recursion depth reached. Accidental infinite loop?") |
| Error message on reaching maximum recusrion depth. | |
| #define | BLOCK_END_ERR_MSG _( L"Could not locate end of block. The 'end' command is missing, misspelled or a ';' is missing.") |
| Error message used when the end of a block can't be located. | |
| #define | BLOCK_ERR_MSG _( L"Maximum number of nested blocks reached.") |
| Error message on reaching maximum number of block calls. | |
| #define | CMD_ERR_MSG _( L"Expected a command name, got token of type '%ls'") |
| Error message when a non-string token is found when expecting a command name. | |
| #define | CMD_OR_ERR_MSG _( L"Expected a command name, got token of type '%ls'. Did you mean 'COMMAND; or COMMAND'? See the help section for the 'or' builtin command by typing 'help or'.") |
| Error message when a non-string token is found when expecting a command name. | |
| #define | CMD_AND_ERR_MSG _( L"Expected a command name, got token of type '%ls'. Did you mean 'COMMAND; and COMMAND'? See the help section for the 'and' builtin command by typing 'help and'.") |
| Error message when a non-string token is found when expecting a command name. | |
| #define | ILLEGAL_CMD_ERR_MSG _( L"Illegal command name '%ls'") |
| Error message when encountering an illegal command name. | |
| #define | ILLEGAL_FD_ERR_MSG _( L"Illegal file descriptor '%ls'") |
| Error message when encountering an illegal file descriptor. | |
| #define | WILDCARD_ERR_MSG _( L"Warning: No match for wildcard '%ls'. The command will not be executed.") |
| Error message for wildcards with no matches. | |
| #define | INVALID_CASE_ERR_MSG _( L"'case' builtin not inside of switch block") |
| Error when using case builtin outside of switch block. | |
| #define | INVALID_LOOP_ERR_MSG _( L"Loop control command while not inside of loop" ) |
| Error when using loop control builtins (break or continue) outside of loop. | |
| #define | INVALID_RETURN_ERR_MSG _( L"'return' builtin command outside of function definition" ) |
| Error when using return builtin outside of function definition. | |
| #define | INVALID_ELSE_ERR_MSG _( L"'else' builtin not inside of if block" ) |
| Error when using else builtin outside of if block. | |
| #define | INVALID_END_ERR_MSG _( L"'end' command outside of block") |
| Error when using end builtin outside of block. | |
| #define | COMMAND_ASSIGN_ERR_MSG _( L"Unknown command '%ls'. Did you mean 'set %ls %ls'? For information on assigning values to variables, see the help section on the set command by typing 'help set'.") |
| Error message for Posix-style assignment. | |
| #define | REDIRECT_TOKEN_ERR_MSG _( L"Expected redirection specification, got token of type '%ls'") |
| Error for invalid redirection token. | |
| #define | INVALID_REDIRECTION_ERR_MSG _( L"Encountered redirection when expecting a command name. Fish does not allow a redirection operation before a command.") |
| Error when encountering redirection without a command. | |
| #define | EVAL_NULL_ERR_MSG _( L"Tried to evaluate null pointer." ) |
| Error for evaluating null pointer. | |
| #define | INVALID_SCOPE_ERR_MSG _( L"Tried to evaluate commands using invalid block type '%ls'" ) |
| Error for evaluating in illegal scope. | |
| #define | UNEXPECTED_TOKEN_ERR_MSG _( L"Unexpected token of type '%ls'") |
| Error for wrong token type. | |
| #define | WHILE_BLOCK N_( L"'while' block" ) |
| While block description. | |
| #define | FOR_BLOCK N_( L"'for' block" ) |
| For block description. | |
| #define | BREAKPOINT_BLOCK N_( L"Block created by breakpoint" ) |
| Breakpoint block. | |
| #define | IF_BLOCK N_( L"'if' conditional block" ) |
| If block description. | |
| #define | FUNCTION_DEF_BLOCK N_( L"function definition block" ) |
| Function definition block description. | |
| #define | FUNCTION_CALL_BLOCK N_( L"function invocation block" ) |
| Function invocation block description. | |
| #define | FUNCTION_CALL_NO_SHADOW_BLOCK N_( L"function invocation block with no variable shadowing" ) |
| Function invocation block description. | |
| #define | SWITCH_BLOCK N_( L"'switch' block" ) |
| Switch block description. | |
| #define | FAKE_BLOCK N_( L"unexecutable block" ) |
| Fake block description. | |
| #define | TOP_BLOCK N_( L"global root block" ) |
| Top block description. | |
| #define | SUBST_BLOCK N_( L"command substitution block" ) |
| Command substitution block description. | |
| #define | BEGIN_BLOCK N_( L"'begin' unconditional block" ) |
| Begin block description. | |
| #define | SOURCE_BLOCK N_( L"Block created by the . builtin" ) |
| Source block description. | |
| #define | EVENT_BLOCK N_( L"event handler block" ) |
| Source block description. | |
| #define | UNKNOWN_BLOCK N_( L"unknown/invalid block" ) |
| Unknown block description. | |
Functions | |
| static int | parse_job (process_t *p, job_t *j, tokenizer *tok) |
| Fully parse a single job. | |
| static int | block_count (block_t *b) |
| Return the current number of block nestings. | |
| void | parser_push_block (int type) |
| Create block of specified type. | |
| void | parser_pop_block () |
| Remove the outermost block namespace. | |
| const wchar_t * | parser_get_block_desc (int block) |
| Return a description of the given blocktype. | |
| static int | parser_is_pipe_forbidden (wchar_t *word) |
| Returns 1 if the specified command is a builtin that may not be used in a pipeline. | |
| static const wchar_t * | parser_find_end (const wchar_t *buff) |
| Search the text for the end of the current block. | |
| void | parser_forbid_function (wchar_t *function) |
| Tell the parser that the specified function may not be run if not inside of a conditional block. | |
| void | parser_allow_function () |
| Undo last call to parser_forbid_function(). | |
| void | error (int ec, int p, const wchar_t *str,...) |
| Sets the current evaluation error. | |
| void | parser_init () |
| Initialize static parser data. | |
| static void | print_profile (array_list_t *p, int pos, FILE *out) |
| Print profiling information to the specified stream. | |
| void | parser_destroy () |
| Destroy static parser data. | |
| static void | print_errors (string_buffer_t *target, const wchar_t *prefix) |
| Print error message to string_buffer_t if an error has occured while parsing. | |
| static void | print_errors_stderr () |
| Print error message to stderr if an error has occured while parsing. | |
| int | eval_args (const wchar_t *line, array_list_t *args) |
| Evaluate line as a list of parameters, i.e. | |
| void | parser_stack_trace (block_t *b, string_buffer_t *buff) |
| Write a stack trace starting at the specified block to the specified string_buffer_t. | |
| static const wchar_t * | is_function () |
| Returns the name of the currently evaluated function if we are currently evaluating a function, null otherwise. | |
| int | parser_get_lineno () |
| Returns the current line number. | |
| const wchar_t * | parser_current_filename () |
| Returns the file currently evaluated by the parser. | |
| static int | printed_width (const wchar_t *str, int len) |
| Calculates the on-screen width of the specified substring of the specified string. | |
| wchar_t * | parser_current_line () |
| Returns a string describing the current parser pisition in the format 'FILENAME (line LINE_NUMBER): LINE'. | |
| int | parser_get_pos () |
| Returns the current position in the latest string of the tokenizer. | |
| int | parser_get_job_pos () |
| Returns the position where the current job started in the latest string of the tokenizer. | |
| void | parser_set_pos (int p) |
| Set the current position in the latest string of the tokenizer. | |
| const wchar_t * | parser_get_buffer () |
| Get the string currently parsed. | |
| int | parser_is_help (wchar_t *s, int min_match) |
| This function checks if the specified string is a help option. | |
| static void | parse_job_argument_list (process_t *p, job_t *j, tokenizer *tok, array_list_t *args) |
| Parse options for the specified job. | |
| static void | skipped_exec (job_t *j) |
| Do skipped execution of command. | |
| static void | eval_job (tokenizer *tok) |
| Evaluates a job from the specified tokenizer. | |
| int | eval (const wchar_t *cmd, io_data_t *io, int block_type) |
| Evaluate the expressions contained in cmd. | |
| int | parser_get_block_type (const wchar_t *cmd) |
| const wchar_t * | parser_get_block_command (int type) |
| static int | parser_test_argument (const wchar_t *arg, string_buffer_t *out, const wchar_t *prefix, int offset) |
| Test if this argument contains any errors. | |
| int | parser_test_args (const wchar_t *buff, string_buffer_t *out, const wchar_t *prefix) |
| Test if the specified string can be parsed as an argument list, e.g. | |
| int | parser_test (const wchar_t *buff, int *block_level, string_buffer_t *out, const wchar_t *prefix) |
| Test if the specified string can be parsed, or if more bytes need to be read first. | |
Variables | |
| static const struct block_lookup_entry | block_lookup [] |
| List of all legal block types. | |
| static int | error_code |
| Last error code. | |
| event_block_t * | global_event_block = 0 |
| Global event blocks. | |
| io_data_t * | block_io |
| Current block level io redirections. | |
| static int | err_pos |
| Position of last error. | |
| static string_buffer_t * | err_buff = 0 |
| Description of last error. | |
| static tokenizer * | current_tokenizer |
| Pointer to the current tokenizer. | |
| static string_buffer_t * | lineinfo = 0 |
| String for representing the current line. | |
| static int | current_tokenizer_pos |
| This is the position of the beginning of the currently parsed command. | |
| block_t * | current_block = 0 |
| The current innermost block. | |
| static array_list_t * | forbidden_function |
| List of called functions, used to help prevent infinite recursion. | |
| static int | job_start_pos |
| String index where the current job started. | |
| static array_list_t | profile_data |
| List of all profiling data. | |
| static int | eval_level = -1 |
| Keeps track of how many recursive eval calls have been made. | |
Contains functions for parsing and evaluating code.
|
|
Maximum number of block levels in code. This is not the same as maximum recursion depth, this only has to do with how many block levels are legal in the source code, not at evaluation. |
|
|
Maximum number of function calls, i.e. recursion depth. |
|
|
Error message for tokenizer error. The tokenizer message is appended to this message. |
|
||||||||||||||||||||
|
Sets the current evaluation error. This function should only be used by libraries that are called by
|
|
||||||||||||||||
|
Evaluate the expressions contained in cmd.
|
|
||||||||||||
|
Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens. The output is inserted into output, and should be freed by the caller.
|
|
|
Evaluates a job from the specified tokenizer. First calls parse_job to parse the job and then calls exec to execute it.
|
|
|
Returns the name of the currently evaluated function if we are currently evaluating a function, null otherwise. This is tested by moving down the block-scope-stack, checking every block if it is of type FUNCTION_CALL. |
|
||||||||||||||||
|
Fully parse a single job. Does not call exec on it, but any command substitutions in the job will be executed.
|
|
||||||||||||||||||||
|
Parse options for the specified job.
|
|
|
Returns the file currently evaluated by the parser. This can be different than reader_current_filename, e.g. if we are evaulating a function defined in a different file than the one curently read. |
|
|
Returns a string describing the current parser pisition in the format 'FILENAME (line LINE_NUMBER): LINE'. If we are not going to print a stack trace, at least print the line number and filename |
|
|
Tell the parser that the specified function may not be run if not inside of a conditional block. This is to remove some possibilities of infinite recursion. |
|
|
|
|
|
|
|
||||||||||||
|
This function checks if the specified string is a help option.
|
|
||||||||||||||||||||
|
Test if the specified string can be parsed, or if more bytes need to be read first. The result will have the PARSER_TEST_ERROR bit set if there is a syntax error in the code, and the PARSER_TEST_INCOMPLETE bit set if the code contains unclosed blocks.
|
|
||||||||||||||||
|
Test if the specified string can be parsed as an argument list, e.g. sent to eval_args. The result has the first bit set if the string contains errors, and the second bit is set if the string contains an unclosed block. |
|
||||||||||||||||||||
|
Test if this argument contains any errors. Detected errors include syntax errors in command substitutions, improperly escaped characters and improper use of the variable expansion operator. |
|
||||||||||||
|
Print error message to string_buffer_t if an error has occured while parsing.
|
|
||||||||||||
|
Calculates the on-screen width of the specified substring of the specified string. This function takes into account the width and allignment of the tab character, but other wise behaves like repeatedly calling wcwidth. |
|
|
Do skipped execution of command. This means that only limited execution of block level commands such as end and switch should be preformed.
|
|
|
Keeps track of how many recursive eval calls have been made. Eval doesn't call itself directly, recursion happens on blocks and on command substitutions. |
1.4.4