Compare commits

...

22 Commits

Author SHA1 Message Date
axel
13a7269378 Bump version number
darcs-hash:20060422101024-ac50b-8cfc71d94572187d8d3a6ce890beee0a0225a09a.gz
2006-04-22 20:10:24 +10:00
axel
fd2644ce49 Tweaks to a few error messages (Thanks to Philip Ganchev)
darcs-hash:20060422100630-ac50b-18cef1e493321e8ad0cf65982dc1748965d02630.gz
2006-04-22 20:06:30 +10:00
axel
508de57459 Change setup to avoid invalid directories and warnings, also revert directory checking for fish_*_path, it makes sense to add non-empty directories to these
darcs-hash:20060421150558-ac50b-90aff08f81b3d280badba4cc14fb6a0897c39f9e.gz
2006-04-22 01:05:58 +10:00
axel
de2405b35a Add more descriptive error messages when trying to use variables in command names
darcs-hash:20060421142939-ac50b-d1809fa4687706b433d1d0a5e0a0c9d791de510f.gz
2006-04-22 00:29:39 +10:00
axel
a7f977836a Expand the switch/case documentation
darcs-hash:20060421083529-ac50b-f287424c0cc9377085b49492453d35a5512cbc90.gz
2006-04-21 18:35:29 +10:00
axel
f59e4a88c6 If PATH is unset, use a default value
darcs-hash:20060420183502-ac50b-8e746ae4ed00c354712cf61e57e0a187aa40a4fa.gz
2006-04-21 04:35:02 +10:00
axel
c755bd0358 Only allow real directories in PATH, CDPATH, etc. If user tries to use ':' instead of arrays, give a friendly pointer on how to use arrays
darcs-hash:20060420182944-ac50b-fbb5dc63c2a4d3fe3bde92ad7699b1cad972dd0f.gz
2006-04-21 04:29:44 +10:00
axel
536523ffd7 Minor comment and documentation edits
darcs-hash:20060420150206-ac50b-c5c91053ee37a6c3f763287c42b430cdc99bb45b.gz
2006-04-21 01:02:06 +10:00
axel
ca82fc2f03 Add missing documentation for the read builtin
darcs-hash:20060420150124-ac50b-71a94cea3fedb0265af71718022e54e42567d69e.gz
2006-04-21 01:01:24 +10:00
axel
d1411c42d6 Minor edits to Makefile. A mistyped .PHONY was corrected, a few stray .o files are now properly removed by make clean, and the dependency list has been updated
darcs-hash:20060420150028-ac50b-b3b6b04023f1c039d167e5f67c89cbbaa6bd0cdc.gz
2006-04-21 01:00:28 +10:00
axel
9d770af5f4 Earlier history in non-interactive mode bugfix contained a new bug causing fish to crash if read is not used in non-interactive mode
darcs-hash:20060419234211-ac50b-886a33e96cb3f95e9b2c632f03eb3b2b20a560fd.gz
2006-04-20 09:42:11 +10:00
axel
d1ff6a323a Bump version number
darcs-hash:20060419124513-ac50b-f0c4bacee786ca9e147a86004aa90f5a09c04b34.gz
2006-04-19 22:45:13 +10:00
axel
112ea1759a Minor code cleanup
darcs-hash:20060419124315-ac50b-e7e9cafe6850e1fe805bad82278d15c2de327f5d.gz
2006-04-19 22:43:15 +10:00
axel
76bafbef2a Make the read builtin accept 0 parameters and drop the input instead of showing an error message
darcs-hash:20060419100830-ac50b-50f96925481bb29ad840fb12240ef9b9b86d18c4.gz
2006-04-19 20:08:30 +10:00
axel
1947ec88f1 Remove minor memory leak on init
darcs-hash:20060419095818-ac50b-d2146525feba5f00d224bce920ab40cc023e390d.gz
2006-04-19 19:58:18 +10:00
axel
d0956f1e43 Use libc implementations of wcslcpy and wcslcat if they exist. Move internal implementations to fallback.c.
darcs-hash:20060419095628-ac50b-0e94e4205306bb99bb9dea72eec43b442520bf1b.gz
2006-04-19 19:56:28 +10:00
axel
6996c7718e Always init history on startup, to avoid destorying history multiple times when reading interactively in a non-interactive script
darcs-hash:20060419095502-ac50b-abf2fe39cf9c027bdbc69d78fe858e946f7c81f2.gz
2006-04-19 19:55:02 +10:00
axel
45d56d8e05 Drop all calls to wcsncpy
darcs-hash:20060413121851-ac50b-1f479b96b3aa1050a30e9ee0ed27cc107ce2bc45.gz
2006-04-13 22:18:51 +10:00
axel
53295d38b7 Change var_entry_t struct to be ANSI C compliant (Wastes a few hundred bytes)
darcs-hash:20060410160109-ac50b-fa8b097722f06aee5fb09095e89f6b39ff90d44b.gz
2006-04-11 02:01:09 +10:00
axel
bd9c843fd1 Add warning when trying to change read-only variable
darcs-hash:20060410153626-ac50b-700ff7687647b8aab47ba79d759d1739cbe60425.gz
2006-04-11 01:36:26 +10:00
axel
f812b9b26c Fix bug in type command causing type -f to return true even when no file was found
darcs-hash:20060410143201-ac50b-4d8a70cd9721edcddaf11324f0b575d3f8cbace8.gz
2006-04-11 00:32:01 +10:00
axel
52851a3ba4 Quote Doxygen test in configure script to remove warning - thanks to Ray Hammond for the report and the fix
darcs-hash:20060410141909-ac50b-f310b7e326ce28ae8a3bbc1a3c1d247511f3d860.gz
2006-04-11 00:19:09 +10:00
22 changed files with 540 additions and 354 deletions

View File

@@ -344,7 +344,6 @@ builtin_help.c: $(BUILTIN_DOC_HDR) doc_src/count.doxygen gen_hdr2 gen_hdr.sh bui
./gen_hdr.sh $*.doxygen >>$@
echo ");" >>$@
echo "}" >>$@
#man -- doc_src/builtin_doc/man/man1/`basename $@ .c`.1 | cat -s | ./gen_hdr2 >>$@
#
# The build rules for installing/uninstalling fish
@@ -413,7 +412,7 @@ install-force: all install-translations
@echo \* use the command \'chsh -s $(DESTDIR)$(bindir)/fish\'.
@echo
@echo Have fun!
.PHONY: force-install
.PHONY: install-force
# Uninstall this fish version
@@ -455,6 +454,7 @@ uninstall-legacy: uninstall
rmdir $(DESTDIR)$(sysconfdir)/fish.d/completions; true
rmdir $(DESTDIR)$(sysconfdir)/fish.d; true
@echo The previous fish installation has been removed.
.PHONY: uninstall-legacy
install-translations: $(TRANSLATIONS)
if test $(HAVE_GETTEXT) = 1; then \
@@ -579,7 +579,7 @@ distclean: clean
.PHONY: distclean
clean:
rm -f *.o doc.h doc_src/*.doxygen doc_src/*.c builtin_help.c
rm -f *.o doc.h doc_src/*.doxygen doc_src/*.c builtin_help.c doc_src/*.o
rm -f tests/tmp.err tests/tmp.out tests/tmp.status tests/foo.txt
rm -f tokenizer_test fish key_reader set_color gen_hdr2 mimedb
rm -f fishd fish_pager count fish_tests
@@ -620,7 +620,6 @@ complete.o: signal.h config.h fallback.h common.h util.h tokenizer.h
complete.o: wildcard.h proc.h io.h parser.h event.h function.h complete.h
complete.o: builtin.h env.h exec.h expand.h reader.h history.h intern.h
complete.o: translate.h parse_util.h halloc_util.h wutil.h
dragon.o: signal.h
env.o: config.h signal.h fallback.h common.h util.h wutil.h proc.h io.h env.h
env.o: sanity.h expand.h history.h reader.h parser.h event.h env_universal.h
env.o: env_universal_common.h input_common.h translate.h complete.h
@@ -637,7 +636,7 @@ exec.o: halloc.h halloc_util.h parse_util.h
expand.o: signal.h config.h fallback.h common.h util.h wutil.h env.h proc.h
expand.o: io.h parser.h event.h expand.h wildcard.h exec.h tokenizer.h
expand.o: complete.h translate.h parse_util.h halloc_util.h
fallback.o: config.h common.h util.h
fallback.o: config.h fallback.h common.h util.h
fishd.o: config.h signal.h fallback.h common.h util.h wutil.h
fishd.o: env_universal_common.h
fish_pager.o: config.h signal.h fallback.h common.h util.h wutil.h complete.h
@@ -670,6 +669,7 @@ kill.o: io.h sanity.h env.h exec.h parser.h event.h
main.o: config.h signal.h fallback.h common.h util.h reader.h builtin.h
main.o: function.h complete.h wutil.h env.h sanity.h proc.h io.h parser.h
main.o: event.h expand.h intern.h exec.h output.h translate.h halloc_util.h
main.o: history.h
mimedb.o: config.h xdgmime.h fallback.h common.h util.h
output.o: config.h signal.h fallback.h common.h util.h wutil.h expand.h
output.o: output.h halloc_util.h highlight.h

View File

@@ -1029,7 +1029,7 @@ static int builtin_function( wchar_t **argv )
{
event_t *e;
if( !wcsvarname( woptarg ) )
if( wcsvarname( woptarg ) )
{
sb_printf( sb_err,
_( L"%ls: Invalid variable name '%ls'\n" ),
@@ -1145,7 +1145,7 @@ static int builtin_function( wchar_t **argv )
argc-woptind );
res=1;
}
else if( !(is_binding?wcsbindingname( argv[woptind] ) : wcsvarname( argv[woptind] ) ))
else if( !(is_binding?wcsbindingname( argv[woptind] ) : !wcsvarname( argv[woptind] ) ))
{
sb_printf( sb_err,
_( L"%ls: Illegal function name '%ls'\n" ),
@@ -1468,20 +1468,6 @@ static int builtin_read( wchar_t **argv )
return 1;
}
if( woptind == argc )
{
sb_printf( sb_err,
BUILTIN_ERR_MISSING,
argv[0] );
sb_append2( sb_err,
parser_current_line(),
L"\n",
(void *)0 );
builtin_print_help( argv[0], sb_err );
return 1;
}
/*
Verify all variable names
*/
@@ -1512,10 +1498,6 @@ static int builtin_read( wchar_t **argv )
*/
i=woptind;
ifs = env_get( L"IFS" );
if( ifs == 0 )
ifs = L"";
/*
Check if we should read interactively using \c reader_readline()
*/
@@ -1593,20 +1575,29 @@ static int builtin_read( wchar_t **argv )
sb_destroy( &sb );
}
wchar_t *state;
nxt = wcstok( buff, (i<argc-1)?ifs:L"", &state );
while( i<argc )
if( i != argc )
{
env_set( argv[i], nxt != 0 ? nxt: L"", place );
wchar_t *state;
i++;
if( nxt != 0 )
nxt = wcstok( 0, (i<argc-1)?ifs:L"", &state);
ifs = env_get( L"IFS" );
if( ifs == 0 )
ifs = L"";
nxt = wcstok( buff, (i<argc-1)?ifs:L"", &state );
while( i<argc )
{
env_set( argv[i], nxt != 0 ? nxt: L"", place );
i++;
if( nxt != 0 )
nxt = wcstok( 0, (i<argc-1)?ifs:L"", &state);
}
}
free( buff );
return exit_res;
}
@@ -2593,7 +2584,7 @@ static int builtin_for( wchar_t **argv )
argv[0] );
builtin_print_help( argv[0], sb_err );
}
else if ( !wcsvarname(argv[1]) )
else if ( wcsvarname(argv[1]) )
{
sb_printf( sb_err,
_( L"%ls: '%ls' is not a valid variable name\n" ),

View File

@@ -26,6 +26,26 @@ Functions used for implementing the set builtin.
#include "parser.h"
#include "translate.h"
#define BUILTIN_SET_PATH_ERROR L"%ls: Could not add component %ls to %ls.\n"
#define BUILTIN_SET_PATH_HINT L"%ls: Did you mean 'set %ls $%ls %ls'?\n"
/**
Call env_set. On error, print a description of the problem to
stderr.
*/
static void my_env_set( const wchar_t *key, const wchar_t *val, int scope )
{
switch( env_set( key, val, scope | ENV_USER ) )
{
case ENV_PERM:
{
sb_printf( sb_err, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key );
break;
}
}
}
/**
Extract the name from a destination argument of the form name[index1 index2...]
*/
@@ -114,7 +134,12 @@ static int parse_fill_indexes( array_list_t *indexes,
/**
Update a list by writing the specified values at the specified indexes
Update a list \c list by writing copies (using wcsdup) of the
values specified by \c values to the indexes specified by \c
indexes. The previous entries at the specidied position will be
free'd.
\return The number of elements in the list after the modifications have been made
*/
static int update_values( array_list_t *list,
array_list_t *indexes,
@@ -122,16 +147,12 @@ static int update_values( array_list_t *list,
{
int i;
//fwprintf(stderr, L"Scan complete\n");
/* Replace values where needed */
for( i = 0; i < al_get_count(indexes); i++ )
{
int ind = *(int *) al_get(indexes, i) - 1;
void *new = (void *) al_get(values, i);
if (al_get(list, ind) != 0)
{
free((void *) al_get(list, ind));
}
free((void *) al_get(list, ind));
al_set(list, ind, new != 0 ? wcsdup(new) : wcsdup(L""));
}
@@ -169,8 +190,6 @@ static int erase_values(array_list_t *list, array_list_t *indexes)
int i;
array_list_t result;
//fwprintf(stderr, L"Starting with %d\n", al_get_count(list));
al_init(&result);
for (i = 0; i < al_get_count(list); i++)
@@ -189,8 +208,6 @@ static int erase_values(array_list_t *list, array_list_t *indexes)
al_push_all( list, &result );
al_destroy(&result);
//fwprintf(stderr, L"Remaining: %d\n", al_get_count(&result));
return al_get_count(list);
}
@@ -207,8 +224,6 @@ static int fill_buffer_from_list(string_buffer_t *sb, array_list_t *list)
wchar_t *v = (wchar_t *) al_get(list, i);
if (v != 0)
{
// fwprintf(stderr, L".\n");
// fwprintf(stderr, L"Collecting %ls from %d\n", v, i);
sb_append(sb, v);
}
if (i < al_get_count(list) - 1)
@@ -254,12 +269,25 @@ static void print_variables(int include_values, int esc, int scope)
al_destroy(&names);
}
static int is_path_variable( const wchar_t *env )
{
return contains_str( env,
L"PATH",
L"CDPATH",
(void *)0 );
}
/**
The set builtin. Creates, updates and erases environment variables and environemnt variable arrays.
*/
int builtin_set( wchar_t **argv )
{
/**
Variables used for parsing the argument list
*/
const static struct woption
long_options[] =
{
@@ -293,7 +321,7 @@ int builtin_set( wchar_t **argv )
}
;
wchar_t short_options[] = L"+xglenuUq";
const wchar_t *short_options = L"+xglenuUq";
int argc = builtin_count_args(argv);
@@ -363,6 +391,15 @@ int builtin_set( wchar_t **argv )
}
}
/*
Ok, all arguments have been parsed, let's validate them
*/
/*
If we are checking the existance of a variable (-q) we can not
also specify scope
*/
if( query && (erase || list || global || local || universal || export || unexport ) )
{
sb_printf(sb_err,
@@ -375,7 +412,7 @@ int builtin_set( wchar_t **argv )
}
/* Check operation and modifiers sanity */
/* We can't both list and erase varaibles */
if( erase && list )
{
sb_printf(sb_err,
@@ -387,6 +424,9 @@ int builtin_set( wchar_t **argv )
return 1;
}
/*
Variables can only have one scope
*/
if( local + global + universal > 1 )
{
sb_printf( sb_err,
@@ -397,6 +437,9 @@ int builtin_set( wchar_t **argv )
return 1;
}
/*
Variables can only have one export status
*/
if( export && unexport )
{
sb_printf( sb_err,
@@ -410,13 +453,16 @@ int builtin_set( wchar_t **argv )
if( query )
{
/*
Query mode. Return number of specified variables that do not exist.
Query mode. Return the number variables that do not exist
out of the specified variables.
*/
int i;
for( i=woptind; i<argc; i++ )
{
if( !env_exist( argv[i] ) )
{
retcode++;
}
}
return retcode;
@@ -427,8 +473,7 @@ int builtin_set( wchar_t **argv )
if( woptind < argc )
{
dest = wcsdup(argv[woptind++]);
//fwprintf(stderr, L"Dest: %ls\n", dest);
if( !wcslen( dest ) )
{
free( dest );
@@ -444,9 +489,82 @@ int builtin_set( wchar_t **argv )
while( woptind < argc )
{
al_push(&values, argv[woptind++]);
// fwprintf(stderr, L"Val: %ls\n", argv[woptind - 1]);
}
if( is_path_variable( dest ) )
{
int i;
int error = 0;
for( i=0; i<al_get_count( &values ); i++ )
{
int show_perror = 0;
int show_hint = 0;
struct stat buff;
wchar_t *dir = (wchar_t *)al_get( &values, i );
if( wstat( dir, &buff ) )
{
error = 1;
show_perror = 1;
}
if( !( S_IFDIR & buff.st_mode ) )
{
error = 1;
}
if( error )
{
wchar_t *colon;
sb_printf( sb_err,
_(BUILTIN_SET_PATH_ERROR),
argv[0],
dir,
dest );
colon = wcschr( dir, L':' );
if( colon && *(colon+1) )
{
show_hint = 1;
}
}
if( show_perror )
{
builtin_wperror( argv[0] );
}
if( show_hint )
{
sb_printf( sb_err,
_(BUILTIN_SET_PATH_HINT),
argv[0],
dest,
dest,
wcschr( dir, L':' )+1);
}
if( error )
{
break;
}
}
if( error )
{
al_destroy(&values);
return 1;
}
}
/* Extract variable name and indexes */
sb_init(&name_sb);
@@ -459,8 +577,7 @@ int builtin_set( wchar_t **argv )
if( !retcode )
{
name = (wchar_t *) name_sb.buff;
//fwprintf(stderr, L"Name is %ls\n", name);
al_init(&indexes);
retval = parse_fill_indexes(&indexes, dest);
if (retval < 0)
@@ -477,7 +594,7 @@ int builtin_set( wchar_t **argv )
int scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (export ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER;
if( list )
{
/* Maybe we should issue an error if there are any other arguments */
/* Maybe we should issue an error if there are any other arguments? */
print_variables(0, 0, scope);
finished=1;
}
@@ -512,7 +629,7 @@ int builtin_set( wchar_t **argv )
!erase &&
!list )
{
env_set( name, 0, scope );
my_env_set( name, 0, scope );
finished = 1;
}
}
@@ -572,7 +689,8 @@ int builtin_set( wchar_t **argv )
else
{
fill_buffer_from_list(&result_sb, &val_l);
env_set(name, (wchar_t *) result_sb.buff, scope);
my_env_set(name, (wchar_t *) result_sb.buff, scope);
}
}
else
@@ -585,7 +703,7 @@ int builtin_set( wchar_t **argv )
fill_buffer_from_list( &result_sb,
&val_l );
env_set(name,
my_env_set(name,
(wchar_t *) result_sb.buff,
scope);
}
@@ -601,7 +719,7 @@ int builtin_set( wchar_t **argv )
}
/* Common cleanup */
//fwprintf(stderr, L"Cleanup\n");
free(dest);
sb_destroy(&name_sb);
al_destroy( &values );

108
common.c
View File

@@ -400,119 +400,17 @@ wchar_t **strv2wcsv( const char **in )
}
/*$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $*/
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size_t
wcslcat(wchar_t *dst, const wchar_t *src, size_t siz)
{
register wchar_t *d = dst;
register const wchar_t *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + wcslen(s));
while (*s != '\0')
{
if (n != 1)
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src));
/* count does not include NUL */
}
/*$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $*/
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size_t
wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz)
{
register wchar_t *d = dst;
register const wchar_t *s = src;
register size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0)
{
do
{
if ((*d++ = *s++) == 0)
break;
}
while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0';
/* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1);
/* count does not include NUL */
}
int wcsvarname( wchar_t *str )
wchar_t *wcsvarname( wchar_t *str )
{
while( *str )
{
if( (!iswalnum(*str)) && (*str != L'_' ) )
{
return 0;
return str;
}
str++;
}
return 1;
return 0;
}

View File

@@ -134,35 +134,18 @@ wchar_t *wcsdupcat( const wchar_t *a, const wchar_t *b );
*/
wchar_t *wcsdupcat2( const wchar_t *a, ... );
/**
Appends src to string dst of size siz (unlike wcsncat, siz is the
full size of dst, not space left). At most siz-1 characters will be
copied. Always NUL terminates (unless siz <= wcslen(dst)). Returns
wcslen(src) + MIN(siz, wcslen(initial dst)). If retval >= siz,
truncation occurred.
This is the OpenBSD strlcat function, modified for wide characters,
and renamed to reflect this change.
*/
size_t wcslcat( wchar_t *dst, const wchar_t *src, size_t siz );
/**
Copy src to string dst of size siz. At most siz-1 characters will
be copied. Always NUL terminates (unless siz == 0). Returns
wcslen(src); if retval >= siz, truncation occurred.
This is the OpenBSD strlcpy function, modified for wide characters,
and renamed to reflect this change.
*/
size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
/**
Test if the given string is a valid variable name
*/
int wcsvarname( wchar_t *str );
/**
Test if the given string is a valid variable name.
\return null if this is a valid name, and a pointer to the first invalid character otherwise
*/
wchar_t *wcsvarname( wchar_t *str );
/**

View File

@@ -1,5 +1,5 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(fish,1.21.4,fish-users@lists.sf.net)
AC_INIT(fish,1.21.6,fish-users@lists.sf.net)
# If needed, run autoconf to regenerate the configure file
AC_MSG_CHECKING([if autoconf needs to be run])
@@ -12,7 +12,7 @@ if test configure -ot configure.ac; then
if autoconf; then
./configure "$@"
fi
exit
exit
else
AC_MSG_ERROR( [cannot find the autoconf program in your path.
This program needs to be run whenever the configure.ac file is modified.
@@ -85,7 +85,7 @@ AC_PROG_INSTALL
# Check for doxygen, which is needed to build
AC_CHECK_PROG( has_doxygen, [doxygen], "true")
if ! test $has_doxygen = "true"; then
if ! test "$has_doxygen" = "true"; then
AC_MSG_ERROR( [cannot find the Doxygen program in your path.
This program is needed to build fish.
Please install it and try again.])
@@ -276,7 +276,7 @@ AC_CHECK_HEADER([regex.h],
# Check for presense of various functions
AC_CHECK_FUNCS( wcsdup wcsndup wcslen wcscasecmp wcsncasecmp gettext fwprintf )
AC_CHECK_FUNCS( futimes wcwidth wcswidth getopt_long wcstok fputwc fgetwc )
AC_CHECK_FUNCS( wcstol dcgettext )
AC_CHECK_FUNCS( wcstol dcgettext wcslcat wcslcpy )
# Here follows a list of small programs used to test for various
# features that Autoconf doesn't tell us about

View File

@@ -11,6 +11,22 @@ wildcarded values. The \c case statement is used together with the \c
switch statement in order to determine which block should be
performed.
Each \c case command is given one or more parameter. The first \c case
command with a parameter that matches the string specified in the
switch command will be evaluated. \c case parameters may contain
wildcards. These need to be escaped or quoted in order to avoid
regular wildcard expansion using filenames.
Note that fish does not fall through on case statements. Though the
syntax may look a bit like C switch statements, it behaves more like
the case stamantes of traditional shells.
Also note that command substitutions in a case statement will be
evaluated even if it's body is not taken. This may seem
counterintuitive at first, but it is unavoidable, since it would be
impossible to know if a case command will evaluate to true before all
forms of parameter expansion have been performed for the case command.
\subsection case-example Example
If the variable \$animal contains the name of an animal, the following
@@ -27,9 +43,11 @@ switch $animal
echo bird
case shark trout stingray
echo fish
case '*'
echo I have no idea what a $animal is
end
</pre>
</p>
<p>
If the above code was run with \$animal set to \c whale, the output would be \c mammal.
If the above code was run with \c \$animal set to \c whale, the output would be \c mammal.
</p>

View File

@@ -1284,7 +1284,7 @@ Examples:
- Here documents are too similar to using echo inside of a pipeline.
- 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.
- Having both aliases and functions is confusing, especially since both of them have limitations and problems. \c fish functions have none of the drawbacks of either syntax.
- The many Posix quoting styles are silly, especially \$''.
@@ -1377,14 +1377,14 @@ Examples:
\subsection disc The law of discoverability
The shell should implement it's features in a way that makes them as
easy as possible for the user to discover for her/himself.
A program should be designed to make its features as
easy as possible to discover for the user.
Rationale:
A program whose features are discoverable makes a new user into an
expert in a shorter span of time, since the user will learn how to use
the program simply by using it.
A program whose features are discoverable turns a new user into an
expert in a shorter span of time, since the user will become an expert
on the program simply by using it.
The main benefit of a graphical program over a command line-based
program is discoverability. In a graphical program, one can discover

View File

@@ -8,10 +8,13 @@
The <tt>read</tt> builtin causes fish to read one line from standard
input and store the result in one or more environment variables.
- <tt>-c CMD</tt> or <tt>--command=CMD</tt> specifies that the initial string in the interactive mode command buffer should be CMD.
- <tt>-e</tt> or <tt>--export</tt> specifies that the variables will be exported to subshells.
- <tt>-g</tt> or <tt>--global</tt> specifies that the variables will be made global.
- <tt>-pPROMPT_CMD</tt> or <tt>--prompt=PROMPT_CMD</tt> specifies that the output of the shell command PROMPT_CMD should be used as the prompt for the interactive mode prompt. The default prompt command is <tt>set_color green; echo read; set_color normal; echo "> "</tt>.
- <tt>-cCMD</tt> or <tt>--command=CMD</tt> specifies that the initial string in the interactive mode command buffer should be CMD.
- <tt>-p PROMPT_CMD</tt> or <tt>--prompt=PROMPT_CMD</tt> specifies that the output of the shell command PROMPT_CMD should be used as the prompt for the interactive mode prompt. The default prompt command is <tt>set_color green; echo read; set_color normal; echo "> "</tt>.
- <code>-u</code> or <code>--unexport</code> causes the specified environment not to be exported to child processes
- <code>-U</code> or <code>--universal</code> causes the specified environment variable to be made universal. If this option is supplied, the variable will be shared between all the current users fish instances on the current computer, and will be preserved across restarts of the shell.
- <code>-x</code> or <code>--export</code> causes the specified environment variable to be exported to child processes
Read starts by reading a single line of input from stdin, the line is
then tokenized using the <tt>IFS</tt> environment variable. Each variable

View File

@@ -8,7 +8,19 @@
The \c switch statement is used to perform one of several blocks of
commands depending on whether a specified value equals one of several
wildcarded values.
wildcarded values. The \c case statement is used together with the \c
switch statement in order to determine which block should be
performed.
Each \c case command is given one or more parameter. The first \c case
command with a parameter that matches the string specified in the
switch command will be evaluated. \c case parameters may contain
wildcards. These need to be escaped or quoted in order to avoid
regular wildcard expansion using filenames.
Note that fish does not fall through on case statements. Though the
syntax may look a bit like C switch statements, it behaves more like
the case stamantes of traditional shells.
\subsection switch-example Example
@@ -26,12 +38,14 @@ switch $animal
echo bird
case shark trout stingray
echo fish
case '*'
echo I have no idea what a $animal is
end
</pre>
</p>
<p>
If the above code was run with \$animal set to \c whale, the output
If the above code was run with \c \$animal set to \c whale, the output
would be \c mammal.
</p>

17
env.c
View File

@@ -104,7 +104,7 @@ typedef struct env_node
typedef struct var_entry
{
int export; /**< Whether the variable should be exported */
wchar_t val[0]; /**< The value of the variable */
wchar_t val[1]; /**< The value of the variable */
}
var_entry_t;
@@ -608,9 +608,9 @@ static env_node_t *env_get_node( const wchar_t *key )
return 0;
}
void env_set( const wchar_t *key,
const wchar_t *val,
int var_mode )
int env_set( const wchar_t *key,
const wchar_t *val,
int var_mode )
{
int free_val = 0;
var_entry_t *entry;
@@ -626,7 +626,7 @@ void env_set( const wchar_t *key,
if( (var_mode & ENV_USER ) &&
hash_get( &env_read_only, key ) )
{
return;
return ENV_PERM;
}
if( wcscmp( key, L"umask" ) == 0)
@@ -650,7 +650,7 @@ void env_set( const wchar_t *key,
/*
Do not actually create a umask variable, on env_get, it will be calculated dynamically
*/
return;
return 0;
}
/*
@@ -749,7 +749,7 @@ void env_set( const wchar_t *key,
node = top;
while( node->next && !node->new_scope )
node = node->next;
}
}
}
@@ -809,7 +809,8 @@ void env_set( const wchar_t *key,
{
handle_locale();
}
return 0;
}

13
env.h
View File

@@ -41,6 +41,11 @@
*/
#define ENV_UNIVERSAL 32
/**
Error code for trying to alter read-only variable
*/
#define ENV_PERM 1
/**
Initialize environment variable data
*/
@@ -61,9 +66,15 @@ void env_destroy();
\param val The value
\param mode The type of the variable. Can be any combination of ENV_GLOBAL, ENV_LOCAL, ENV_EXPORT and ENV_USER. If mode is zero, the current variable space is searched and the current mode is used. If no current variable with the same name is found, ENV_LOCAL is assumed.
\returns 0 on suicess or an error code on failiure.
The current error codes are:
* ENV_PERM, can only be returned when setting as a user, e.g. ENV_USER is set. This means that the user tried to change a read-only variable.
*/
void env_set( const wchar_t *key,
int env_set( const wchar_t *key,
const wchar_t *val,
int mode );

View File

@@ -429,7 +429,6 @@ static int find_process( const wchar_t *proc,
{
result = malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", j->pgid );
//fwprintf( stderr, L"pid %d %ls\n", j->pgid, result );
al_push( out, result );
found = 1;
}
@@ -441,12 +440,9 @@ static int find_process( const wchar_t *proc,
for( j=first_job; j != 0; j=j->next )
{
// fwprintf( stderr, L"..." );
if( j->command == 0 )
continue;
// fwprintf( stderr, L"match '%ls' '%ls'\n\n\n", j->command, proc );
if( match_pid( j->command, proc, flags ) )
{
if( flags & ACCEPT_INCOMPLETE )
@@ -455,8 +451,6 @@ static int find_process( const wchar_t *proc,
COMPLETE_SEP_STR,
COMPLETE_JOB_DESC,
(void *)0 );
// fwprintf( stderr, L"Woot %ls\n", res );
al_push( out, res );
}
else
@@ -482,12 +476,9 @@ static int find_process( const wchar_t *proc,
for( p=j->first_process; p; p=p->next )
{
// fwprintf( stderr, L"..." );
if( p->actual_cmd == 0 )
continue;
// fwprintf( stderr, L"match '%ls' '%ls'\n\n\n", j->command, proc );
if( match_pid( p->actual_cmd, proc, flags ) )
{
if( flags & ACCEPT_INCOMPLETE )
@@ -687,27 +678,22 @@ static int expand_pid( wchar_t *in,
}
}
// fwprintf( stderr, L"expand_pid() %ls\n", in );
int prev = al_get_count( out );
if( !find_process( in+1, flags, out ) )
return 0;
if( prev == al_get_count( out ) )
{
// fwprintf( stderr, L"no match\n" );
if( flags & ACCEPT_INCOMPLETE )
free( in );
else
{
*in = L'%';
// fwprintf( stderr, L"return %ls\n", in );
al_push( out, in );
}
}
else
{
// fwprintf( stderr, L"match\n" );
free( in );
}
@@ -967,7 +953,7 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
else
{
wcsncpy( new_in, in, start_pos-1 );
wcslcpy( new_in, in, start_pos );
if(start_pos>1 && new_in[start_pos-2]!=VARIABLE_EXPAND)
{
@@ -980,7 +966,6 @@ static int expand_variables( wchar_t *in, array_list_t *out, int last_idx )
wcscat( new_in, next );
wcscat( new_in, &in[stop_pos] );
// fwprintf( stderr, L"New value %ls\n", new_in );
is_ok &= expand_variables( new_in, out, i );
}
}
@@ -1059,9 +1044,6 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
wchar_t *item_begin;
int len1, len2, tot_len;
// fwprintf( stderr, L"expand %ls\n", in );
for( pos=in;
(!bracket_end) && (*pos) && !syntax_error;
pos++ )
@@ -1153,8 +1135,8 @@ static int expand_brackets( wchar_t *in, int flags, array_list_t *out )
int item_len = pos-item_begin;
whole_item = malloc( sizeof(wchar_t)*(tot_len + item_len + 1) );
wcsncpy( whole_item, in, len1 );
wcsncpy( whole_item+len1, item_begin, item_len );
wcslcpy( whole_item, in, len1+1 );
wcslcpy( whole_item+len1, item_begin, item_len+1 );
wcscpy( whole_item+len1+item_len, bracket_end+1 );
expand_brackets( whole_item, flags, out );
@@ -1234,7 +1216,7 @@ static int expand_subshell( wchar_t *in, array_list_t *out )
return 0;
}
wcsncpy( subcmd, paran_begin+1, paran_end-paran_begin-1 );
wcslcpy( subcmd, paran_begin+1, paran_end-paran_begin );
subcmd[ paran_end-paran_begin-1]=0;
if( exec_subshell( subcmd, &sub_res)==-1 )
@@ -1310,7 +1292,6 @@ static wchar_t * expand_tilde_internal( wchar_t *in )
wchar_t *new_in=0;
wchar_t *old_in=0;
// fwprintf( stderr, L"Tilde expand ~%ls\n", (*ptr)+1 );
if( in[1] == '/' || in[1] == '\0' )
{
/* Current users home directory */
@@ -1439,7 +1420,6 @@ int expand_string( void *context,
// debug( 1, L"Expand %ls", str );
if( (!(flags & ACCEPT_INCOMPLETE)) && is_clean( str ) )
{
halloc_register( context, str );

View File

@@ -818,8 +818,7 @@ wchar_t *wcsndup( const wchar_t *in, int c )
{
return 0;
}
wcsncpy( res, in, c+1 );
res[c] = L'\0';
wcslcpy( res, in, c+1 );
return res;
}
#endif
@@ -888,6 +887,113 @@ long wcstol(const wchar_t *nptr,
nptr++;
}
}
#endif
#ifndef HAVE_WCSLCAT
/*$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $*/
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size_t
wcslcat(wchar_t *dst, const wchar_t *src, size_t siz)
{
register wchar_t *d = dst;
register const wchar_t *s = src;
register size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + wcslen(s));
while (*s != '\0')
{
if (n != 1)
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src));
/* count does not include NUL */
}
#endif
#ifndef HAVE_WCSLCPY
/*$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $*/
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size_t
wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz)
{
register wchar_t *d = dst;
register const wchar_t *s = src;
register size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0)
{
do
{
if ((*d++ = *s++) == 0)
break;
}
while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0)
{
if (siz != 0)
*d = '\0';
/* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1);
/* count does not include NUL */
}
#endif

View File

@@ -231,6 +231,35 @@ long wcstol(const wchar_t *nptr,
wchar_t **endptr,
int base);
#endif
#ifndef HAVE_WCSLCAT
/**
Appends src to string dst of size siz (unlike wcsncat, siz is the
full size of dst, not space left). At most siz-1 characters will be
copied. Always NUL terminates (unless siz <= wcslen(dst)). Returns
wcslen(src) + MIN(siz, wcslen(initial dst)). If retval >= siz,
truncation occurred.
This is the OpenBSD strlcat function, modified for wide characters,
and renamed to reflect this change.
*/
size_t wcslcat( wchar_t *dst, const wchar_t *src, size_t siz );
#endif
#ifndef HAVE_WCSLCPY
/**
Copy src to string dst of size siz. At most siz-1 characters will
be copied. Always NUL terminates (unless siz == 0). Returns
wcslen(src); if retval >= siz, truncation occurred.
This is the OpenBSD strlcpy function, modified for wide characters,
and renamed to reflect this change.
*/
size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
#endif
#endif

View File

@@ -202,6 +202,10 @@ static void history_to_hash()
{
history_data *d;
if( !history_last )
return;
d = (history_data *)hash_get( &history_table,
mode_name );

7
main.c
View File

@@ -61,6 +61,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "output.h"
#include "translate.h"
#include "halloc_util.h"
#include "history.h"
/**
@@ -266,6 +267,7 @@ int main( int argc, char **argv )
env_init();
complete_init();
reader_init();
history_init();
if( read_init() )
{
@@ -297,10 +299,10 @@ int main( int argc, char **argv )
return 1;
}
sb_init( &sb );
if( *(argv+2))
{
sb_init( &sb );
for( i=1,ptr = argv+2; *ptr; i++, ptr++ )
{
if( i != 1 )
@@ -337,6 +339,7 @@ int main( int argc, char **argv )
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
history_destroy();
complete_destroy();
proc_destroy();
env_destroy();

222
parser.c
View File

@@ -101,12 +101,12 @@ The fish parser. Contains functions for parsing code.
/**
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'? For more information on the 'or' builtin command, see the help section for 'or' by typing 'help or'.")
#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'? For more information on the 'and' builtin command, see the help section for 'and' by typing 'help and'.")
#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 encountering an illegal command name
@@ -165,7 +165,7 @@ The fish parser. Contains functions for parsing code.
/**
Error for wrong token type
Error for wrong token type
*/
#define UNEXPECTED_TOKEN_ERR_MSG _( L"Unexpected token of type '%ls'")
@@ -176,78 +176,78 @@ The fish parser. Contains functions for parsing code.
/**
While block description
While block description
*/
#define WHILE_BLOCK _( L"'while' block" )
/**
For block description
For block description
*/
#define FOR_BLOCK _( L"'for' block" )
/**
If block description
If block description
*/
#define IF_BLOCK _( L"'if' conditional block" )
/**
function definition block description
Function definition block description
*/
#define FUNCTION_DEF_BLOCK _( L"function definition block" )
/**
Function invocation block description
Function invocation block description
*/
#define FUNCTION_CALL_BLOCK _( L"function invocation block" )
/**
Switch block description
Switch block description
*/
#define SWITCH_BLOCK _( L"'switch' block" )
/**
Fake block description
Fake block description
*/
#define FAKE_BLOCK _( L"unexecutable block" )
/**
Top block description
Top block description
*/
#define TOP_BLOCK _( L"global root block" )
/**
Command substitution block description
Command substitution block description
*/
#define SUBST_BLOCK _( L"command substitution block" )
/**
Begin block description
Begin block description
*/
#define BEGIN_BLOCK _( L"'begin' unconditional block" )
/**
Source block description
Source block description
*/
#define SOURCE_BLOCK _( L"Block created by the . builtin" )
/**
Source block description
Source block description
*/
#define EVENT_BLOCK _( L"event handler block" )
/**
Unknown block description
Unknown block description
*/
#define UNKNOWN_BLOCK _( L"unknown/invalid block" )
@@ -724,75 +724,85 @@ wchar_t *get_filename( const wchar_t *cmd )
else
{
path = env_get(L"PATH");
if( path != 0 )
if( path == 0 )
{
/*
Allocate string long enough to hold the whole command
*/
wchar_t *new_cmd = malloc( sizeof(wchar_t)*(wcslen(cmd)+wcslen(path)+2) );
/*
We tokenize a copy of the path, since strtok modifies
its arguments
*/
wchar_t *path_cpy = wcsdup( path );
wchar_t *nxt_path = path;
wchar_t *state;
if( (new_cmd==0) || (path_cpy==0) )
if( contains_str( PREFIX L"/bin", L"/bin", L"/usr/bin", (void *)0 ) )
{
die_mem();
path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
}
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
nxt_path != 0;
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
else
{
int path_len = wcslen( nxt_path );
wcscpy( new_cmd, nxt_path );
if( new_cmd[path_len-1] != L'/' )
{
new_cmd[path_len++]=L'/';
}
wcscpy( &new_cmd[path_len], cmd );
if( waccess( new_cmd, X_OK )==0 )
{
struct stat buff;
if( wstat( new_cmd, &buff )==-1 )
{
if( errno != EACCES )
{
wperror( L"stat" );
}
continue;
}
if( S_ISREG(buff.st_mode) )
{
free( path_cpy );
return new_cmd;
}
}
else
{
switch( errno )
{
case ENOENT:
case ENAMETOOLONG:
case EACCES:
case ENOTDIR:
break;
default:
{
debug( 1,
MISSING_COMMAND_ERR_MSG,
new_cmd );
wperror( L"access" );
}
}
}
path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
}
free( path_cpy );
free( new_cmd );
}
/*
Allocate string long enough to hold the whole command
*/
wchar_t *new_cmd = malloc( sizeof(wchar_t)*(wcslen(cmd)+wcslen(path)+2) );
/*
We tokenize a copy of the path, since strtok modifies
its arguments
*/
wchar_t *path_cpy = wcsdup( path );
wchar_t *nxt_path = path;
wchar_t *state;
if( (new_cmd==0) || (path_cpy==0) )
{
die_mem();
}
for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state );
nxt_path != 0;
nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) )
{
int path_len = wcslen( nxt_path );
wcscpy( new_cmd, nxt_path );
if( new_cmd[path_len-1] != L'/' )
{
new_cmd[path_len++]=L'/';
}
wcscpy( &new_cmd[path_len], cmd );
if( waccess( new_cmd, X_OK )==0 )
{
struct stat buff;
if( wstat( new_cmd, &buff )==-1 )
{
if( errno != EACCES )
{
wperror( L"stat" );
}
continue;
}
if( S_ISREG(buff.st_mode) )
{
free( path_cpy );
return new_cmd;
}
}
else
{
switch( errno )
{
case ENOENT:
case ENAMETOOLONG:
case EACCES:
case ENOTDIR:
break;
default:
{
debug( 1,
MISSING_COMMAND_ERR_MSG,
new_cmd );
wperror( L"access" );
}
}
}
}
free( path_cpy );
free( new_cmd );
}
return 0;
}
@@ -1101,8 +1111,8 @@ int parser_get_lineno()
int lineno;
/* static const wchar_t *prev_str = 0;
static int i=0;
static int lineno=1;
static int i=0;
static int lineno=1;
*/
if( !current_tokenizer )
return -1;
@@ -1241,8 +1251,8 @@ wchar_t *parser_current_line()
// debug( 1, L"Current pos %d, line pos %d, file_length %d, is_interactive %d, offset %d\n", current_tokenizer_pos, current_line_pos, wcslen(whole_str), is_interactive, offset);
/*
Skip printing character position if we are in interactive mode
and the error was on the first character of the line.
Skip printing character position if we are in interactive mode
and the error was on the first character of the line.
*/
if( !is_interactive || is_function() || (current_line_width!=0) )
{
@@ -1716,8 +1726,8 @@ static int parse_job( process_t *p,
else
{
error( SYNTAX_ERROR,
tok_get_pos( tok ),
CMD_ERR_MSG,
tok_get_pos( tok ),
CMD_ERR_MSG,
tok_get_desc( tok_last_type(tok) ) );
}
@@ -1926,8 +1936,8 @@ static int parse_job( process_t *p,
if( !p->type || (p->type == INTERNAL_EXEC) )
{
/*
If we are not executing the current block, allow
non-existent commands.
If we are not executing the current block, allow
non-existent commands.
*/
if( current_block->skip )
{
@@ -1971,7 +1981,8 @@ static int parse_job( process_t *p,
else
{
int tmp;
wchar_t *cmd = (wchar_t *)al_get( args, 0 );
/*
We couln't find the specified command.
@@ -1986,19 +1997,42 @@ static int parse_job( process_t *p,
cause the job to silently not execute. We
also print an error message.
*/
if( wcschr( (wchar_t *)al_get( args, 0 ), L'=' ) )
if( wcschr( cmd, L'=' ) )
{
debug( 0,
COMMAND_ASSIGN_ERR_MSG,
(wchar_t *)al_get( args, 0 ) );
}
else
else if(cmd[0]==L'$')
{
wchar_t *val = env_get( cmd+1 );
if( val )
{
debug( 0,
_(L"Variables may not be used as commands. Instead, define a function like 'function %ls; %ls $argv; end'. See the help section for the function command by typing 'help function'." ),
cmd+1,
val,
cmd );
}
else
{
debug( 0,
_(L"Variables may not be used as commands. Instead, define a function. See the help section for the function command by typing 'help function'." ),
cmd );
}
}
else if(wcschr( cmd, L'$' ))
{
debug( 0,
_(L"Commands may not contain variables. Use the eval builtin instead, like 'eval %ls'. See the help section for the eval command by typing 'help eval'." ),
cmd,
cmd );
}
else
{
debug( 0,
_(L"Unknown command '%ls'"),
(wchar_t *)al_get( args, 0 ) );
cmd );
}
tmp = current_tokenizer_pos;
@@ -2482,7 +2516,7 @@ int eval( const wchar_t *cmd, io_data_t *io, int block_type )
}
/*
Restore previous eval state
Restore previous eval state
*/
forbidden_function = prev_forbidden;
current_tokenizer=previous_tokenizer;

View File

@@ -1631,7 +1631,6 @@ static void reader_interactive_init()
al_init( &prompt_list );
history_init();
common_handle_winch(0);
@@ -1658,7 +1657,6 @@ static void reader_interactive_destroy()
kill_destroy();
al_foreach( &prompt_list, (void (*)(const void *))&free );
al_destroy( &prompt_list );
history_destroy();
writestr( L"\n" );
set_color( FISH_COLOR_RESET, FISH_COLOR_RESET );

View File

@@ -18,7 +18,7 @@ if test "$USER" = root
end
for i in $path_list
if not expr "$PATH" : .\*$i.\* >/dev/null
if not expr "$PATH" : "$i/*" >/dev/null
if test -d $i
set PATH $PATH $i
end
@@ -43,8 +43,8 @@ end
# Convenience functions
#
# The naming heuristic is that __fish_complete_* prints completions
# and descriptions, while __fish_print_* only prints the completion,
# without the description
# and descriptions, while __fish_print_* only prints the completions
# and no descriptions
#
function __fish_complete_users -d "Print a list of local users, with the real user name as a description"

View File

@@ -1,9 +1,3 @@
#
# This file defines various shellscript functions. Most of them are
# meant to be used directly by the user, but some of them, typically
# the ones whose name start with '__fish_', are only meant to be used
# internally by fish.
#
function contains -d (N_ "Test if a key is contained in a set of values")
while set -q argv

View File

@@ -2,7 +2,7 @@
function type -d (N_ "Print the type of a command")
# Initialize
set -l status 1
set -l res 1
set -l mode normal
set -l selection all
@@ -66,7 +66,7 @@ function type -d (N_ "Print the type of a command")
if test $selection != files
if contains -- $i (functions -na)
set status 0
set res 0
set found 1
switch $mode
case normal
@@ -86,7 +86,8 @@ function type -d (N_ "Print the type of a command")
end
if contains -- $i (builtin -n)
set status 0
set res 0
set found 1
switch $mode
case normal
@@ -107,7 +108,7 @@ function type -d (N_ "Print the type of a command")
set -l path (which $i ^/dev/null)
if test -x (echo $path)
set status 0
set res 0
set found 1
switch $mode
case normal
@@ -130,6 +131,6 @@ function type -d (N_ "Print the type of a command")
end
return $status
return $res
end