Compare commits

...

23 Commits

Author SHA1 Message Date
axel
fe5bf8f80e Set version to 1.18.0
darcs-hash:20051207163122-ac50b-9844fb2917028886a5a1f6ce54edf7641abbc231.gz
2005-12-08 02:31:22 +10:00
axel
0a713a7939 Correct set help page. The handling of setting a variable to no value has changed.
darcs-hash:20051207162924-ac50b-3e3c579b8b932b9a5a11546fb4a042d5e2aa85c5.gz
2005-12-08 02:29:24 +10:00
axel
4ba2709452 Improved error messages
darcs-hash:20051207160647-ac50b-4061540829a108381c20a1a6f3c8fd2d004a9800.gz
2005-12-08 02:06:47 +10:00
axel
0c877183b9 Spelling
darcs-hash:20051207155717-ac50b-6146b02bd8aff0fd27816acd5e31b38093d8575d.gz
2005-12-08 01:57:17 +10:00
axel
a46be4cadb Handle setting zero length variable name
darcs-hash:20051207144849-ac50b-d919481d54ef80c68d5f4cc847d5c2370e94ddcc.gz
2005-12-08 00:48:49 +10:00
axel
8b4637e900 Insert boundary token at quotes, makes things like $foo"bar" work right
darcs-hash:20051207144307-ac50b-a708fa43b196f435efdcb1bfac17ce592cdb4533.gz
2005-12-08 00:43:07 +10:00
axel
ab13c4caad Give intelligent warning messages on zero-length variable names.
darcs-hash:20051207130330-ac50b-cc9d78ba63f592925b6076049e2c59aaaa930eec.gz
2005-12-07 23:03:30 +10:00
axel
479696a8ec Set status to 1 on parse errors
darcs-hash:20051207130209-ac50b-f1431d395bf741bb4c8f99ed64ed8ccc53a960a3.gz
2005-12-07 23:02:09 +10:00
netocrat
acde745e34 Add a distclean target to Makefile.in
darcs-hash:20051103170348-344c5-9e8f20f2363ac031c8eeb991d01c58fde86fd33b.gz
2005-11-04 03:03:48 +10:00
netocrat
064d49215a Add missing files to remove for make clean
darcs-hash:20051103151026-344c5-c79770e8273cc18f0515c4bbbed730fec89af060.gz
2005-11-04 01:10:26 +10:00
netocrat
78d3b37e11 Modify fish init scripts to take account of @SYSCONFDIR@
darcs-hash:20051103143535-344c5-203a64cc8bdb14cc018254f6eb74852a1db4843f.gz
2005-11-04 00:35:35 +10:00
axel
12aa33fad4 Even more documentation updates. Variable expantion and design document sections.
darcs-hash:20051204132259-ac50b-d63356923e41c85a8d4aae1a4db3c815867fe5e2.gz
2005-12-04 23:22:59 +10:00
axel
e4ade8f41b Remove silly warnings in help script
darcs-hash:20051204132218-ac50b-e9e74283b7fe3f12a9af90f2b6d93b189e80a684.gz
2005-12-04 23:22:18 +10:00
axel
9d7723b330 More documentation corrections and updates
darcs-hash:20051204124043-ac50b-11a283ee48103cb24efdaf18f6de62f503d6e028.gz
2005-12-04 22:40:43 +10:00
axel
2bc2e0b9ec More documentation tweaks
darcs-hash:20051204023353-ac50b-196f21f186237d5e7074667fc86f2172a7ac40e2.gz
2005-12-04 12:33:53 +10:00
axel
02083a1bd7 Updated some obsolete documentation sections, and added some general polish
darcs-hash:20051204022740-ac50b-d3258d6b6f6caaf1b728c3c5074e1318135d6752.gz
2005-12-04 12:27:40 +10:00
axel
e534a952b7 Fix display bug causing the wrong completion string prefix to be shown in some situations
darcs-hash:20051204015613-ac50b-3c9feaf11d9657a30272303f9605f8139a0c5923.gz
2005-12-04 11:56:13 +10:00
axel
754d8d3712 Fix bug breaking filename completions, introduced by csh wildcard syntax
darcs-hash:20051204015402-ac50b-911c6188f6c8213a733f4e967fc903f5290f1772.gz
2005-12-04 11:54:02 +10:00
axel
86230813de Remove more deprecated event hooks
darcs-hash:20051203195135-ac50b-bcdfc71f1e634ee9e2745683a8b23243e03a0412.gz
2005-12-04 05:51:35 +10:00
axel
2faba57e5a Update todo list to reflect recent changes
darcs-hash:20051203195003-ac50b-3c0bcaebf8a6d81fa0e0940ab6b215781cb26d52.gz
2005-12-04 05:50:03 +10:00
axel
3789127d28 No longer track changes to the ChangeLog file, since it is autogenerated
darcs-hash:20051203194801-ac50b-215457a371538276fd71f9aa368e13f1b8bfff73.gz
2005-12-04 05:48:01 +10:00
axel
32e833f331 Remove old event hooks, add more event handler documentation
darcs-hash:20051203194618-ac50b-e90683cb69b19da789152164a89a34bf187fd4e4.gz
2005-12-04 05:46:18 +10:00
axel
9b4c34aa4c Use csh-style error rules with wildcards, i.e. if no matches are found, the command is not executed
darcs-hash:20051203164356-ac50b-1b1818db2698eab9ae765a5af1e259bce3ab37e7.gz
2005-12-04 02:43:56 +10:00
33 changed files with 785 additions and 1426 deletions

1016
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -134,9 +134,9 @@ MAIN_DIR_FILES := Doxyfile Doxyfile.user Makefile.in configure \
config.guess fish_tests.c main.c fish_pager.c fishd.c
# Files in ./init/
INIT_DIR_FILES :=init/fish.in init/fish_complete.fish \
INIT_DIR_FILES :=init/fish.in init/fish_complete.fish.in \
init/fish_function.fish init/fish_inputrc \
init/fish_interactive.fish
init/fish_interactive.fish.in
# Files in ./tests/
TESTS_DIR_FILES := $(TEST_IN) $(TEST_IN:.in=.out) $(TEST_IN:.in=.err) \
@@ -374,10 +374,16 @@ rpm: fish-@PACKAGE_VERSION@.tar.bz2
mv /usr/src/redhat/RPMS/*/fish*@PACKAGE_VERSION@*.rpm .
mv /usr/src/redhat/SRPMS/fish*@PACKAGE_VERSION@*.src.rpm .
distclean: clean
rm -f fish.spec doc_src/fish.1 doc_src/Doxyfile
rm -f init/fish init/fish_interactive.fish init/fish_complete.fish
rm -f config.status config.log config.h Makefile
clean:
rm -f *.o doc.h doc_src/*.doxygen doc_src/*.c builtin_help.c
rm -f config.status config.log config.h Makefile
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
rm -f tokenizer_test fish key_reader set_color tokenize gen_hdr2 mimedb
rm -f fishd fish_pager count
rm -f fish-@PACKAGE_VERSION@.tar
rm -f fish-@PACKAGE_VERSION@.tar.gz
rm -f fish-@PACKAGE_VERSION@.tar.bz2

View File

@@ -1321,6 +1321,31 @@ static int builtin_read( wchar_t **argv )
builtin_print_help( argv[0], sb_err );
return 1;
}
/*
Verify all variable names
*/
for( i=woptind; i<argc; i++ )
{
wchar_t *src;
if( !wcslen( argv[i] ) )
{
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
return 1;
}
for( src=argv[i]; *src; src++ )
{
if( (!iswalnum(*src)) && (*src != L'_' ) )
{
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, argv[0], *src );
sb_append2(sb_err, parser_current_line(), L"\n", (void *)0 );
return 1;
}
}
}
/*
The call to reader_readline may change woptind, so we save it away here
@@ -2322,7 +2347,7 @@ static int builtin_jobs( wchar_t **argv )
sb_printf( sb_out, L"%d\t%d\t", j->job_id, j->pgid );
#ifdef HAVE__PROC_SELF_STAT
sb_printf( sb_out, L"%d\t", cpu_use(j) );
sb_printf( sb_out, L"%d%%\t", cpu_use(j) );
#endif
sb_append2( sb_out, job_is_stopped(j)?L"stopped\t":L"running\t",
// job_is_completed(j)?L"completed\t":L"unfinished\t",

View File

@@ -42,6 +42,10 @@ enum
*/
#define BUILTIN_ERR_UNKNOWN L": Unknown option"
#define BUILTIN_ERR_VARCHAR L"%ls: Invalid character in variable name: '%lc'. Only alphanumerical characters and underscores are valid in a variable name.\n"
#define BUILTIN_ERR_VARNAME_ZERO L"%ls: Variable name can not be the empty string\n"
/**
Stringbuffer used to represent standard output
*/

View File

@@ -40,10 +40,8 @@ static int parse_fill_name( string_buffer_t *name,
if (*src != L'[' && *src != L'\0')
{
sb_append(sb_err, L"set: Invalid character in variable name: ");
sb_append_char(sb_err, *src);
sb_append2(sb_err, L"\n", parser_current_line(), L"\n", (void *)0 );
sb_printf( sb_err, BUILTIN_ERR_VARCHAR, L"set", *src );
sb_append2(sb_err, parser_current_line(), L"\n", (void *)0 );
// builtin_print_help( L"set", sb_err );
return -1;
@@ -435,6 +433,13 @@ int builtin_set( wchar_t **argv )
{
dest = wcsdup(argv[woptind++]);
//fwprintf(stderr, L"Dest: %ls\n", dest);
if( !wcslen( dest ) )
{
free( dest );
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
return 1;
}
}
/* Parse values */

View File

@@ -1208,14 +1208,14 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case L'\'':
{
mode = 1;
out_pos--;
in[out_pos] = INTERNAL_SEPARATOR;
break;
}
case L'\"':
{
mode = 2;
out_pos--;
in[out_pos] = INTERNAL_SEPARATOR;
break;
}
@@ -1236,7 +1236,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
{
if( c == L'\'' )
{
out_pos--;
in[out_pos] = INTERNAL_SEPARATOR;
mode = 0;
}
else
@@ -1257,7 +1257,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case '"':
{
mode = 0;
out_pos--;
in[out_pos] = INTERNAL_SEPARATOR;
break;
}

View File

@@ -1213,10 +1213,12 @@ static void complete_cmd( const wchar_t *cmd,
array_list_t tmp;
al_init( &tmp );
expand_string( wcsdup(cmd),
comp,
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY );
complete_cmd_desc( cmd, comp );
if( expand_string( wcsdup(cmd),
comp,
ACCEPT_INCOMPLETE | EXECUTABLES_ONLY ) != EXPAND_ERROR )
{
complete_cmd_desc( cmd, comp );
}
al_destroy( &tmp );
}
else
@@ -1237,14 +1239,15 @@ static void complete_cmd( const wchar_t *cmd,
al_init( &tmp );
expand_string( nxt_completion,
if( expand_string( nxt_completion,
&tmp,
ACCEPT_INCOMPLETE |
EXECUTABLES_ONLY );
for( i=0; i<al_get_count(&tmp); i++ )
EXECUTABLES_ONLY ) != EXPAND_ERROR )
{
al_push( comp, al_get( &tmp, i ) );
for( i=0; i<al_get_count(&tmp); i++ )
{
al_push( comp, al_get( &tmp, i ) );
}
}
al_destroy( &tmp );
@@ -1290,24 +1293,26 @@ static void complete_cmd( const wchar_t *cmd,
al_init( &tmp );
expand_string( nxt_completion,
if( expand_string( nxt_completion,
&tmp,
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY );
for( i=0; i<al_get_count(&tmp); i++ )
ACCEPT_INCOMPLETE | DIRECTORIES_ONLY ) != EXPAND_ERROR )
{
wchar_t *nxt = (wchar_t *)al_get( &tmp, i );
wchar_t *desc = wcsrchr( nxt, COMPLETE_SEP );
int is_valid = (desc && (wcscmp(desc,
COMPLETE_DIRECTORY_DESC)==0));
if( is_valid )
for( i=0; i<al_get_count(&tmp); i++ )
{
al_push( comp, nxt );
}
else
{
free(nxt);
wchar_t *nxt = (wchar_t *)al_get( &tmp, i );
wchar_t *desc = wcsrchr( nxt, COMPLETE_SEP );
int is_valid = (desc && (wcscmp(desc,
COMPLETE_DIRECTORY_DESC)==0));
if( is_valid )
{
al_push( comp, nxt );
}
else
{
free(nxt);
}
}
}
@@ -1766,7 +1771,10 @@ static void complete_param_expand( wchar_t *str,
else
comp_str = str;
// fwprintf( stderr, L"expand_string( \"%ls\", [list], EXPAND_SKIP_SUBSHELL | ACCEPT_INCOMPLETE | %ls )\n", comp_str, do_file?L"0":L"EXPAND_SKIP_WILDCARDS" );
debug( 2,
L"expand_string( \"%ls\", comp_out, EXPAND_SKIP_SUBSHELL | ACCEPT_INCOMPLETE | %ls );",
comp_str,
do_file?L"0":L"EXPAND_SKIP_WILDCARDS" );
expand_string( wcsdup(comp_str), comp_out, EXPAND_SKIP_SUBSHELL | ACCEPT_INCOMPLETE | (do_file?0:EXPAND_SKIP_WILDCARDS) );
}
@@ -1963,7 +1971,7 @@ void complete( const wchar_t *cmd,
error_max=0;
/**
If we are completing a variable name or a tilde expantion user
If we are completing a variable name or a tilde expansion user
name, we do that and return. No need for any other competions.
*/

View File

@@ -1,5 +1,5 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(fish,1.17.0,axel@liljencrantz.se)
AC_INIT(fish,1.18.0,fish-users@lists.sf.net)
AC_CANONICAL_TARGET
@@ -56,6 +56,7 @@ fi
AC_DEFINE_UNQUOTED( DOCDIR, [L"$(eval echo $docdir)"], [Documentation directory] )
AC_DEFINE_UNQUOTED( SYSCONFDIR, [L"$(eval echo $sysconfdir)"], [System configuration directory] )
AC_SUBST( SYSCONFDIR, ["$(eval echo $sysconfdir)"] )
# See if Linux procfs is present
AC_CHECK_FILES([/proc/self/stat])
@@ -127,5 +128,5 @@ AC_CHECK_HEADERS([ncurses.h],[AC_SUBST(CURSESLIB,[ncurses]) AC_DEFINE(HAVE_NCURS
#does not properly support terminfo.
AC_CHECK_FILE([/usr/pkg/include/ncurses.h],[AC_SUBST(CURSESLIB,[ncurses]) AC_DEFINE(HAVE_NCURSES_H)])
AC_CONFIG_FILES([Makefile fish.spec doc_src/fish.1 doc_src/Doxyfile init/fish])
AC_CONFIG_FILES([Makefile fish.spec doc_src/fish.1 doc_src/Doxyfile init/fish init/fish_interactive.fish init/fish_complete.fish])
AC_OUTPUT

View File

@@ -4,6 +4,11 @@
<tt>complete (-c|--command|-p|--path) COMMAND [(-s|--short-option) SHORT_OPTION] [(-l|--long-option|-o|--old-option) LONG_OPTION [(-a||--arguments) OPTION_ARGUMENTS] [(-d|--description) DESCRIPTION] </tt>
\subsection complete-description Description
For an introduction to how to specify completions, see the section <a
href='index.html#completions-own'>Writing your own completions</a> of
the fish manual.
- <tt>COMMAND</tt> is the name of the command for which to add a completion
- <tt>SHORT_OPTION</tt> is a one character option for the command
- <tt>LONG_OPTION</tt> is a multi character option for the command
@@ -61,7 +66,9 @@ are valid, like the \c nodeps switch.
This can be written as:
<tt>complete -c rpm -n "__fish_contains_opt -s e erase" -l nodeps -d 'Dont check dependencies'</tt>
<tt>complete -c rpm -n "__fish_contains_opt -s e erase" -l nodeps -d
"Don't check dependencies"</tt>
where \c __fish_contains_opt is a function that checks the commandline buffer for the presense of a specified set of options.
where \c __fish_contains_opt is a function that checks the commandline
buffer for the presense of a specified set of options.

View File

@@ -16,7 +16,7 @@ the user does not have to worry about an array containing elements
such as dashes. \c fish performs a special check when invoking the
count program, and if the user uses a help option, this help page is
displayed, but if a help option is contained inside of a variable or
is the result of expantion, it will be passed on to the count program.
is the result of expansion, it will be passed on to the count program.
\subsection count-example Example

View File

@@ -1,15 +1,20 @@
/** \mainpage fish
/** \mainpage Fish user documentation
\c fish is a user friendly shell intended mostly for interactive use.
A shell is a program which allows you to execute other programs by
typing their names. For updates on \c fish, go to the <a
\section introduction The friendly interactive shell
This is the documentation for \c fish, the friendly interactive
shell. \c fish is a user friendly commandline shell shell intended
mostly for interactive use. A shell is a program used to execute other
programs. For the latest information on \c fish, please visit the <a
href="http://roo.no-ip.org/fish/"><tt>fish</tt> homepage</a>.
\section syntax Syntax overview
Shells like \c fish are used by giving them commands. Every \c fish command follows the same simple syntax.
Shells like fish are used by giving them commands. Every \c fish
command follows the same simple syntax.
A command is executed by writing the name of the command followed by any arguments.
A command is executed by writing the name of the command followed by
any arguments.
Example:
@@ -61,11 +66,13 @@ written on the same line by separating them with semicolons.
Sometimes features such as <a href="#globbing">parameter expansion</a>
and <a href="#escapes">character escapes</a> get in the way. When that
happens, the user can write a parameter within quotes, either '
(single quote) or " (double quote). There is no difference between
single quoted and double quoted strings. A quoted parameter will not
be parameter expanded, may contain spaces, and the only escape
sequences allowed is the corresponding quote character. Single and
double quotes may be nested.
(single quote) or " (double quote). There is one important difference
between single quoted and double quoted strings: When using double
quoted string, <a href='#expand-variable'>variable expansion</a> still
takes place. Other than that, a quoted parameter will not be
parameter expanded, may contain spaces, and escape sequences are
ignored. Single quotes have no special meaning withing double quotes
and vice versa.
Example:
@@ -210,7 +217,7 @@ This is a short explanation of some of the commonly used words in fish.
- argument, a parameter given to a command
- builtin, a command that is implemented as part of the shell
- command, a program
- function, a command that is implemented as a set of fish commands
- function, a block of one or more fish commands that can be called as a single command. By using functions, it is possible to string together multiple smaller commands into one more advanced command.
- job, a running pipeline or command
- pipeline, a set of commands stringed together so that the output of one command is the input of the next command
- redirection, a operation that changes one of the input/output streams associated with a job
@@ -264,31 +271,59 @@ in the known_hosts file. (see the ssh documentation for more information)
- The 'su' command complete using all users on the system
- The \c apt-get, \c rpm and \c tym commands complete using all installed packages.
Specifying your own completions is easy. If the command 'myprog' has
an option '-o' which can also be written as '--output', which requires
an additional value of either 'yes' or 'no' and decides if the program
should write anything, this can be specified by writing:
\subsection completion-own Writing your own completions
<tt>complete -c myprog -s o -l output -r -a "yes no" -d "Write output"</tt>
Specifying your own completions is not complicated. To specify a
completion, one simply uses the \c complete command. \c complete takes
as a parameter the name of the command to specify a completion
for. For example, to add a completion for the program \c myprog, one
would start the completion command with <tt>complete -c myprog
...</tt>. To provide a list of possible completions for myprog, use
the \c -a switch. If \c myprog accepts the arguments start and stop,
this can be specified as <tt>complete -c myprog -a 'start
stop'</tt>. The argument to the \c -a switch is always a single
string. At completion time, it will be tokenized on spaces and tabs,
and variable expansion, command substitution and other forms of
parameter expansion will take place.
For a more complete description of how to specify your own
completions, go <a href="builtins.html#complete">here</a> or write 'complete --help' in the \c fish shell.
Fish has a special syntax to support specifying switches accepted by a
command. The switches \c -s, \c -l and \c -o are used to specify a
short switch (single character, such as -l), a gnu style long switch (such as
--color) and an old-style long switch (like -shuffle),
respectively. If the command 'myprog' has an option '-o' which can
also be written as '--output', and which can take an additional value
of either 'yes' or 'no', this can be specified by writing:
<tt>complete -c myprog -s o -l output -a "yes no"</tt>
There are also special switches for specifying that a switch requires
an argument, to disable filename completion, to create completions
that are only available in some combinations, etc.. For a complete
description of the various switches accepted by the \c complete
command, see the documentation for the <a
href="builtins.html#complete">complete</a> builtin, or write 'complete
--help' inside the \c fish shell.
For examples of how to write your own complex completions, study the
completions in /etc/fish.d/completions (or ~/etc/fish.d/completions if
you installed fish in your home directory).
If you wish to use a completion, you should consider adding it to your
startup files. When completion has been requested for a command \c
COMMAND, fish will automatically look for the file
~/.fish.d/completions/COMMAND.fish. If it exists, it will be
automatically loaded. For examples of how to write your own complex
completions, study the completions in /etc/fish.d/completions (or ~/etc/fish.d/completions if you installed fish in your home directory).
automatically loaded. If you have written new completions for a common
Unix command, please consider sharing your work by sending it to <a
href='mailto: fish-users@lists.sf.net'>the fish mailinglist</a>.
\section expand Parameter expansion (Globbing)
When an argument for a program is given on the commandline, it
undergoes the process of parameter expantion before it is sent on to
undergoes the process of parameter expansion before it is sent on to
the command. There are many ways in which the user can specify a
parameter to be expanded. These include:
\subsection expand-wildcards Wildcards
\subsection expand-wildcard Wildcards
If a star (*) or a question mark (?) is present in the parameter, \c
fish attempts to mach the given parameter to any files in such a
@@ -300,17 +335,24 @@ Example:
<code>???</code> matches any file in the current directory whose name is exactly three characters long.
If no matches are founf for a specific wildcard, it will expand intto
zero arguments, i.e. to nothing. If none of the wildcarded arguments
sent to a command result in any matches, the command will not be
executed. If this happens when using the shell interactively, a
warning will also be printed.
\subsection expand-command-substitution Command substitution
If a parameter contains a set of parenthesis, the text enclosed by the
parentesis will be interpreted as a list of commands. Om expantion,
parentesis will be interpreted as a list of commands. Om expansion,
this list is executed, and substituted by the output. If the output is
more than one line long, each line will be expanded to a new
parameter.
Example:
The command <code>echo (basename image.jpg .jpg).png</code> will output 'image.png'.
The command <code>echo (basename image.jpg .jpg).png</code> will
output 'image.png'.
The command <tt>for i in *.jpg; convert $i (basename $i .jpg).png;
end</tt> will convert all Jpeg files in the current directory to the
@@ -339,11 +381,44 @@ href="#variables"> Environment variables</a> section.
Example:
<tt> echo \$HOME</tt> prints the home directory of the current
user. If you wish to combine environment variables with text, you can
user.
If you wish to combine environment variables with text, you can
encase the variables within braces to embed a variable inside running
text like <tt>echo Konnichiwa {$USER}san</tt>, which will print a
personalized Japanese greeting.
The {$USER}san syntax might need a bit of an elaboration. Posix
shells allow you to specify a variable name using '$VARNAME' or
'${VARNAME}'. Fish only supports the former, but has no support
whatsoever for the latter or anything remotely like it. So what is
'{$VARNAME}' then? Well, '{WHATEVER}' is <a href='#brace'>brace
expansion</a>, the same as supported by Posix shells, i.e. 'a{b,c}d'
-> 'abd acd' works both in bash and on fish. So '{$VARNAME}' is a
bracket-expansion with only a single element, i.e. it becomes
expanded to '$VARNAME', which will be variable expanded to the value
of the variable 'VARNAME'. So you might think that the brackets don't
actually do anything, and that is nearly the truth. The snag is that
there once along the way was a '}' in there somewhere, and } is not a
valid character in a variable name. So anything after the otherwise
pointless bracket expansion becomes NOT a part of the variable name,
even if it happens to be a legal variable name character. That's why
'{$USER}san' works. A case of one syntax just lending itself so nicely
to solving an unrelated problem in it's spare time.
Variable expansion is the only type of expansion performed on double
quoted strings. There is, however, an important difference in how
variables are expanded when quoted and when unquoted. An unquoted
variable expansion will result in a variable number of arguments. For
example, if the variable $foo has zero elements or is undefined, the
argument $foo will expand to zero elements. If the variable $foo is an
array of five elements, the argument $foo will expand to five
elements. When quoted, like "$foo", a variable expansion will always
result in exactly one argument. Undefined variables will expand to the
empty string, and array variables will be concatenated using the space
character.
\subsection expand-home Home directory expansion
The ~ (tilde) character at the beginning of a parameter, followed by a
@@ -354,7 +429,7 @@ directory of the process owner.
\subsection expand-process Process expansion
The \% (percent) character at the beginning of a parameter followed by
a string is expanded into a process id. The following expantions are
a string is expanded into a process id. The following expansions are
performed:
- If the string is the entire word \c self, the shells pid is the result
@@ -394,7 +469,9 @@ will output 'abar1 abar2 abar3 afoo1 afoo2 afoo3'.
The concept of environment variables are central to any
shell. Environment variables are variables, whose values can be set
and used by the user.
and used by the user. For information on how to use the current value
of a variable, see the section on <a href='#expand-variable'>variable
expansion</a>.
To set a variable value, use the <a href="builtins.html#set"> \c set
command</a>.
@@ -409,25 +486,25 @@ the shell through <a href="expand-variable">variable expansion</a>.
Example:
To use the value of a the variable \c smurf, use the command <tt>echo
Smurfs are $smurf</tt>, which would print the result 'Smurfs are
blue'.
To use the value of a the variable \c smurf, write $ (dollar synbol)
followed by the name of the variable, like <tt>echo Smurfs are
$smurf</tt>, which would print the result 'Smurfs are blue'.
\subsection variables-scope Variable scope
There are three kinds of variables in fish, universal, global and
local variables. Universal variables are shared between all fish
sessions a user is running on one computer. Global variables are
specific to the current fish session, and will never be erased unless
the user explicitly requests it using <tt>set -e</tt>. Local variables
are specific to the current fish session, and associated with a
specific block of commands, and is automatically erased when a
specific block goes out of scope. A block of commands is a series of
commands that begins with one of the commands \c 'for, \c 'while' , \c
'if', \c 'function', \c 'begin' or \c 'switch', and ends with the
command \c 'end'. The user can specify that a variable should have
either global or local scope using the \c -g/--global or \c -l/--local
switches.
specific to the current fish session, but are not associated with any
soecific block scope, and will never be erased unless the user
explicitly requests it using <tt>set -e</tt>. Local variables are
specific to the current fish session, and associated with a specific
block of commands, and is automatically erased when a specific block
goes out of scope. A block of commands is a series of commands that
begins with one of the commands \c 'for, \c 'while' , \c 'if', \c
'function', \c 'begin' or \c 'switch', and ends with the command \c
'end'. The user can specify that a variable should have either global
or local scope using the \c -g/--global or \c -l/--local switches.
Variables can be explicitly set to be universal with the \c -U or \c
--universal switch, global with the \c -g or \c --global switch, or
@@ -436,21 +513,24 @@ creating or updating a variable are:
-# If a variable is explicitly set to either universal, global or local, that setting will be honored
-# If a variable is not explicitly set to be either universal, global or local, but has been previously defined, the variable scope is not changed
-# If a variable is not explicitly set to be either universal, global or local and has never befor been defined, the variable will be local to the current scope
-# If a variable is not explicitly set to be either universal, global or local and has never befor been defined, the variable will be local to the currently executing functions. If no function is executing, the variable will be global.
There may be many variables with the same name, but different scopes.
When using a variable, the variable scope will be searched from the
inside out, i.e. a local variable will be used rather than a global
variable with the same name, a global variable will be used rather
than a universal variable with the same name.
For example, the following code will not output anything:
Example:
The following code will not output anything:
<pre>
if true
begin
# This is a nice local scope where all variables will die
set pirate 'There be treasure in them thar hills'
set -l pirate 'There be treasure in them thar hills'
end
# This will not output anything, since the pirate is dead
# This will not output anything, since the pirate was local
echo $pirate
</pre>
@@ -563,22 +643,25 @@ certain environment variables.
- \c CDPATH, which is an array of directories in which to search for the new directory for the \c cd builtin.
- \c fish_color_normal, \c fish_color_command, \c fish_color_substitution, \c fish_color_redirection, \c fish_color_end, \c fish_color_error, \c fish_color_param, \c fish_color_comment, \c fish_color_match, \c fish_color_search_match, \c fish_color_cwd, \c fish_pager_color_prefix, \c fish_pager_color_completion, \c fish_pager_color_description and \c fish_pager_color_progress are used to change the color of various elements in \c fish. These variables are universal, i.e. when changing them, their new value will be used by all running fish sessions. The new value will also be retained when restarting fish.
- \c PATH, which is an array of directories in which to search for commands
- \c umask, which is the current file creation mask. The preffered way to change the umask variable is through the <a href="commands.html#umask">umask shellscript function</a>. An attempt to set umask to an invalid value will always fail.
- \c umask, which is the current file creation mask. The prefered way to change the umask variable is through the <a href="commands.html#umask">umask shellscript function</a>. An attempt to set umask to an invalid value will always fail.
\c fish also sends additional information to the user through the
values of certain environment variables. The user can not change the values of these variables. They are:
values of certain environment variables. The user can not change the
values of these variables. They are:
- \c _, which is the name of the currently running command.
- \c history, which is an array containing the last commands that where entered
- \c history, which is an array containing the last commands that where entered.
- \c HOME, which is the users home directory. This variable can only be changed by the root user.
- \c PWD, which is the current working directory.
- \c PWD, which is the current working directory.
- \c status, which is the exit status of the last foreground job to exit. If a job contains pipelines, the status of the last command in the pipeline is the status for the job.
- \c USER, which is the username. This variable can only be changed by the root user.
Variables whose name are in uppercase are exported to the commands
started by fish. \c fish also uses several variables internally. Such
variables are prefixed with the string __FISH or __fish. These should
be ignored by the user.
started by fish. This rule is not enfored by fish, but it is good
coding practice to use casing to distinguish between exported and
unexported variables. \c fish also uses several variables
internally. Such variables are prefixed with the string __FISH or
__fish. These should be ignored by the user.
\section builtin-overview Builtins
@@ -721,24 +804,26 @@ After a command has been entered, it is inserted at the end of a
history list. Any duplicate history items are automatically
removed. By pressing the up and down keys, the user can search
forwards and backwards in the history. If the current command line is
not empty when starting a history search, only the commands starting
with the string entered into the command line are searched.
not empty when starting a history search, only the commands containing
the string entered into the command line are shown.
The history is stored in the file '.fish_history'. It is automatically
read on startup and merged on program exit.
Example:
To search for previous entries starting with the letter 'l', type 'l'
To search for previous entries containing the word 'make', type 'make'
in the console and press the up key.
\section job-control Running multiple programs
Normally when \c fish starts a program, this program will be put
in the foreground, meaning it will take control of the terminal and
\c fish will be stopped until the program finishes. Sometimes
this is not desirable. In such cases, there are several ways in which
the user can change <tt>fish</tt>'s behaviour.
Normally when \c fish starts a program, this program will be put in
the foreground, meaning it will take control of the terminal and \c
fish will be stopped until the program finishes. Sometimes this is not
desirable. For example, you may wish to start an application with a
graphical user interface from the terminal, and then be able to
continue using the shell. In such cases, there are several ways in
which the user can change <tt>fish</tt>'s behaviour.
-# By ending a command with the \& (ampersand) symbol, the user tells \c fish to put the specified command into the background. A background process will be run simultaneous with \c fish. \c fish will retain control of the terminal, so the program will not be able to read from the keyboard.
-# By pressing ^Z, the user stops a currently running foreground program and returns control to \c fish. Some programs do not support this feature, or remap it to another key. Gnu emacs uses ^X z to stop running.
@@ -746,14 +831,29 @@ the user can change <tt>fish</tt>'s behaviour.
\section initialization Initialization files
On startup, \c fish evaluates the file /etc/fish (Or ~/etc/fish if you installed fish in your home directory) and ~/.fish, in that
order. If you want to run a command only on starting an interactive
shell, use the output of the 'status --is-interactive' command. If
you want to run a command only on starting a login shell, use 'status --is-login' instead.
On startup, \c fish evaluates the file /etc/fish (Or ~/etc/fish if you
installed fish in your home directory) and ~/.fish, in that order. If
you want to run a command only on starting an interactive shell, use
the exit status of the command 'status --is-interactive' to determine
if the shell is interactive. If you want to run a command only on
starting a login shell, use 'status --is-login' instead.
If you want to run a set of commands when \c fish exits, redefine the
<a href="#hooks">function hook</a> \c fish_on_exit. If the \c
fish_on_exit is defined, it will be execute before the shell exits.
Example:
If you want to add the directory ~/linux/bin to your PATH variable
when loging in, add the following to your ~/.fish file:
<pre>if status --is-login
set PATH $PATH ~/linux/bin
end</pre>
If you want to run a set of commands when \c fish exits, use an <a
href='#event'>event handler</a> that is triggered by the exit of the
shell:
<pre>function on_exit --on-process %self
echo fish is now exiting
end</pre>
<a href="#variables-universal">Universal variables</a> are stored in
the file .fishd.HOSTNAME, where HOSTNAME is the name of your
@@ -772,7 +872,7 @@ marked red.
Detected errors include:
- Non existing commands.
- Reading or appending from non existing files.
- Reading from or appending to a non existing file.
- Incorrect use of output redirects
- Mismatched parenthesis
@@ -789,7 +889,7 @@ fish_pager_color_description and \c fish_pager_color_progress. Valid
values are \c black, \c red, \c green, \c brown, \c yellow, \c blue,
\c magenta, \c purple, \c cyan, \c white or \c normal. Setting one of
the above variables to normal will mean that the text color will be
set to the default color for the terminal.
set to the default foreground color for the terminal.
\subsection prompt Programmable prompt
@@ -835,15 +935,28 @@ end
</pre>
</p>
\subsection hooks Event hooks
\subsection event Event handlers
There are several special function names in fish. If a function is
given this name, it will be automatically called when a specific event
has occured. These functions are:
When defining a new function in fish, it is possible to make it into an
event handler, i.e. a function that is automatically run when a
specific event takes place. Events that can trigger a handler currently are:
- \c fish_on_exit, which is called before the shell exits
- \c fish_on_exec, which is called before interactively executing a command
- \c fish_on_return, which is called when control returns to the shell after interactively executing a command
* When a signal is delivered
* When a process or job exits
* When the value of a variable is updated
Example:
To specify a signal handler for the WINCH signal, write:
<pre>function --on-signal WINCH my_signal_handler
echo Got WINCH signal!
end
</pre>
For more information on how to define new event handlers, see the
documentation for the <a href='builtins.html#function'>function</a>
command.
\section issues Common issues with fish
@@ -860,9 +973,7 @@ directory, or install them in /etc.
\subsection todo-features Missing features
- Complete vi-mode key bindings
- '**' wildcard for recursive wildcard matching
- next-history-complete
- umask shellscript function
- builtin wait command
- More completions (for example xterm, vim,
konsole, gnome-terminal, dcop, cdrecord, cron, xargs
@@ -871,9 +982,8 @@ bibtex, patch, aspell, xpdf,
zip, compress, wine, xmms, dig, wine, batch, cron,
g++, javac, java, gcj, lpr, doxygen, whois, find)
- Undo support
- Multiple input characters should be inserted in one batch whenever possible, to avoid flickering
- Check keybinding commands for output - if non has happened, don't repaint to reduce flicker
- the jobs builtin should be able to give information on a specific job, such as the pids of the processes in the job
- The jobs builtin should be able to give information on a specific job, such as the pids of the processes in the job
- Syntax highlighting should mark cd to non-existing directories as an error
@@ -904,7 +1014,7 @@ g++, javac, java, gcj, lpr, doxygen, whois, find)
- Many completions are made specifically for the GNU
version of a POSIX command
- Yanking weird characters from clipboard prints Unicode escapes
- Prefix string in completion display is sometimes incorrect
If you think you have found a bug not described here, please send a
report to <a href="mailto:axel@liljencrantz.se"> axel@liljencrantz.se
@@ -942,6 +1052,10 @@ Most tradeoffs between power and ease of use can be avoided with careful design.
-# Whenever possible without breaking the above goals, fish should
follow the Posix syntax.
To achive these high-level goals, the fish design relies on a number
of more specific design principles. These are presented below,
together with a rationale and a few examples for each.
\subsection ortho The law of orthogonality
The shell language should have a small set of orthogonal features. Any
@@ -958,7 +1072,10 @@ program harder to maintain and update.
Examples:
- Here documents are too similar to using echo inside of a pipeline.
- The different quoting styles are silly. ("", '' and \$'')
- Subshells, command substitution and process substitution are strongly related. \c fish only supports command substitution, the others can be achived either using a block or the psub shellscript function.
- Having both aliases and functions is confusing, especially since both of them have limitations and problems. \c fish sunctions have none of the drawbacks of either syntax.
- The many Posix quoting styles are silly, especially \$''.
\subsection sep The law of minimalism
@@ -990,9 +1107,8 @@ and many other funtions can easily be done in external programs. They
should not be supported internally by the shell.
The law of minimalism does not imply that a large feature set is
bad. So long as a feature is not part of the language itself, but a
separate command or at least a shellscript function, bloat is much
more acceptable.
bad. So long as a feature is not part of the shell itself, but a
separate command or at least a shellscript function, bloat is fine.
\subsection conf Configurability is the root of all evil
@@ -1015,7 +1131,7 @@ enough approximation of it.
Examples:
- Fish allows the user to set various syntax highlighting colors. This is needed because fish does not know what colors the terminal uses by default, which might make some things unreadable. The proper solution would be for text color preferences to be defined centrally by the user for all programs, and for the terminal emulator to send these color properties to fish.
- Fish does not allow you to set the history filename, the number of history entries, different language substyles or any number of other common cshell configuration options
- Fish does not allow you to set the history filename, the number of history entries, different language substyles or any number of other common shell configuration options.
A special note on the evils of configurability is the long list of
very useful features found in some shells, that are not turned on by
@@ -1033,13 +1149,18 @@ considered once a user interface has been designed.
Rationale:
If too much attention is given to what is easy to implement the law of
orthogonality and the law of minimalism will by necessity be disobeyed.
This design rule is different than the others, since it describes how
one should go about designing new features, not what the features
should be. The problem with focusing on what can be done, and what is
easy to do, is that to much of the implementation is exposed. This
means that the user must know a great deal about the underlying system
to be able to guess how the shell works, it also means that the
language will often be rather low-level.
Examples:
- There should only be one type of input to the shell, lists of commands. Loops, conditionals and variable assignments are all performed through regular commands.
- The differences between builtin commands, shellscript functions and builtin commands should be made as small as possible. Builtins and shellscript functions should have exactly the same types of argument expantion as other commands, should be possible to use in any position in a pipeline, and should support any io redirection.
- The differences between builtin commands, shellscript functions and builtin commands should be made as small as possible. Builtins and shellscript functions should have exactly the same types of argument expansion as other commands, should be possible to use in any position in a pipeline, and should support any io redirection.
- Instead of forking when performing command substitution to provide a fake variable scope, all fish commands are performed from the same process, and fish instead supports true scoping
- All blocks end with the \c end builtin
@@ -1074,7 +1195,6 @@ Examples:
/** \page about About fish
\section about-program About the program
\c fish is meant to be used for interactive shell tasks on a modern
@@ -1255,17 +1375,6 @@ builtin. The are very few builtins, \c fish relies on normal commands
like <tt>echo</tt>, <tt>kill</tt>, <tt>printf</tt> and <tt>time</tt>
instead of reimplementing them as builtins.
The globbing in fish is significantly simplified. Since I can never
remember all the subtle differences between single and double quotes,
which kind of tick is used for command substitution and all the other
strange quirks of of the Posix shell language, that aspect of shells
has been significantly simplified. This makes \c fish unsuitable for
strange shell scripting, but much more suited to interactive needs
than regular shells.
There is no difference between double and single quotes. They both
turn of all globbing and escape sequences. They can be nested.
Token separation is performed before variable expansion. This means
that even if a variable contains spaces, it will never be separated
into multiple arguments. If you want to tokenize a string, you can use

View File

@@ -18,16 +18,12 @@ The <tt>set</tt> builtin causes fish to assign the variable <tt>VARIABLE_NAME</t
If set is called with no arguments, the names and values of all
environment variables are printed.
If set is called with only one argument, the scope of the variable
with the given name will be changed as specified, but it's value will
remain the same. If the variable did not previously exist, it's value
will be an empty string.
If the \c -e or \c --erase option is specified, the variable
specified by the following arguments will be erased
If a variable is set to more than one value, the variable will be an
array with the specified elements.
array with the specified elements. If a variable is set to zero
elements, it will become an array with zero elements.
If the variable name is one or more array elements, such as <tt>PATH[1
3 7]</tt>, only those array elements specified will be changed.

18
event.c
View File

@@ -273,6 +273,9 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
int i, j;
string_buffer_t *b=0;
array_list_t *fire=0;
int was_subshell = is_subshell;
int was_interactive = is_interactive;
/*
First we free all events that have been removed
@@ -344,15 +347,22 @@ static void event_fire_internal( event_t *event, array_list_t *arguments )
// debug( 1, L"Event handler fires command '%ls'", (wchar_t *)b->buff );
/*
Event handlers are not part of the main flow of code, so
they are marked as non-interactive and as a subshell
*/
is_subshell=1;
is_interactive=1;
is_interactive=0;
eval( (wchar_t *)b->buff, 0, TOP );
is_subshell=0;
is_interactive=1;
}
/*
Restore interactivity flags
*/
is_subshell = was_subshell;
is_interactive = was_interactive;
if( b )
{
sb_destroy( b );

View File

@@ -61,6 +61,9 @@ typedef struct
} param1;
/**
The name of the event handler function
*/
const wchar_t *function_name;
}
event_t;

2
exec.c
View File

@@ -1201,7 +1201,7 @@ int exec_subshell( const wchar_t *cmd,
if( !cmd )
{
debug( 1,
L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %ls",
L"Sent null command to subshell. This is a fish bug. If it can be reproduced, please send a bug report to %s",
PACKAGE_BUGREPORT );
return 0;
}

View File

@@ -67,6 +67,9 @@ parameter expansion.
*/
#define COMPLETE_LAST_DESC COMPLETE_SEP_STR L"Last background job"
#define COMPLETE_VAR_DESC L"Variable name is zero characters long."
#define COMPLETE_VAR2_DESC L" Did you mean {$VARIABLE}? For information on how variable expansion in fish differs from Posix variable expansion, see the manual section on variable expansion by typing 'help expand-variable'."
/**
String in process expansion denoting ourself
*/
@@ -92,8 +95,8 @@ parameter expansion.
any tokens which need to be expanded or otherwise altered. Clean
strings can be passed through expand_string and expand_one without
changing them. About 90% of all strings are clean, so skipping
expantion on them actually does save a small amount of time, since
it avoids multiple memory allocations during the expantion process.
expansion on them actually does save a small amount of time, since
it avoids multiple memory allocations during the expansion process.
*/
static int is_clean( const wchar_t *in )
{
@@ -727,6 +730,27 @@ static int expand_variables( wchar_t *in, array_list_t *out )
/* printf( "Stop for '%c'\n", in[stop_pos]);*/
var_len = stop_pos - start_pos;
if( var_len == 0 )
{
if( in[stop_pos] == BRACKET_BEGIN )
{
error( SYNTAX_ERROR,
-1, COMPLETE_VAR_DESC
COMPLETE_VAR2_DESC );
}
else
{
error( SYNTAX_ERROR,
-1,
COMPLETE_VAR_DESC);
}
is_ok = 0;
break;
}
if( !(var_name = malloc( sizeof(wchar_t)*(var_len+1) )))
{
@@ -770,8 +794,9 @@ static int expand_variables( wchar_t *in, array_list_t *out )
if( ( errno ) || ( end == &in[stop_pos] ) )
{
error( SYNTAX_ERROR,
L"Expected integer or \']\'",
-1 );
-1,
L"Expected integer or \']\'" );
is_ok = 0;
break;
}
@@ -791,7 +816,9 @@ static int expand_variables( wchar_t *in, array_list_t *out )
int tmp = (int)al_get( &idx, j );
if( tmp < 1 || tmp > al_get_count( &l ) )
{
error( SYNTAX_ERROR, L"Array index out of bounds", -1 );
error( SYNTAX_ERROR,
-1,
L"Array index out of bounds" );
is_ok=0;
al_truncate( &idx, j );
break;
@@ -852,8 +879,7 @@ static int expand_variables( wchar_t *in, array_list_t *out )
if( !(new_in = malloc( sizeof(wchar_t)*new_len )))
{
error( OOM, L"Out of memory", -1 );
is_ok = 0;
die_mem();
}
else
{
@@ -893,14 +919,14 @@ static int expand_variables( wchar_t *in, array_list_t *out )
if( c == VARIABLE_EXPAND )
{
/*
Regular expantion, i.e. expand this argument to nothing
Regular expansion, i.e. expand this argument to nothing
*/
empty = 1;
}
else
{
/*
Expantion to single argument.
Expansion to single argument.
*/
string_buffer_t res;
sb_init( &res );
@@ -1022,7 +1048,9 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
if( syntax_error )
{
error( SYNTAX_ERROR, L"Mismatched brackets", -1 );
error( SYNTAX_ERROR,
-1,
L"Mismatched brackets" );
return 0;
}
@@ -1168,7 +1196,9 @@ static int expand_subshell( wchar_t *in, array_list_t *out )
0 ) )
{
case -1:
error( SYNTAX_ERROR, L"Mismatched parans", -1 );
error( SYNTAX_ERROR,
-1,
L"Mismatched parans" );
return 0;
case 0:
al_push( out, in );
@@ -1247,7 +1277,7 @@ wchar_t *expand_unescape( const wchar_t * in, int escape_special )
{
wchar_t *res = unescape( in, escape_special );
if( !res )
error( SYNTAX_ERROR, L"Unexpected end of string", -1 );
error( SYNTAX_ERROR, -1, L"Unexpected end of string" );
return res;
}
@@ -1379,7 +1409,7 @@ static void remove_internal_separator( const void *s, int conv )
/**
The real expantion function. expand_one is just a wrapper around this one.
The real expansion function. expand_one is just a wrapper around this one.
*/
int expand_string( wchar_t *str,
array_list_t *end_out,
@@ -1390,11 +1420,15 @@ int expand_string( wchar_t *str,
int i;
int subshell_ok = 1;
int res = EXPAND_OK;
// debug( 1, L"Expand %ls", str );
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) )
{
al_push( end_out, str );
return 1;
return EXPAND_OK;
}
al_init( &list1 );
@@ -1412,11 +1446,11 @@ int expand_string( wchar_t *str,
if( (pos == str) || ( *(pos-1) != L'\\' ) )
{
error( SUBSHELL_ERROR, L"Subshells not allowed", -1 );
error( SUBSHELL_ERROR, -1, L"Subshells not allowed" );
free( str );
al_destroy( &list1 );
al_destroy( &list2 );
return 0;
return EXPAND_ERROR;
}
pos++;
}
@@ -1430,7 +1464,7 @@ int expand_string( wchar_t *str,
if( !subshell_ok )
{
al_destroy( &list1 );
return 0;
return EXPAND_ERROR;
}
else
{
@@ -1464,7 +1498,7 @@ int expand_string( wchar_t *str,
{
al_destroy( in );
al_destroy( out );
return 0;
return EXPAND_ERROR;
}
}
}
@@ -1481,7 +1515,7 @@ int expand_string( wchar_t *str,
{
al_destroy( in );
al_destroy( out );
return 0;
return EXPAND_ERROR;
}
}
al_truncate( in, 0 );
@@ -1496,17 +1530,22 @@ int expand_string( wchar_t *str,
{
al_destroy( in );
al_destroy( out );
return 0;
return EXPAND_ERROR;
}
if( flags & ACCEPT_INCOMPLETE )
{
if( *next == PROCESS_EXPAND )
{
/*
If process expansion matches, we are not
interested in other completions, so we
short-circut and return
*/
expand_pid( next, flags, end_out );
al_destroy( in );
al_destroy( out );
return 1;
return EXPAND_OK;
}
else
al_push( out, next );
@@ -1517,7 +1556,7 @@ int expand_string( wchar_t *str,
{
al_destroy( in );
al_destroy( out );
return 0;
return EXPAND_ERROR;
}
}
}
@@ -1550,19 +1589,18 @@ int expand_string( wchar_t *str,
case 0:
if( !(flags & ACCEPT_INCOMPLETE) )
{
if( res == EXPAND_OK )
res = EXPAND_WILDCARD_NO_MATCH;
break;
}
case 1:
res = EXPAND_WILDCARD_MATCH;
sort_list( out );
al_push_all( end_out, out );
al_truncate( out, 0 );
break;
default:
fwprintf( stderr, L"error\n" );
/*al_destroy( &list1 );*/
/*al_destroy( &list2 );*/
/*return 0;*/
}
}
else
@@ -1577,7 +1615,8 @@ int expand_string( wchar_t *str,
al_destroy( out );
}
return 1;
return res;
}

View File

@@ -1,12 +1,12 @@
/**\file expand.h
Prototypes for string expantion functions. These functions perform
several kinds of parameter expantion. There are a lot of issues
Prototypes for string expansion functions. These functions perform
several kinds of parameter expansion. There are a lot of issues
with regards to memory allocation. Overall, these functions would
benefit from using a more clever memory allocation scheme, perhaps
an evil combination of talloc, string buffers and reference
counting.
*/
#ifndef FISH_EXPAND_H
@@ -20,17 +20,17 @@
#include "util.h"
/**
Flag specifying that subshell expantion should be skipped
Flag specifying that subshell expansion should be skipped
*/
#define EXPAND_SKIP_SUBSHELL 1
/**
Flag specifying that variable expantion should be skipped
Flag specifying that variable expansion should be skipped
*/
#define EXPAND_SKIP_VARIABLES 2
/**
Flag specifying that wildcard expantion should be skipped
Flag specifying that wildcard expansion should be skipped
*/
#define EXPAND_SKIP_WILDCARDS 4
@@ -64,23 +64,45 @@ enum
/** Character represeting a home directory */
HOME_DIRECTORY = EXPAND_RESERVED,
/** Character represeting process expantion */
/** Character represeting process expansion */
PROCESS_EXPAND,
/** Character representing variable expantion */
/** Character representing variable expansion */
VARIABLE_EXPAND,
/** Character rpresenting variable expantion into a single element*/
/** Character rpresenting variable expansion into a single element*/
VARIABLE_EXPAND_SINGLE,
/** Character representing the start of a bracket expantion */
/** Character representing the start of a bracket expansion */
BRACKET_BEGIN,
/** Character representing the end of a bracket expantion */
/** Character representing the end of a bracket expansion */
BRACKET_END,
/** Character representing separation between two bracket elements */
BRACKET_SEP,
/**
Separate subtokens in a token with this character.
*/
INTERNAL_SEPARATOR,
}
;
/**
These are the possible return values for expand_string
*/
enum
{
/** Error */
EXPAND_ERROR,
/** Ok */
EXPAND_OK,
/** Ok, a wildcard in the string matched no files */
EXPAND_WILDCARD_NO_MATCH,
/* Ok, a wildcard in the string matched a file */
EXPAND_WILDCARD_MATCH
}
;
@@ -90,18 +112,13 @@ enum
/** String containing the character for separating two array elements */
#define ARRAY_SEP_STR L"\x1e"
/**
Separate subtokens in a token with this character.
*/
#define INTERNAL_SEPARATOR 0xfffffff0
/**
Perform various forms of expansion on in, such as tilde expansion
(~USER becomes the users home directory), variable expansion
($VAR_NAME becomes the value of the environment variable VAR_NAME),
subshell expantion and wildcard expansion. The results are inserted
subshell expansion and wildcard expansion. The results are inserted
into the list out.
If the parameter does not need expansion, it is copied into the list
@@ -109,8 +126,9 @@ enum
newly allocated strings are inserted into the list out.
\param in The parameter to expand
\param flag Specifies if any expantion pass should be skipped. Legal values are any combination of EXPAND_SKIP_SUBSHELL EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\param flag Specifies if any expansion pass should be skipped. Legal values are any combination of EXPAND_SKIP_SUBSHELL EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\param out The list to which the result will be appended.
\return One of EXPAND_OK, EXPAND_ERROR, EXPAND_WILDCARD_MATCH and EXPAND_WILDCARD_NO_MATCH
*/
int expand_string( wchar_t *in, array_list_t *out, int flag );
@@ -120,7 +138,7 @@ int expand_string( wchar_t *in, array_list_t *out, int flag );
names.
\param in The parameter to expand
\param flag Specifies if any expantion pass should be skipped. Legal values are any combination of EXPAND_SKIP_SUBSHELL EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\param flag Specifies if any expansion pass should be skipped. Legal values are any combination of EXPAND_SKIP_SUBSHELL EXPAND_SKIP_VARIABLES and EXPAND_SKIP_WILDCARDS
\return The expanded parameter, or 0 on failiure
*/
wchar_t *expand_one( wchar_t *in, int flag );
@@ -157,9 +175,9 @@ wchar_t *expand_escape_variable( const wchar_t *in );
/**
Perform tilde expantion and nothing else on the specified string.
Perform tilde expansion and nothing else on the specified string.
If tilde expantion is needed, the original string is freed and a
If tilde expansion is needed, the original string is freed and a
new string, allocated using malloc, is returned.
*/
wchar_t *expand_tilde(wchar_t *in);

View File

@@ -518,7 +518,7 @@ static void test_parser()
}
/**
Perform parameter expantion and test if the output equals the zero-terminated parameter list supplied.
Perform parameter expansion and test if the output equals the zero-terminated parameter list supplied.
\param in the string to expand
\param flags the flags to send to expand_string
@@ -561,11 +561,11 @@ static int expand_test( const wchar_t *in, int flags, ... )
}
/**
Test globbing and other parameter expantion
Test globbing and other parameter expansion
*/
static void test_expand()
{
say( L"Testing parameter expantion" );
say( L"Testing parameter expansion" );
if( !expand_test( L"foo", 0, L"foo", 0 ))
{
@@ -574,12 +574,12 @@ static void test_expand()
if( !expand_test( L"a{b,c,d}e", 0, L"abe", L"ace", L"ade", 0 ) )
{
err( L"Bracket expantion is broken" );
err( L"Bracket expansion is broken" );
}
if( !expand_test( L"a*", EXPAND_SKIP_WILDCARDS, L"a*", 0 ) )
{
err( L"Cannot skip wildcard expantion" );
err( L"Cannot skip wildcard expansion" );
}
}

View File

@@ -22,8 +22,6 @@ complete -c help -x -a prompt -d "Help on how to set the prompt"
complete -c help -x -a title -d "Help on how to set the titlebar message"
complete -c help -x -a killring -d "Help on how to copy and paste"
complete -c help -x -a editor -d "Help on editor shortcuts"
complete -c help -x -a expand -d "Help on parameter expantion (Globbing)"
complete -c help -x -a globbing -d "Help on parameter expantion (Globbing)"
complete -c help -x -a variables -d "Help on environment variables"
complete -c help -x -a color -d "Help on setting syntax highlighting colors"
complete -c help -x -a prompt -d "Help on changing the prompt"
@@ -31,3 +29,11 @@ complete -c help -x -a title -d "Help on changing the titlebar messages"
complete -c help -x -a builtin-overview -d "A short summary of all builtin commands"
complete -c help -x -a changes -d "The changelog"
complete -c help -x -a globbing -d "Help on parameter expansion (Globbing)"
complete -c help -x -a expand -d "Help on parameter expansion (Globbing)"
complete -c help -x -a expand-variable -d "Help on variable exapantion \$VARNAME"
complete -c help -x -a expand-home -d "Help on home directory expansion ~USER"
complete -c help -x -a expand-brace -d "Help on brace expansion {a,b,c}"
complete -c help -x -a expand-wildcard -d "Help on wildcard expansion *.*"
complete -c help -x -a expand-command-substitution -d "Help on command substututions (SUBCOMMAND)"
complete -c help -x -a expand-process -d "Help on process expansion %JOB"

View File

@@ -10,7 +10,7 @@ if not status --is-interactive
exit
end
set -g fish_complete_path /etc/fish.d/completions ~/.fish.d/completions
set -g fish_complete_path @SYSCONFDIR@/fish.d/completions ~/.fish.d/completions
# Knowing the location of the whatis database speeds up command
# description lookup.

View File

@@ -132,18 +132,20 @@ function help -d "Show help for the fish shell"
return 1
end
set fish_help_item $argv[1]
if count $argv >/dev/null
set fish_help_item $argv[1]
end
set fish_help_page ""
if test $fish_help_item = .
if test "$fish_help_item" = .
set fish_help_page "builtins.html\#source"
end
if test $fish_help_item = difference
if test "$fish_help_item" = difference
set fish_help_page difference.html
end
if test $fish_help_item = globbing
if test "$fish_help_item" = globbing
set fish_help_page "index.html\#expand"
end
@@ -156,8 +158,9 @@ function help -d "Show help for the fish shell"
end
set idx_subj syntax completion editor job-control todo bugs history
set idx_subj $idx_subj killring help color prompt title expand variables
set idx_subj $idx_subj builtin-overview changes
set idx_subj $idx_subj killring help color prompt title variables
set idx_subj $idx_subj builtin-overview changes
set idx_subj $idx_subj expand expand-variable expand-home expand-brace expand-wildcard expand-command-substitution expand-process
if contains -- $fish_help_item $idx_subj
set fish_help_page "index.html\#"$fish_help_item
@@ -561,7 +564,7 @@ function __fish_type_help -d "Help for the type shellscript function"
set bullet \*
if expr match "$LANG" ".*UTF" >/dev/null
set bullet \u2022
set bullet \u2022
end
echo \ttype - Indicate how a name would be interpreted if used as a \n\tcommand name
@@ -1002,3 +1005,4 @@ function delete-or-exit --key-binding
exit
end
end

View File

@@ -20,7 +20,7 @@ printf 'for instructions on how to use fish\n'
# Set exit message
#
function fish_on_exit -d "Commands to execute when fish exits"
function fish_on_exit -d "Commands to execute when fish exits" --on-process %self
echo Good bye
end
@@ -39,9 +39,11 @@ end
# other than fish, which may use a different file. The new value should
# be exported, since the fish inputrc file plays nice with other files
# by including them when found.
# Give priority to the default file installed with fish in
# @SYSCONFDIR@/fish_inputrc.
#
for i in ~/.fish_inputrc ~/etc/fish_inputrc /etc/fish_inputrc ~/.inputrc /etc/inputrc
for i in ~/.fish_inputrc @SYSCONFDIR@/fish_inputrc ~/etc/fish_inputrc /etc/fish_inputrc ~/.inputrc /etc/inputrc
if test -f $i
set -xg INPUTRC $i
break

6
main.c
View File

@@ -284,11 +284,7 @@ int main( int argc, char **argv )
}
}
if( function_exists(L"fish_on_exit"))
{
eval( L"fish_on_exit", 0, TOP );
}
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
reader_pop_current_filename();

383
parser.c
View File

@@ -66,7 +66,7 @@ The fish parser. Contains functions for parsing code.
Error message for tokenizer error. The tokenizer message is
appended to this message.
*/
#define TOK_ERR_MSG L"Tokenizer error"
#define TOK_ERR_MSG L"Tokenizer error: %ls"
/**
Error message for short circut command error.
@@ -98,6 +98,16 @@ The fish parser. Contains functions for parsing code.
*/
#define CMD_ERR_MSG L"Expected command"
/**
Error message for wildcards with no matches
*/
#define WILDCARD_ERR_MSG L"Warning: No match for wildcard %ls"
/**
Error message for Posix-style assignment
*/
#define COMMAND_ASSIGN_ERR_MSG L"Unknown command %ls. Did you mean 'set VARIABLE VALUE'? For information on setting variable values, see the manual section on the set command by typing 'help set'."
/** Last error code */
int error_code;
@@ -152,23 +162,23 @@ static int parse_job( process_t *p,
typedef struct
{
/**
Time spent executing the specified command, including parse time for nested blocks
Time spent executing the specified command, including parse time for nested blocks.
*/
int exec;
/**
Time spent parsing the specified command, incvluding execution time for command substitutions
Time spent parsing the specified command, including execution time for command substitutions.
*/
int parse;
/**
The block level of the specified command
The block level of the specified command. nested blocks and command substitutions both increase the block level.
*/
int level;
/**
If the execution of this command was skipped
If the execution of this command was skipped.
*/
int skipped;
/**
The command string
The command string.
*/
wchar_t *cmd;
} profile_element_t;
@@ -559,21 +569,17 @@ void parser_allow_function()
free( (void *) al_pop( &forbidden_function ) );
}
void error( int ec, const wchar_t *str, int p )
void error( int ec, int p, const wchar_t *str, ... )
{
error_code = ec;
wcsncpy( err_str, str, 256 );
err_pos = p;
}
va_list va;
error_code = ec;
err_pos = p;
va_start( va, str );
vswprintf( err_str, 256, str, va );
va_end( va );
/**
Wrapper for the error function, which sets the error string to "ec 'ea'".
*/
static void error_arg( int ec, const wchar_t *es, const wchar_t *ea, int p )
{
wchar_t *msg = wcsdupcat2( es, L" \'", ea, L"\'", 0 );
error( ec, msg, p );
free(msg);
}
wchar_t *get_filename( const wchar_t *cmd )
@@ -757,6 +763,12 @@ static void print_errors()
{
int tmp;
/*
Wildcard warnings are only printed in interactive mode
*/
if( ( error_code == WILDCARD_ERROR ) && !is_interactive )
return;
debug( 0, L"%ls", err_str );
@@ -791,10 +803,20 @@ int eval_args( const wchar_t *line, array_list_t *args )
switch(tok_last_type( &tok ) )
{
case TOK_STRING:
if( !expand_string( wcsdup(tok_last( &tok )), args, 0 ) )
switch( expand_string( wcsdup(tok_last( &tok )), args, 0 ) )
{
err_pos=tok_get_pos( &tok );
do_loop=0;
case EXPAND_ERROR:
{
err_pos=tok_get_pos( &tok );
do_loop=0;
break;
}
default:
{
break;
}
}
break;
@@ -803,20 +825,21 @@ int eval_args( const wchar_t *line, array_list_t *args )
case TOK_ERROR:
{
error_arg( SYNTAX_ERROR,
TOK_ERR_MSG,
tok_last(&tok),
tok_get_pos( &tok ) );
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
TOK_ERR_MSG,
tok_last(&tok) );
do_loop=0;
break;
}
default:
error_arg( SYNTAX_ERROR,
L"Unexpected token of type",
tok_get_desc( tok_last_type(&tok)),
tok_get_pos( &tok ) );
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
L"Unexpected token of type %ls",
tok_get_desc( tok_last_type(&tok)) );
do_loop=0;
break;
@@ -948,6 +971,11 @@ static void parse_job_main_loop( process_t *p,
int proc_is_count=0;
int matched_wildcard = 0, unmatched_wildcard = 0;
wchar_t *unmatched = 0;
int unmatched_pos=0;
/*
Test if this is the 'count' command. We need to special case
count, since it should display a help message on 'count .h',
@@ -974,8 +1002,8 @@ static void parse_job_main_loop( process_t *p,
if( (p->type == INTERNAL_EXEC) )
{
error( SYNTAX_ERROR,
EXEC_ERR_MSG,
tok_get_pos( tok ) );
tok_get_pos( tok ),
EXEC_ERR_MSG );
return;
}
p->pipe_fd = wcstol( tok_last( tok ), 0, 10 );
@@ -1045,20 +1073,48 @@ static void parse_job_main_loop( process_t *p,
wcscpy( p->actual_cmd, L"count" );
}
if( !expand_string( wcsdup(tok_last( tok )),
args,
0 )
)
switch( expand_string( wcsdup(tok_last( tok )), args, 0 ) )
{
err_pos=tok_get_pos( tok );
if( error_code == 0 )
case EXPAND_ERROR:
{
error_arg( SYNTAX_ERROR,
err_pos=tok_get_pos( tok );
if( error_code == 0 )
{
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Could not expand string",
tok_last(tok),
tok_get_pos( tok ) );
tok_last(tok) );
}
break;
}
case EXPAND_WILDCARD_NO_MATCH:
{
unmatched_wildcard = 1;
if( !unmatched )
{
unmatched = wcsdup(tok_last( tok ));
unmatched_pos = tok_get_pos( tok );
}
break;
}
case EXPAND_WILDCARD_MATCH:
{
matched_wildcard = 1;
break;
}
case EXPAND_OK:
{
break;
}
}
}
break;
@@ -1102,27 +1158,27 @@ static void parse_job_main_loop( process_t *p,
target = expand_one( wcsdup( tok_last( tok ) ), 0);
if( target == 0 && error_code == 0 )
{
error_arg( SYNTAX_ERROR,
L"Could not expand string",
tok_last( tok ),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Could not expand string %ls",
tok_last( tok ) );
}
}
break;
default:
error_arg( SYNTAX_ERROR,
L"Expected redirection, got token of type",
tok_get_desc( tok_last_type(tok)),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Expected redirection, got token of type %ls",
tok_get_desc( tok_last_type(tok)) );
}
if( target == 0 || wcslen( target )==0 )
{
if( error_code == 0 )
error( SYNTAX_ERROR,
L"Invalid IO redirection",
tok_get_pos( tok ) );
tok_get_pos( tok ),
L"Invalid IO redirection" );
tok_next(tok);
}
else
@@ -1163,11 +1219,12 @@ static void parse_job_main_loop( process_t *p,
if( ( new_io->param1.old_fd < 0 ) ||
( new_io->param1.old_fd > 10 ) )
{
error_arg( SYNTAX_ERROR,
L"Requested redirection to something "
L"that is not a file descriptor",
target,
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Requested redirection to something "
L"that is not a file descriptor %ls",
target );
tok_next(tok);
}
free(target);
@@ -1183,19 +1240,20 @@ static void parse_job_main_loop( process_t *p,
case TOK_ERROR:
{
error_arg( SYNTAX_ERROR,
TOK_ERR_MSG,
tok_last(tok),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
TOK_ERR_MSG,
tok_last(tok) );
return;
}
default:
error_arg( SYNTAX_ERROR,
L"Unexpected token of type",
tok_get_desc( tok_last_type(tok)),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Unexpected token of type %ls",
tok_get_desc( tok_last_type(tok)) );
tok_next(tok);
break;
}
@@ -1205,6 +1263,20 @@ static void parse_job_main_loop( process_t *p,
tok_next( tok );
}
if( !error_code )
{
if( unmatched_wildcard && !matched_wildcard )
{
error( WILDCARD_ERROR,
unmatched_pos,
WILDCARD_ERR_MSG,
unmatched );
}
}
free( unmatched );
return;
}
@@ -1240,39 +1312,45 @@ static int parse_job( process_t *p,
switch( tok_last_type( tok ))
{
case TOK_STRING:
{
nxt = expand_one( wcsdup(tok_last( tok )),
EXPAND_SKIP_SUBSHELL | EXPAND_SKIP_VARIABLES);
if( nxt == 0 )
{
error_arg( SYNTAX_ERROR,
L"Illegal command name ",
tok_last( tok ),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Illegal command name %ls",
tok_last( tok ) );
al_destroy( &args );
return 0;
}
break;
}
case TOK_ERROR:
{
error_arg( SYNTAX_ERROR,
TOK_ERR_MSG,
tok_last(tok),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
TOK_ERR_MSG,
tok_last(tok) );
al_destroy( &args );
return 0;
}
default:
error_arg( SYNTAX_ERROR,
L"Expected a command name, got token of type ",
tok_get_desc( tok_last_type(tok)),
tok_get_pos( tok ) );
{
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Expected a command name, got token of type %ls",
tok_get_desc( tok_last_type(tok) ) );
al_destroy( &args );
return 0;
}
}
int mark = tok_get_pos( tok );
if( wcscmp( L"command", nxt )==0 )
@@ -1351,8 +1429,8 @@ static int parse_job( process_t *p,
if( p != j->first_process )
{
error( SYNTAX_ERROR,
EXEC_ERR_MSG,
tok_get_pos( tok ) );
tok_get_pos( tok ),
EXEC_ERR_MSG );
al_destroy( &args );
free(nxt);
return 0;
@@ -1377,7 +1455,7 @@ static int parse_job( process_t *p,
int new_block = 0;
tok_next( tok );
if( (current_block->type != WHILE) )
if( ( current_block->type != WHILE ) )
{
new_block = 1;
}
@@ -1436,8 +1514,8 @@ static int parse_job( process_t *p,
if( al_get_count( &forbidden_function ) > MAX_RECURSION_DEPTH )
{
error( SYNTAX_ERROR,
RECURSION_ERR_MSG,
tok_get_pos( tok ) );
tok_get_pos( tok ),
RECURSION_ERR_MSG );
}
else
{
@@ -1507,10 +1585,23 @@ static int parse_job( process_t *p,
}
else
{
error_arg( EVAL_ERROR,
L"Unknown command",
(wchar_t *)al_get( &args, 0 ),
tok_get_pos( tok ) );
if( wcschr( (wchar_t *)al_get( &args, 0 ), L'=' ) )
{
error( EVAL_ERROR,
tok_get_pos( tok ),
COMMAND_ASSIGN_ERR_MSG,
(wchar_t *)al_get( &args, 0 ) );
}
else
{
error( EVAL_ERROR,
tok_get_pos( tok ),
L"Unknown command %ls",
(wchar_t *)al_get( &args, 0 ) );
}
}
}
}
@@ -1527,8 +1618,8 @@ static int parse_job( process_t *p,
if( !end )
{
error( SYNTAX_ERROR,
L"Could not find end of block" ,
tok_get_pos( tok ) );
tok_get_pos( tok ),
L"Could not find end of block" );
}
if( !make_sub_block )
@@ -1552,8 +1643,8 @@ static int parse_job( process_t *p,
default:
{
error( SYNTAX_ERROR,
BLOCK_END_ERR_MSG,
current_tokenizer_pos );
current_tokenizer_pos,
BLOCK_END_ERR_MSG );
}
}
tok_destroy( &subtok );
@@ -1813,9 +1904,11 @@ static void eval_job( tokenizer *tok )
else
{
/*
This job could not be properly parsed. We free it instead.
This job could not be properly parsed. We free it instead, and set the status to 1.
*/
job_free( j );
proc_set_last_status( 1 );
}
current_block->job = 0;
break;
@@ -1830,21 +1923,21 @@ static void eval_job( tokenizer *tok )
case TOK_ERROR:
{
error_arg( SYNTAX_ERROR,
TOK_ERR_MSG,
tok_last(tok),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
TOK_ERR_MSG,
tok_last(tok) );
return;
}
default:
{
error_arg( SYNTAX_ERROR,
L"Expected a command string, got token of type",
tok_get_desc( tok_last_type(tok)),
tok_get_pos( tok ) );
error( SYNTAX_ERROR,
tok_get_pos( tok ),
L"Expected a command string, got token of type %ls",
tok_get_desc( tok_last_type(tok)) );
return;
}
}
@@ -2026,8 +2119,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
COND_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
COND_ERR_MSG );
print_errors();
}
}
@@ -2052,7 +2146,10 @@ int parser_test( wchar_t * buff,
{
if( count >= BLOCK_MAX_COUNT )
{
error( SYNTAX_ERROR, BLOCK_ERR_MSG, tok_get_pos( &tok ) );
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
BLOCK_ERR_MSG );
print_errors();
}
else
@@ -2108,8 +2205,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
EXEC_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
EXEC_ERR_MSG );
print_errors();
}
@@ -2130,8 +2228,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
EXEC_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
EXEC_ERR_MSG );
print_errors();
}
@@ -2154,8 +2253,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
L"'case' builtin not inside of switch block",
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
L"'case' builtin not inside of switch block" );
print_errors();
}
}
@@ -2186,9 +2286,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
L"Loop control command while not inside of loop",
tok_get_pos( &tok ) );
print_errors();
tok_get_pos( &tok ),
L"Loop control command while not inside of loop" );
print_errors();
}
}
}
@@ -2204,9 +2304,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
L"'else' builtin not inside of if block",
tok_get_pos( &tok ) );
print_errors();
tok_get_pos( &tok ),
L"'else' builtin not inside of if block" );
print_errors();
}
}
@@ -2221,8 +2321,8 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
L"'end' command outside of block",
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
L"'end' command outside of block" );
print_errors();
}
}
@@ -2241,8 +2341,8 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
L"Redirection error",
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
L"Redirection error" );
print_errors();
}
}
@@ -2257,9 +2357,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
CMD_ERR_MSG,
tok_get_pos( &tok ) );
print_errors();
tok_get_pos( &tok ),
CMD_ERR_MSG );
print_errors();
}
}
needs_cmd=0;
@@ -2277,8 +2377,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
EXEC_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
EXEC_ERR_MSG );
print_errors();
}
}
@@ -2295,8 +2396,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
CMD_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
CMD_ERR_MSG );
print_errors();
}
}
@@ -2313,10 +2415,12 @@ int parser_test( wchar_t * buff,
err = 1;
if( babble )
{
error_arg( SYNTAX_ERROR,
TOK_ERR_MSG,
tok_last(&tok),
tok_get_pos( &tok ) );
error( SYNTAX_ERROR,
tok_get_pos( &tok ),
TOK_ERR_MSG,
tok_last(&tok) );
print_errors();
//debug( 2, tok_last( &tok) );
}
@@ -2330,8 +2434,9 @@ int parser_test( wchar_t * buff,
if( babble )
{
error( SYNTAX_ERROR,
COND_ERR_MSG,
tok_get_pos( &tok ) );
tok_get_pos( &tok ),
COND_ERR_MSG );
print_errors();
}
}
@@ -2340,8 +2445,8 @@ int parser_test( wchar_t * buff,
if( babble && count>0 )
{
error( SYNTAX_ERROR,
END_ERR_MSG L"\n",
block_pos[count-1] );
block_pos[count-1],
END_ERR_MSG );
print_errors();
}

View File

@@ -125,12 +125,34 @@ enum while_status
*/
enum parser_error
{
/**
No error
*/
NO_ERR=0,
/**
An error in the syntax
*/
SYNTAX_ERROR,
/**
Error occured while evaluating commands
*/
EVAL_ERROR,
/**
Out of memory error
*/
OOM,
/**
Stack inconsistency error
*/
STACK_ERROR,
SUBSHELL_ERROR
/**
Error while evaluating subshell
*/
SUBSHELL_ERROR,
/**
No files matching wildcards where found
*/
WILDCARD_ERROR
}
;
@@ -178,10 +200,11 @@ int eval_args( const wchar_t *line,
Sets the current error
\param ec The new error code
\param str The new error message
\param p The character offset at which the error occured
\param str The printf-style error message filter
*/
void error( int ec, const wchar_t *str, int p );
void error( int ec, int p, const wchar_t *str, ... );
/**
Tests if the specified commands parameters should be interpreted as another command, which will be true if the command is either 'command', 'exec', 'if', 'while' or 'builtin'.

11
proc.c
View File

@@ -482,12 +482,9 @@ static void format_job_info( const job_t *j, const wchar_t *status )
fwprintf (stdout, L"\n" );
}
static void fire_process_event( const wchar_t *msg, int type, pid_t pid, int status )
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status )
{
static event_t ev;
event_t e;
e.function_name=0;
ev.type=type;
ev.param1.pid = pid;
@@ -538,7 +535,7 @@ int job_reap( int interactive )
s = p->status;
fire_process_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
if( WIFSIGNALED(s) )
{
@@ -596,8 +593,8 @@ int job_reap( int interactive )
found=1;
}
}
fire_process_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
fire_process_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
job_free(j);
}

5
proc.h
View File

@@ -254,6 +254,11 @@ void proc_update_jiffies();
*/
void proc_sanity_check();
/**
Send of an process/job exit event notification. This function is a conveniance wrapper around event_fire().
*/
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status );
/*
Initializations
*/

View File

@@ -1093,7 +1093,7 @@ static wchar_t get_quote( wchar_t *cmd, int l )
\param pos An index in the string which is inside the parameter
\param quote If not 0, store the type of quote this parameter has, can be either ', " or \\0, meaning the string is not quoted.
\param offset If not 0, get_param will store a pointer to the beginning of the parameter.
\param string If not o, get_parm will store a copy of the parameter string as returned by the tokenizer.
\param string If not 0, get_parm will store a copy of the parameter string as returned by the tokenizer.
\param type If not 0, get_param will store the token type as returned by tok_last.
*/
static void get_param( wchar_t *cmd,
@@ -1123,6 +1123,7 @@ static void get_param( wchar_t *cmd,
*type = tok_last_type( &tok );
if( string != 0 )
wcscpy( *string, tok_last( &tok ) );
prev_pos = tok_get_pos( &tok );
}
@@ -1381,13 +1382,12 @@ static int handle_completions( array_list_t *comp )
0,
0 );
len = &data->buff[data->buff_pos]-prefix_start;
if( len <= PREFIX_MAX_LEN )
{
prefix = malloc( sizeof(wchar_t)*(len+1) );
wcsncpy( prefix, prefix_start, len );
wcslcpy( prefix, prefix_start, len );
prefix[len]=L'\0';
}
else
@@ -1401,6 +1401,8 @@ static int handle_completions( array_list_t *comp )
prefix = wcsdupcat( tmp,
prefix_start + (len - PREFIX_MAX_LEN+1) );
prefix[PREFIX_MAX_LEN] = 0;
}
{
@@ -2347,21 +2349,13 @@ static int read_i()
that we can handle a call to reader_set_buffer
during evaluation.
*/
tmp = wcsdup( reader_readline() );
data->buff_pos=data->buff_len=0;
data->buff[data->buff_len]=L'\0';
if( function_exists(L"fish_on_exec"))
{
eval( L"fish_on_exec", 0, TOP );
}
reader_run_command( tmp );
free( tmp );
if( function_exists(L"fish_on_return"))
{
eval( L"fish_on_return", 0, TOP );
}
if( data->end_loop)
{
@@ -2405,7 +2399,6 @@ static int can_read( int fd )
static int wchar_private( wchar_t c )
{
return ( (c >= 0xe000) && (c <= 0xf8ff ) );
}
wchar_t *reader_readline()
@@ -2761,8 +2754,8 @@ wchar_t *reader_readline()
break;
}
/* Move left*/
case R_BACKWARD_CHAR:
if( data->buff_pos > 0 )

View File

@@ -11,6 +11,8 @@
|
<a class="qindex" href="index.html">Main documentation page</a>
|
<a class="qindex" href="design.html">Design document</a>
|
<a class="qindex" href="about.html">About fish</a>
|
<a class="qindex" href="commands.html">External commands</a>

View File

@@ -7,12 +7,18 @@
internal commands use wide characters and hence this library is
useful.
If you want to use this version of getopt in your program, simply
copy wgetopt.c and wgetopt.h into your program, include wgetopt.h,
and use all the regular getopt functions, prefixing every
function, global variable and structure with a 'w', and use only
wide character strings. There are no other functional changes in
this version of getopt besides using wide character strings.
If you want to use this version of getopt in your program,
download the fish sourcecode, available at <a
href='http://roo.no-ip.org/fish/'>the fish homepage</a>. Extract
the sourcode, copy wgetopt.c and wgetopt.h into your program
directory, include wgetopt.h in your program, and use all the
regular getopt functions, prefixing every function, global
variable and structure with a 'w', and use only wide character
strings. There are no other functional changes in this version of
getopt besides using wide character strings.
For examples of how to use wgetopt, see the fish builtin
functions, many of which are defined in builtin.c.
*/

View File

@@ -7,12 +7,18 @@
internal commands use wide characters and hence this library is
useful.
If you want to use this version of getopt in your program, simply
copy wgetopt.c and wgetopt.h into your program, include wgetopt.h,
and use all the regular getopt functions, prefixing every
function, global variable and structure with a 'w', and use only
wide character strings. There are no other functional changes in
this version of getopt besides using wide character strings.
If you want to use this version of getopt in your program,
download the fish sourcecode, available at <a
href='http://roo.no-ip.org/fish/'>the fish homepage</a>. Extract
the sourcode, copy wgetopt.c and wgetopt.h into your program
directory, include wgetopt.h in your program, and use all the
regular getopt functions, prefixing every function, global
variable and structure with a 'w', and use only wide character
strings. There are no other functional changes in this version of
getopt besides using wide character strings.
For examples of how to use wgetopt, see the fish builtin
functions, many of which are defined in builtin.c.
*/

View File

@@ -70,7 +70,7 @@ int wildcard_has( const wchar_t *str, int internal )
\param str String to be matched.
\param wc The wildcard.
\param is_first Whether files beginning with dots should not be matched against wildcards.
\param is_first Whether files beginning with dots should not be matched against wildcards.
\param wc_unescaped Whether the unescaped special character ANY_CHAR abd ANY_STRING should be used instead of '?' and '*' for wildcard matching
*/
@@ -307,7 +307,7 @@ void get_desc( wchar_t *fn, string_buffer_t *sb, int is_cmd )
/*
Test if the file specified by the given filename matches the
expantion flags specified. flags can be a combination of
expansion flags specified. flags can be a combination of
EXECUTABLES_ONLY and DIRECTORIES_ONLY.
*/
static int test_flags( wchar_t *filename,
@@ -358,7 +358,7 @@ int wildcard_expand( const wchar_t *wc,
/* Description for completions */
string_buffer_t sb_desc;
// debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );
// debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );
if( flags & ACCEPT_INCOMPLETE )
{

View File

@@ -1,8 +1,7 @@
/** \file wildcard.h
My own globbing implementation. Needed to implement this instead
of using libs globbing to support tab-expantion of globbed
of using libs globbing to support tab-expansion of globbed
paramaters.
*/