Compare commits

..

35 Commits

Author SHA1 Message Date
axel
1aa1ab540e Bump version number
darcs-hash:20060519141037-ac50b-52155b56cfcd60f4a57787cd29ef8fa3f6348acc.gz
2006-05-20 00:10:37 +10:00
axel
27c9eb8758 Fix test suite
darcs-hash:20060519141023-ac50b-96cb2401e68ed0fa169c332c8efa8037a8482011.gz
2006-05-20 00:10:23 +10:00
axel
e6b1035ddc Spelling fixes - Thanks Netocrat!
darcs-hash:20060519140425-ac50b-e687924b06a7711b4e92930e239aea4b01076434.gz
2006-05-20 00:04:25 +10:00
axel
9f6aba38d6 Define WCHAR_MAX to INT_MAX, not 0x7fffffff if undefined, as per suggestion from Netocrat
darcs-hash:20060519095948-ac50b-19842d18f4a020da7895d21df2f289dcf42f30bf.gz
2006-05-19 19:59:48 +10:00
axel
b52fe0feb6 Minor edits to builtin_set.c
darcs-hash:20060519085813-ac50b-67b6772ac7723e13312e444944cc4b077ba23479.gz
2006-05-19 18:58:13 +10:00
axel
db459f869a Update the PATH checking code to work in batch mode
darcs-hash:20060518133726-ac50b-81759f01565fdfdb85c042c1db1b766a9a6adcda.gz
2006-05-18 23:37:26 +10:00
axel
763a6b8351 Minor cleanup
darcs-hash:20060518130039-ac50b-c17e794113c38909d90be840fce36c7727c628b4.gz
2006-05-18 23:00:39 +10:00
axel
4a06821d99 Make fish remove invalid PATH entries on startup, and give a warning about it
darcs-hash:20060518130017-ac50b-9326ed6b5671bbe0285fd2d5604e4ea69087c7c1.gz
2006-05-18 23:00:17 +10:00
axel
22f3dcfd35 Fix bug that causes fish to elongate the PATH whith directories which are already there
darcs-hash:20060518125909-ac50b-9c23915bb6f51f9105e04ad71b102b386b5d43a9.gz
2006-05-18 22:59:09 +10:00
axel
dbb66e1895 Remove two minor memory leaks
darcs-hash:20060514223903-ac50b-4e764c460effd8c45493acfe5682626c3711c77e.gz
2006-05-15 08:39:03 +10:00
axel
5a7a264b96 Fix bug that caused block level io redirection to break on while loops
darcs-hash:20060514222905-ac50b-7dec0ed716f5fe6af9069b597eee464829a8d820.gz
2006-05-15 08:29:05 +10:00
axel
3d601bd751 Remove superflous event_signal_listen function, replace all calls to it with event_get
darcs-hash:20060514222758-ac50b-de4457154510b89d1c9b893bc39f06a23c8fc08f.gz
2006-05-15 08:27:58 +10:00
axel
c9deea2237 Minor edits
darcs-hash:20060514163936-ac50b-2a208818ccb26dabb60fba18078c3824da40adf5.gz
2006-05-15 02:39:36 +10:00
axel
32e54fd719 Remove some hardcoded values in favour of constants
darcs-hash:20060514132510-ac50b-2c703e8892d04b7d74555d05eb6618140e281a61.gz
2006-05-14 23:25:10 +10:00
axel
9ebdc16be6 Fix the longstanding hang-on-exit bug in eterm, as well as making sure the history is saved when the terminal emulator exits
darcs-hash:20060514101623-ac50b-f8ce693ec111e3c158640ef8de309bf7e5484c5b.gz
2006-05-14 20:16:23 +10:00
axel
92ecc01baa Fix broken method for sorting output of builtin commands 'functions', 'set' and others
darcs-hash:20060514094721-ac50b-9f1d8b6a2e8b4438e6a655de61af54d15cd4f537.gz
2006-05-14 19:47:21 +10:00
axel
ff1c5e058f Fix output of the functions command, where a single function would sometimes be printed twice
darcs-hash:20060514094635-ac50b-0cb03011b667a2458c19619a04d46140834e637c.gz
2006-05-14 19:46:35 +10:00
axel
3d192a8e93 Remoce C99:ism (Non-constant expression as array size)
darcs-hash:20060512154447-ac50b-5731603e1bf75f91703bf79cc06f6bbdb94e6a61.gz
2006-05-13 01:44:47 +10:00
axel
f5c6306bde Do not repaint prompt on universal variable events, but add event handler for fish_color_cwd to repiant prompt on change
darcs-hash:20060511122629-ac50b-a725d87fe9ec911282e8de79aa9de5c00d180caa.gz
2006-05-11 22:26:29 +10:00
axel
524e0aa174 Add fallback del_curterm which does nothing, used in preference to BSD curses del_curterm, which seems to do a double-free
darcs-hash:20060511115846-ac50b-8d5fc054d31cff637d30e858ae8ffe2b1d1e8c03.gz
2006-05-11 21:58:46 +10:00
axel
94abb30f94 Do not try to read init files if the cd to the proper directory fails
darcs-hash:20060511115758-ac50b-94661cb36c5a55bc78ddfe576d1cd40fada5f065.gz
2006-05-11 21:57:58 +10:00
axel
af8e053896 Include stdint.h, in fallback.h, since WCHAR_MAX might be defined there and not in wchar.h, as the C standard says - Thanks to Peter Moulder for pointing this one out
darcs-hash:20060510132704-ac50b-9da156a6ee5f04e33fa8d5bf8cee581a88643cb2.gz
2006-05-10 23:27:04 +10:00
axel
633e2f498f Escape $ character in apropos completions - Thanks to Peter Moulder for pointing this one out
darcs-hash:20060510115641-ac50b-51db7d181d63119c6edc223b06f8b8b63e8149d6.gz
2006-05-10 21:56:41 +10:00
axel
4932538c74 Add a few NULL checks to the codebase to avoid crashes on minor bugs
darcs-hash:20060510115431-ac50b-f6b50fb29b95ff88e7504355aaffef1edcb6739d.gz
2006-05-10 21:54:31 +10:00
axel
786144ba86 Make sure tokenization errors in eval_args doesn't cause fish to crash while error reporting
darcs-hash:20060510115351-ac50b-57354a1a6f044504a16e294840d0092ebf98f600.gz
2006-05-10 21:53:51 +10:00
axel
e3dd94f272 Add missing quote escape to ls completions
darcs-hash:20060510115243-ac50b-6aff103edec7d1499702d5eb38d9841571d95c16.gz
2006-05-10 21:52:43 +10:00
axel
b110a0ae21 Allow backslash escape fur null byte
darcs-hash:20060509165501-ac50b-3a69a7ed0b96d5be7860aa997b7c77e37a6b1dc7.gz
2006-05-10 02:55:01 +10:00
axel
48d9c38d1e Fixed use of improper storage type for variable
darcs-hash:20060509165207-ac50b-48561332ab938fe7972bbf07f32ac1f92322d316.gz
2006-05-10 02:52:07 +10:00
axel
51f8272ebd Make sure WCHAR_MAX is defined (This is missing on OpenBSD for example)
darcs-hash:20060509164222-ac50b-595fd7507e2e5585b1a14e32792a38853b795b47.gz
2006-05-10 02:42:22 +10:00
axel
77f35c1b41 Add a little padding in the documentation stylesheet to make it easier to differ between different header levels
darcs-hash:20060509164146-ac50b-f165e89d3cf5d9a8db9826d804cd62b85bd6a3f7.gz
2006-05-10 02:41:46 +10:00
axel
06668bfacb Alter syntax for set builtin so that better slicing operations are possible
darcs-hash:20060509164055-ac50b-8514b73bb9e992c463966f95f783f01893ba93bd.gz
2006-05-10 02:40:55 +10:00
axel
df59b8498f Minor edits of function descriptions, includes, etc.
darcs-hash:20060502162950-ac50b-c2fcfc957d55f292744bcb4b33b4d66fc42087ed.gz
2006-05-03 02:29:50 +10:00
axel
92fde30c0c Fix segfault when using the 'set' command with no arguments
darcs-hash:20060502162830-ac50b-d3ab63c29a6daeaa62803923b060ec69942911f8.gz
2006-05-03 02:28:30 +10:00
axel
d690a15b29 Make job id numbering start from 1, not 0
darcs-hash:20060428132137-ac50b-8e5adcdbc18ad7627b66e9129a13b037a669dd02.gz
2006-04-28 23:21:37 +10:00
axel
445f6539cf Fix two bugs in the jobs builtin, causing freezes and other incorrect behaviours
darcs-hash:20060424153434-ac50b-2434329395cbd4a258d6fb9f15e166065b2eb164.gz
2006-04-25 01:34:34 +10:00
37 changed files with 858 additions and 569 deletions

105
builtin.c
View File

@@ -497,27 +497,24 @@ static int builtin_builtin( wchar_t **argv )
if( list )
{
array_list_t names;
wchar_t **names_arr;
int i;
al_init( &names );
builtin_get_names( &names );
names_arr = list_to_char_arr( &names );
qsort( names_arr,
al_get_count( &names ),
sizeof(wchar_t *),
(int (*)(const void *, const void *))&wcsfilecmp );
sort_list( &names );
for( i=0; i<al_get_count( &names ); i++ )
{
if( wcscmp( names_arr[i], L"count" ) == 0 )
wchar_t *el = (wchar_t *)al_get( &names, i );
if( wcscmp( el, L"count" ) == 0 )
continue;
sb_append2( sb_out,
names_arr[i],
el,
L"\n",
(void *)0 );
}
free( names_arr );
al_destroy( &names );
}
return 0;
@@ -677,7 +674,6 @@ static int builtin_functions( wchar_t **argv )
wchar_t *desc=0;
array_list_t names;
wchar_t **names_arr;
int argc=builtin_count_args( argv );
int list=0;
@@ -820,11 +816,7 @@ static int builtin_functions( wchar_t **argv )
al_init( &names );
function_get_names( &names, show_hidden );
names_arr = list_to_char_arr( &names );
qsort( names_arr,
al_get_count( &names ),
sizeof(wchar_t *),
(int (*)(const void *, const void *))&wcsfilecmp );
sort_list( &names );
if( is_screen )
{
string_buffer_t buff;
@@ -833,12 +825,12 @@ static int builtin_functions( wchar_t **argv )
for( i=0; i<al_get_count( &names ); i++ )
{
sb_append2( &buff,
names_arr[i],
al_get(&names, i),
L", ",
(void *)0 );
}
write_screen( (wchar_t *)buff.buff );
write_screen( (wchar_t *)buff.buff, sb_out );
sb_destroy( &buff );
}
else
@@ -846,13 +838,12 @@ static int builtin_functions( wchar_t **argv )
for( i=0; i<al_get_count( &names ); i++ )
{
sb_append2( sb_out,
names_arr[i],
al_get(&names, i),
L"\n",
(void *)0 );
}
}
free( names_arr );
al_destroy( &names );
return 0;
}
@@ -865,16 +856,13 @@ static int builtin_functions( wchar_t **argv )
sb_append( sb_out, _( L"Current function definitions are:\n\n" ) );
al_init( &names );
function_get_names( &names, show_hidden );
names_arr = list_to_char_arr( &names );
qsort( names_arr,
al_get_count( &names ),
sizeof(wchar_t *),
(int (*)(const void *, const void *))&wcsfilecmp );
sort_list( &names );
for( i=0; i<al_get_count( &names ); i++ )
{
functions_def( names_arr[i] );
functions_def( (wchar_t *)al_get( &names, i ) );
}
free( names_arr );
al_destroy( &names );
break;
}
@@ -1170,7 +1158,6 @@ static int builtin_function( wchar_t **argv )
{
int i;
array_list_t names;
wchar_t **names_arr;
int chars=0;
// builtin_print_help( argv[0], sb_err );
@@ -1180,14 +1167,11 @@ static int builtin_function( wchar_t **argv )
al_init( &names );
function_get_names( &names, 0 );
names_arr = list_to_char_arr( &names );
qsort( names_arr,
al_get_count( &names ),
sizeof(wchar_t *),
(int (*)(const void *, const void *))&wcsfilecmp );
sort_list( &names );
for( i=0; i<al_get_count( &names ); i++ )
{
wchar_t *nxt = names_arr[i];
wchar_t *nxt = (wchar_t *)al_get( &names, i );
int l = wcslen( nxt + 2 );
if( chars+l > common_get_width() )
{
@@ -1198,7 +1182,6 @@ static int builtin_function( wchar_t **argv )
sb_append2( sb_err,
nxt, L" ", (void *)0 );
}
free( names_arr );
al_destroy( &names );
sb_append( sb_err, L"\n" );
@@ -1351,7 +1334,7 @@ static int builtin_read( wchar_t **argv )
int exit_res=0;
woptind=0;
while( 1 )
{
const static struct woption
@@ -1439,7 +1422,6 @@ static int builtin_read( wchar_t **argv )
case L'?':
builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -1874,7 +1856,7 @@ static int builtin_exit( wchar_t **argv )
return 1;
}
reader_exit( 1 );
reader_exit( 1, 0 );
return ec;
}
@@ -2077,7 +2059,7 @@ static void make_first( job_t *j )
*/
static int builtin_fg( wchar_t **argv )
{
job_t *j;
job_t *j=0;
if( argv[1] == 0 )
{
@@ -2127,27 +2109,40 @@ static int builtin_fg( wchar_t **argv )
}
else
{
int pid = abs(wcstol( argv[1], 0, 10 ));
j = job_get_from_pid( pid );
if( !j )
wchar_t *end;
int pid = abs(wcstol( argv[1], &end, 10 ));
if( *end )
{
sb_printf( sb_err,
_( L"%ls: No suitable job: %d\n" ),
argv[0],
pid );
builtin_print_help( argv[0], sb_err );
sb_printf( sb_err,
_( L"%ls: Argument must be a number: %ls\n" ),
argv[0],
argv[1] );
builtin_print_help( argv[0], sb_err );
}
if( !j->job_control )
else
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
argv[0],
pid,
j->command );
builtin_print_help( argv[0], sb_err );
j=0;
j = job_get_from_pid( pid );
if( !j || !j->constructed || job_is_completed( j ))
{
sb_printf( sb_err,
_( L"%ls: No suitable job: %d\n" ),
argv[0],
pid );
builtin_print_help( argv[0], sb_err );
j=0;
}
else if( !j->job_control )
{
sb_printf( sb_err,
_( L"%ls: Can't put job %d, '%ls' to foreground because it is not under job control\n" ),
argv[0],
pid,
j->command );
builtin_print_help( argv[0], sb_err );
j=0;
}
}
}
if( j )

View File

@@ -26,66 +26,164 @@ Functions used for implementing the set builtin.
#include "parser.h"
#include "translate.h"
/**
Error message for invalid path operations
*/
#define BUILTIN_SET_PATH_ERROR L"%ls: Could not add component %ls to %ls.\n"
/**
Hint for invalid path operation with a colon
*/
#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.
Error for mismatch between index count and elements
*/
static void my_env_set( const wchar_t *key, const wchar_t *val, int scope )
{
#define BUILTIN_SET_ARG_COUNT L"%ls: The number of variable indexes does not match the number of values\n"
switch( env_set( key, val, scope | ENV_USER ) )
/**
Test if the specified variable should be subject to path validation
*/
static int is_path_variable( const wchar_t *env )
{
return contains_str( env,
L"PATH",
L"CDPATH",
(void *)0 );
}
/**
Call env_set. If this is a path variable, e.g. PATH, validate the
elements. On error, print a description of the problem to stderr.
*/
static int my_env_set( const wchar_t *key, array_list_t *val, int scope )
{
string_buffer_t sb;
int i;
int retcode = 0;
wchar_t *val_str=0;
if( is_path_variable( key ) )
{
int error = 0;
for( i=0; i<al_get_count( val ); i++ )
{
int show_perror = 0;
int show_hint = 0;
struct stat buff;
wchar_t *dir = (wchar_t *)al_get( val, 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),
L"set",
dir,
key );
colon = wcschr( dir, L':' );
if( colon && *(colon+1) )
{
show_hint = 1;
}
}
if( show_perror )
{
builtin_wperror( L"set" );
}
if( show_hint )
{
sb_printf( sb_err,
_(BUILTIN_SET_PATH_HINT),
L"set",
key,
key,
wcschr( dir, L':' )+1);
}
if( error )
{
break;
}
}
if( error )
{
return 1;
}
}
sb_init( &sb );
if( al_get_count( val ) )
{
for( i=0; i<al_get_count( val ); i++ )
{
sb_append( &sb, (wchar_t *)al_get( val, i ) );
if( i<al_get_count( val )-1 )
{
sb_append( &sb, ARRAY_SEP_STR );
}
}
val_str = (wchar_t *)sb.buff;
}
switch( env_set( key, val_str, scope | ENV_USER ) )
{
case ENV_PERM:
{
sb_printf( sb_err, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key );
retcode=1;
break;
}
}
sb_destroy( &sb );
return retcode;
}
/**
Extract the name from a destination argument of the form name[index1 index2...]
*/
static int parse_fill_name( string_buffer_t *name,
const wchar_t *src)
{
if (src == 0)
{
return 0;
}
while (iswalnum(*src) || *src == L'_')
{
sb_append_char(name, *src++);
}
if (*src != L'[' && *src != L'\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;
}
else
{
return 0;
}
}
/**
Extract indexes from a destination argument of the form name[index1 index2...]
*/
static int parse_fill_indexes( array_list_t *indexes,
const wchar_t *src)
{
int count = 0;
\param indexes the list to insert the new indexes into
\param src the source string to parse
\param name the name of the element. Return null if the name in \c src does not match this name
\return the number of indexes parsed, or -1 on error
*/
static int parse_index( array_list_t *indexes,
const wchar_t *src,
const wchar_t *name )
{
int len;
int count = 0;
const wchar_t *src_orig = src;
if (src == 0)
{
return 0;
@@ -96,16 +194,27 @@ static int parse_fill_indexes( array_list_t *indexes,
src++;
}
if (*src == L'\0')
if (*src != L'[')
{
sb_printf( sb_err, _(BUILTIN_SET_ARG_COUNT), L"set" );
return 0;
}
if (*src++ != L'[')
{
return -1;
}
len = src-src_orig;
if( (wcsncmp( src_orig, name, len )!=0) || (wcslen(name) != (len)) )
{
sb_printf( sb_err,
_(L"%ls: Multiple variable names specified in single call (%ls and %.*ls)\n"),
L"set",
name,
len,
src_orig);
return 0;
}
src++;
while (iswspace(*src))
{
src++;
@@ -118,9 +227,9 @@ static int parse_fill_indexes( array_list_t *indexes,
if (end == src)
{
sb_printf(sb_err, _(L"%ls: Invalid index starting at '%ls'\n"), L"set", src);
return -1;
return 0;
}
int *ind = (int *) calloc(1, sizeof(int));
*ind = (int) l_ind;
al_push(indexes, ind);
@@ -139,7 +248,8 @@ static int parse_fill_indexes( array_list_t *indexes,
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
\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,
@@ -172,7 +282,7 @@ static int al_contains_int( array_list_t *list,
for (i = 0; i < al_get_count(list); i++)
{
int *current = (int *) al_get(list, i);
if (current != 0 && *current == val)
if( current != 0 && *current == val )
{
return 1;
}
@@ -185,7 +295,7 @@ static int al_contains_int( array_list_t *list,
/**
Erase from a list values at specified indexes
*/
static int erase_values(array_list_t *list, array_list_t *indexes)
static void erase_values(array_list_t *list, array_list_t *indexes)
{
int i;
array_list_t result;
@@ -207,29 +317,6 @@ static int erase_values(array_list_t *list, array_list_t *indexes)
al_truncate(list,0);
al_push_all( list, &result );
al_destroy(&result);
return al_get_count(list);
}
/**
Fill a string buffer with values from a list, using ARRAY_SEP_STR to separate them
*/
static int fill_buffer_from_list(string_buffer_t *sb, array_list_t *list)
{
int i;
for (i = 0; i < al_get_count(list); i++)
{
wchar_t *v = (wchar_t *) al_get(list, i);
if (v != 0)
{
sb_append(sb, v);
}
if (i < al_get_count(list) - 1)
sb_append(sb, ARRAY_SEP_STR);
}
return al_get_count(list);
}
@@ -269,19 +356,12 @@ 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.
The set builtin. Creates, updates and erases environment variables
and environemnt variable arrays.
*/
int builtin_set( wchar_t **argv )
{
@@ -337,14 +417,12 @@ int builtin_set( wchar_t **argv )
Variables used for performing the actual work
*/
wchar_t *dest = 0;
array_list_t values;
string_buffer_t name_sb;
int retcode=0;
wchar_t *name;
array_list_t indexes;
int retval;
int scope;
int slice=0;
int i;
/* Parse options to obtain the requested operation and the modifiers */
woptind = 0;
while (1)
@@ -407,7 +485,7 @@ int builtin_set( wchar_t **argv )
argv[0],
parser_current_line() );
builtin_print_help( argv[0], sb_err );
// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -420,7 +498,7 @@ int builtin_set( wchar_t **argv )
argv[0],
parser_current_line() );
builtin_print_help( argv[0], sb_err );
// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -433,7 +511,7 @@ int builtin_set( wchar_t **argv )
BUILTIN_ERR_GLOCAL,
argv[0],
parser_current_line() );
builtin_print_help( argv[0], sb_err );
// builtin_print_help( argv[0], sb_err );
return 1;
}
@@ -446,10 +524,15 @@ int builtin_set( wchar_t **argv )
BUILTIN_ERR_EXPUNEXP,
argv[0],
parser_current_line() );
builtin_print_help( argv[0], sb_err );
// builtin_print_help( argv[0], sb_err );
return 1;
}
/*
Calculate the scope value for variable assignement
*/
scope = (local ? ENV_LOCAL : 0) | (global ? ENV_GLOBAL : 0) | (export ? ENV_EXPORT : 0) | (unexport ? ENV_UNEXPORT : 0) | (universal ? ENV_UNIVERSAL:0) | ENV_USER;
if( query )
{
/*
@@ -468,262 +551,188 @@ int builtin_set( wchar_t **argv )
return retcode;
}
/* Parse destination */
if( woptind < argc )
if( woptind == argc )
{
dest = wcsdup(argv[woptind++]);
if( !wcslen( dest ) )
/*
Print values of variables
*/
if( erase )
{
free( dest );
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
return 1;
}
sb_printf( sb_err,
_(L"%ls: Erase needs a variable name\n%ls\n"),
argv[0],
parser_current_line() );
// builtin_print_help( argv[0], sb_err );
retcode = 1;
}
else
{
print_variables( 1, 1, scope );
}
return retcode;
}
/* Parse values */
// wchar_t **values = woptind < argc ? (wchar_t **) calloc(argc - woptind, sizeof(wchar_t *)) : 0;
al_init(&values);
while( woptind < argc )
if( list )
{
al_push(&values, argv[woptind++]);
/* Maybe we should issue an error if there are any other arguments? */
print_variables(0, 0, scope);
return 0;
}
if( !(dest = wcsdup(argv[woptind])))
{
die_mem();
}
if( is_path_variable( dest ) )
if( wcschr( dest, L'[' ) )
{
int i;
int error = 0;
slice = 1;
*wcschr( dest, L'[' )=0;
}
if( !wcslen( dest ) )
{
free( dest );
sb_printf( sb_err, BUILTIN_ERR_VARNAME_ZERO, argv[0] );
return 1;
}
/*
set assignment can work in two modes, either using slices or
using the whole array. We detect which mode is used here.
*/
if( slice )
{
/*
Slice mode
*/
int idx_count, val_count;
array_list_t values;
array_list_t indexes;
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 )
al_init(&values);
al_init(&indexes);
for( ; woptind<argc; woptind++ )
{
if( !parse_index( &indexes, argv[woptind], dest ) )
{
retcode = 1;
break;
}
}
val_count = argc-woptind-1;
idx_count = al_get_count( &indexes );
if( error )
{
al_destroy(&values);
return 1;
}
}
/* Extract variable name and indexes */
sb_init(&name_sb);
retval = parse_fill_name(&name_sb, dest);
if( retval < 0 )
retcode=1;
if( !retcode )
{
name = (wchar_t *) name_sb.buff;
al_init(&indexes);
retval = parse_fill_indexes(&indexes, dest);
if (retval < 0)
retcode = 1;
}
if( !retcode )
{
int i;
int finished=0;
/* Do the actual work */
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? */
print_variables(0, 0, scope);
finished=1;
}
if( (!finished ) &&
(name == 0 || wcslen(name) == 0))
{
/* No arguments -- display name & value for all variables in scope */
if( erase )
if( !erase )
{
sb_printf( sb_err,
_(L"%ls: Erase needs a variable name\n%ls\n"),
argv[0],
parser_current_line() );
if( val_count < idx_count )
{
sb_printf( sb_err, _(BUILTIN_SET_ARG_COUNT), argv[0] );
retcode=1;
break;
}
if( val_count == idx_count )
{
woptind++;
break;
}
}
}
if( !retcode )
{
/*
Slice indexes have been calculated, do the actual work
*/
array_list_t result;
al_init(&result);
expand_variable_array( env_get(dest), &result );
if( erase )
{
erase_values(&result, &indexes);
my_env_set( dest, &result, scope);
}
else
{
array_list_t value;
al_init(&value);
while( woptind < argc )
{
al_push(&value, argv[woptind++]);
}
update_values( &result,
&indexes,
&value );
builtin_print_help( argv[0], sb_err );
retcode = 1;
}
else
{
print_variables( 1, 1, scope );
}
finished=1;
}
if( !finished )
{
if( al_get_count( &values ) == 0 &&
al_get_count( &indexes ) == 0 &&
!erase &&
!list )
{
my_env_set( name, 0, scope );
finished = 1;
}
my_env_set(dest,
&result,
scope);
al_destroy( &value );
}
al_foreach( &result, (void (*)(const void *))&free );
al_destroy( &result );
}
al_foreach( &indexes, (void (*)(const void *))&free );
al_destroy(&indexes);
al_destroy(&values);
if( !finished )
}
else
{
woptind++;
/*
No slicing
*/
if( erase )
{
/* There are some arguments, we have at least a variable name */
if( erase && al_get_count(&values) != 0 )
if( woptind != argc )
{
sb_printf( sb_err,
_(L"%ls: Values cannot be specfied with erase\n%ls\n"),
argv[0],
parser_current_line() );
builtin_print_help( argv[0], sb_err );
retcode = 1;
}
retcode=1;
}
else
{
/* All ok, we can alter the specified variable */
array_list_t val_l;
al_init(&val_l);
void *old=0;
if (al_get_count(&indexes) == 0)
{
/* We will act upon the entire variable */
al_push( &val_l, wcsdup(L"") );
old = val_l.arr;
/* Build indexes for all variable or all new values */
int end_index = erase ? al_get_count(&val_l) : al_get_count(&values);
for (i = 0; i < end_index; i++)
{
int *ind = (int *) calloc(1, sizeof(int));
*ind = i + 1;
al_push(&indexes, ind);
}
}
else
{
/* We will act upon some specific indexes */
expand_variable_array( env_get(name), &val_l );
}
string_buffer_t result_sb;
sb_init(&result_sb);
if (erase)
{
int rem = erase_values(&val_l, &indexes);
if (rem == 0)
{
env_remove(name, ENV_USER);
}
else
{
fill_buffer_from_list(&result_sb, &val_l);
my_env_set(name, (wchar_t *) result_sb.buff, scope);
}
}
else
{
update_values( &val_l,
&indexes,
&values );
fill_buffer_from_list( &result_sb,
&val_l );
my_env_set(name,
(wchar_t *) result_sb.buff,
scope);
}
al_foreach( &val_l, (void (*)(const void *))&free );
al_destroy(&val_l);
sb_destroy(&result_sb);
{
env_remove( dest, ENV_USER );
}
}
else
{
array_list_t val;
al_init( &val );
for( i=woptind; i<argc; i++ )
{
al_push( &val, argv[i] );
}
al_foreach( &indexes, (void (*)(const void *))&free );
al_destroy(&indexes);
retcode = my_env_set( dest, &val, scope );
al_destroy( &val );
}
}
/* Common cleanup */
free(dest);
sb_destroy(&name_sb);
al_destroy( &values );
free( dest );
return retcode;
}

View File

@@ -61,17 +61,27 @@ parts of fish.
#include "wildcard.h"
#include "parser.h"
/**
The maximum number of minor errors to report. Further errors will be omitted.
*/
#define ERROR_MAX_COUNT 1
/**
The number of milliseconds to wait between polls when attempting to acquire
a lockfile
*/
#define LOCKPOLLINTERVAL 10
/**
Highest legal ascii value
*/
#define ASCII_MAX 127u
/**
Highest legal 16-bit unicode value
*/
#define UCS2_MAX 0xffffu
/**
Highest legal byte value
*/
#define BYTE_MAX 0xffu
struct termios shell_modes;
int error_max=1;
@@ -495,6 +505,12 @@ int contains_str( const wchar_t *a, ... )
wchar_t *arg;
va_list va;
int res = 0;
if( !a )
{
debug( 1, L"Warning: Called contains_str with null argument. This is a bug." );
return 0;
}
va_start( va, a );
while( (arg=va_arg(va, wchar_t *) )!= 0 )
@@ -539,23 +555,27 @@ void debug( int level, const wchar_t *msg, ... )
{
va_list va;
string_buffer_t sb;
string_buffer_t sb2;
if( level > debug_level )
return;
sb_init( &sb );
sb_init( &sb2 );
va_start( va, msg );
sb_printf( &sb, L"%ls: ", program_name );
sb_vprintf( &sb, msg, va );
va_end( va );
write_screen( (wchar_t *)sb.buff );
write_screen( (wchar_t *)sb.buff, &sb2 );
fwprintf( stderr, L"%ls", sb2.buff );
sb_destroy( &sb );
sb_destroy( &sb2 );
}
void write_screen( const wchar_t *msg )
void write_screen( const wchar_t *msg, string_buffer_t *buff )
{
const wchar_t *start, *pos;
int line_width = 0;
@@ -605,8 +625,8 @@ void write_screen( const wchar_t *msg )
*/
wchar_t *token = wcsndup( start, pos-start );
if( line_width != 0 )
putwc( L'\n', stderr );
fwprintf( stderr, L"%ls-\n", token );
sb_append_char( buff, L'\n' );
sb_printf( buff, L"%ls-\n", token );
free( token );
line_width=0;
}
@@ -618,10 +638,10 @@ void write_screen( const wchar_t *msg )
wchar_t *token = wcsndup( start, pos-start );
if( (line_width + (line_width!=0?1:0) + tok_width) > screen_width )
{
putwc( L'\n', stderr );
sb_append_char( buff, L'\n' );
line_width=0;
}
fwprintf( stderr, L"%ls%ls", line_width?L" ":L"", token );
sb_printf( buff, L"%ls%ls", line_width?L" ":L"", token );
free( token );
line_width += (line_width!=0?1:0) + tok_width;
}
@@ -636,9 +656,9 @@ void write_screen( const wchar_t *msg )
}
else
{
fwprintf( stderr, L"%ls", msg );
sb_printf( buff, L"%ls", msg );
}
putwc( L'\n', stderr );
sb_append_char( buff, L'\n' );
}
wchar_t *escape( const wchar_t *in,
@@ -832,14 +852,14 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
int base=16;
int byte = 0;
int max_val = 127;
wchar_t max_val = ASCII_MAX;
switch( in[in_pos] )
{
case L'u':
{
chars=4;
max_val = 35535;
max_val = UCS2_MAX;
break;
}
@@ -858,7 +878,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
case L'X':
{
byte=1;
max_val = 255;
max_val = BYTE_MAX;
break;
}
@@ -884,7 +904,7 @@ wchar_t *unescape( const wchar_t * orig, int unescape_special )
res=(res*base)|d;
}
if( (res > 0) && (res <= max_val) )
if( (res <= max_val) )
{
in[out_pos] = (byte?ENCODE_DIRECT_BASE:0)+res;
}

View File

@@ -181,9 +181,11 @@ void error_reset();
const wchar_t *wsetlocale( int category, const wchar_t *locale );
/**
Checks if \c needle is included in the list of strings specified
Checks if \c needle is included in the list of strings specified. A warning is printed if needle is zero.
\param needle the string to search for in the list
\return zero is needle is not found, of if needle is null, non-zero otherwise
*/
int contains_str( const wchar_t *needle, ... );
@@ -285,10 +287,10 @@ int common_get_height();
void common_handle_winch( int signal );
/**
Write paragraph of output to screen. Ignore newlines in message and
perform internal line-breaking.
Write paragraph of output to the specified stringbuffer, and redo
the linebreaks to fit the current screen.
*/
void write_screen( const wchar_t *msg );
void write_screen( const wchar_t *msg, string_buffer_t *buff );
#endif

View File

@@ -1983,7 +1983,8 @@ void complete( const wchar_t *cmd,
{
if( parser_is_subcommand( tok_last( &tok ) ) )
break;
free( current_command );
current_command = wcsdup( tok_last( &tok ) );
on_command = (pos <= tok_get_pos( &tok) + wcslen( tok_last( &tok ) ) );
@@ -2050,11 +2051,12 @@ void complete( const wchar_t *cmd,
}
}
free( current_token );
free( current_command );
free( prev_token );
}
free( current_token );
free( current_command );
free( prev_token );
error_max=old_error_max;
condition_cache_clear();

View File

@@ -1,5 +1,5 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(fish,1.21.6,fish-users@lists.sf.net)
AC_INIT(fish,1.21.7,fish-users@lists.sf.net)
# If needed, run autoconf to regenerate the configure file
AC_MSG_CHECKING([if autoconf needs to be run])
@@ -389,6 +389,20 @@ else
AC_MSG_RESULT(no)
fi
# Check if we are using basic BSD curses - in that case we redefine
# del_curterm as a no-op, to avoid a double-free
AC_MSG_CHECKING([If we are using BSD curses])
case $target_os in
*bsd*)
AC_MSG_RESULT(yes)
AC_CHECK_LIB( ncurses, del_curterm, true, [AC_DEFINE([HAVE_BROKEN_DEL_CURTERM],[1],[We are using basic BSD curses, redefine del_curterm to a no-op to avoid a double-free bug])])
;;
*)
AC_MSG_RESULT(no)
;;
esac
# Tell the world what we know
AC_CONFIG_FILES([Makefile fish.spec doc_src/fish.1 doc_src/Doxyfile etc/fish etc/fish_interactive.fish share/fish seq])
AC_OUTPUT

View File

@@ -144,7 +144,7 @@ a number called a file descriptor (FD). These are:
The reason for providing for two output file descriptors is to allow
separation of errors and warnings from regular program output.
Any file descriptor can be directed to a different output than it's
Any file descriptor can be directed to a different output than its
default through a simple mechanism called a redirection.
An example of a file redirection is <code> echo hello \>output.txt</code>,
@@ -488,7 +488,7 @@ becomes explicitly NOT a part of the variable name, even if it happens
to be a legal variable name character. That's why '{$USER}san' looks
for the variable '$USER' and not for the variable '$USERsan'. It's
simply a case of one syntax lending itself nicely to solving an
unrelated problem in it's spare time.
unrelated problem in its spare time.
Variable expansion is the only type of expansion performed on double
quoted strings. There is, however, an important difference in how
@@ -644,7 +644,7 @@ echo $pirate
\subsection variables-universal More on universal variables
Universal variables are variables that are shared between all the
users fish sessions on the computer. Fish stores many of it's
users fish sessions on the computer. Fish stores many of its
configuration options as universal variables. This means that in order
to change fish settings, all you have to do is change the variable
value once, and it will be automatically updated for all sessions, and
@@ -758,9 +758,10 @@ certain environment variables.
\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 most of these variables.
- \c _, which is the name of the currently running command.
- \c argv, which is an array of arguments to the shell or function. \c argv is only defined when inside a function call, or if fish was invoked with a list of arguments, like 'fish myscript.fish foo bar'. This variable can be changed by the user.
- \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.
@@ -769,11 +770,11 @@ values of these variables. They are:
- \c LANG, \c LC_ALL, \c LC_COLLATE, \c LC_CTYPE, \c LC_MESSAGES, \c LC_MONETARY, \c LC_NUMERIC and \c LC_TIME set the language option for the shell and subprograms. See the section <a href='#variables-locale'>Locale variables</a> for more information.
Variables whose name are in uppercase are exported to the commands
started by fish. This rule is not enforced 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.
started by fish, those in lowercase are not exported. This rule is not
enforced 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.
\subsection variables-locale Locale variables
@@ -1025,7 +1026,7 @@ Detected errors include:
- Mismatched parenthesis
When the cursor is over a parenthesis or a quote, \c fish also
highlights it's matching quote or parenthesis.
highlights its matching quote or parenthesis.
To customize the syntax highlighting, you can set the environment
variables \c fish_color_normal, \c fish_color_command, \c
@@ -1116,7 +1117,7 @@ command.
If you install fish in your home directory, fish will not work
correctly for any other user than yourself. This is because fish needs
it's initalization files to function properly. To solve this
its initalization files to function properly. To solve this
problem, either copy the initialization files to each fish users home
directory, or install them in /etc.
@@ -1176,7 +1177,7 @@ msgstr "%ls: Inget passande jobb\n"
placeholders. These will be replaced by a value by fish at
runtime. You must always take care to use exactly the same
placeholders in the same order in your translation. (Actually, there
are ways to avoid this, but they are to complicated for this short
are ways to avoid this, but they are too complicated for this short
introduction. See the full manual for the printf C function for more
information.)
@@ -1199,8 +1200,9 @@ g++, javac, java, gcj, lpr, doxygen, whois, find)
- 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
- wait shellscript
- Signal handler to save the history file before exiting from a signal
- Support for the screen clipboard
- The -a string sent to complete should be validated
- Fish should detect improper variable expansion when validating, e.g. strings such as 'foo$' and 'a${}' should be detected as invalid
\subsection todo-possible Possible features

13
event.c
View File

@@ -57,7 +57,7 @@ typedef struct
active, which is the one that new events is written to. The inactive
one contains the events that are currently beeing performed.
*/
static signal_list_t sig_list[2];
static signal_list_t sig_list[]={{0,0},{0,0}};
/**
The index of sig_list that is the list of signals currently written to
@@ -273,9 +273,12 @@ void event_remove( event_t *criterion )
event_t e;
/*
Because of concurrency issues, env_remove does not actually free
any events - instead it simply moves all events that should be
removed from the event list to the killme list.
Because of concurrency issues (env_remove could remove an event
that is currently being executed), env_remove does not actually
free any events - instead it simply moves all events that should
be removed from the event list to the killme list, and the ones
that shouldn't be killed to new_list, and then drops the empty
events-list.
*/
if( !events )
@@ -617,7 +620,6 @@ void event_fire( event_t *event )
void event_init()
{
sig_list[active_list].count=0;
}
void event_destroy()
@@ -653,3 +655,4 @@ void event_free( event_t *e )
free( (void *)e->param1.variable );
free( e );
}

26
exec.c
View File

@@ -126,7 +126,7 @@ int exec_pipe( int fd[2])
if( open_fds == 0 )
{
open_fds = al_new();
open_fds = al_halloc( global_context );
}
al_push( open_fds, (void *)(long)fd[0] );
@@ -164,7 +164,8 @@ static int use_fd_in_pipe( int fd, io_data_t *io )
the redirection list io. This should make sure that there are no
stray opened file descriptors in the child.
\param io the list of io redirections for this job. Pipes mentioned here should not be closed.
\param io the list of io redirections for this job. Pipes mentioned
here should not be closed.
*/
static void close_unused_internal_pipes( io_data_t *io )
{
@@ -185,20 +186,6 @@ static void close_unused_internal_pipes( io_data_t *io )
}
}
void exec_init()
{
}
void exec_destroy()
{
if( open_fds )
{
al_destroy( open_fds );
free( open_fds );
}
}
/**
Make sure the fd used by this redirection is not used by i.e. a pipe.
*/
@@ -564,7 +551,7 @@ static void internal_exec_helper( const wchar_t *def,
io_data_t *io_internal = io_transmogrify( io );
int is_block_old=is_block;
is_block=1;
/*
Did the transmogrification fail - if so, set error status and return
*/
@@ -575,7 +562,7 @@ static void internal_exec_helper( const wchar_t *def,
}
signal_unblock();
eval( def, io_internal, block_type );
signal_block();
@@ -837,7 +824,7 @@ void exec( job_t *j )
io_buffer = io_buffer_create();
j->io = io_add( j->io, io_buffer );
}
internal_exec_helper( p->argv[0], TOP, j->io );
break;
@@ -852,6 +839,7 @@ void exec( job_t *j )
if( p == j->first_process )
{
io_data_t *in = io_get( j->io, 0 );
if( in )
{
switch( in->io_mode )

11
exec.h
View File

@@ -18,17 +18,6 @@
*/
#define PIPE_ERROR _(L"An error occurred while setting up pipe")
/**
Initialize the exec library
*/
void exec_init();
/**
Destroy dynamically allocated data and other resources used by the
exec library
*/
void exec_destroy();
/**
Execute the processes specified by j.

View File

@@ -421,16 +421,18 @@ static int find_process( const wchar_t *proc,
{
int jid = wcstol( proc, 0, 10 );
j = job_get( jid );
if( (j != 0) && (j->command != 0 ) )
if( jid > 0 )
{
j = job_get( jid );
if( (j != 0) && (j->command != 0 ) )
{
result = malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", j->pgid );
al_push( out, result );
found = 1;
{
result = malloc(sizeof(wchar_t)*16 );
swprintf( result, 16, L"%d", j->pgid );
al_push( out, result );
found = 1;
}
}
}
}

View File

@@ -997,3 +997,11 @@ wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz)
#endif
#ifdef HAVE_BROKEN_DEL_CURTERM
int del_curterm(TERMINAL *oterm)
{
}
#endif

View File

@@ -3,10 +3,18 @@
#define FISH_FALLBACK_H
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <wctype.h>
#include <wchar.h>
#include "common.h"
#include <limits.h>
#ifndef WCHAR_MAX
/**
This _should_ be defined by wchar.h, but e.g. OpenBSD doesn't.
*/
#define WCHAR_MAX INT_MAX
#endif
/**
Under curses, tputs expects an int (*func)(char) as its last
@@ -213,7 +221,8 @@ wchar_t *wcsndup( const wchar_t *in, int c );
/**
Converts from wide char to digit in the specified base. If d is not
a valid digit in the specified base, return -1.
a valid digit in the specified base, return -1. This is a helper
function for wcstol, but it is useful itself, so it is exported.
*/
long convert_digit( wchar_t d, int base );
@@ -262,4 +271,12 @@ size_t wcslcpy( wchar_t *dst, const wchar_t *src, size_t siz );
#endif
#ifdef HAVE_BROKEN_DEL_CURTERM
/**
BSD del_curterm seems to do a double-free. We redefine it as a no-op
*/
int del_curterm(TERMINAL *oterm);
#endif
#endif

View File

@@ -102,7 +102,7 @@ static int pq_compare( void *e1, void *e2 )
/**
Test priority queue functionality
*/
static int pq_test( int elements )
static void pq_test( int elements )
{
int i;
int prev;
@@ -290,7 +290,7 @@ static int hash_test( int elements )
/**
Arraylist test
*/
static int al_test( int sz)
static void al_test( int sz)
{
int i;
array_list_t l;
@@ -690,7 +690,6 @@ int main( int argc, char **argv )
proc_init();
halloc_util_init();
event_init();
exec_init();
parser_init();
function_init();
builtin_init();
@@ -718,7 +717,6 @@ int main( int argc, char **argv )
builtin_destroy();
complete_destroy();
wutil_destroy();
exec_destroy();
event_destroy();
proc_destroy();
halloc_util_destroy();

View File

@@ -248,6 +248,19 @@ void function_set_desc( const wchar_t *name, const wchar_t *desc )
data->desc =wcsdup(desc);
}
static int al_contains_str( array_list_t *list, const wchar_t * str )
{
int i;
for( i=0; i<al_get_count( list ); i++ )
{
if( wcscmp( al_get( list, i ), str) == 0 )
{
return 1;
}
}
return 0;
}
/**
Helper function for removing hidden functions
*/
@@ -258,8 +271,25 @@ static void get_names_internal( const void *key,
wchar_t *name = (wchar_t *)key;
function_data_t *f = (function_data_t *)val;
if( name[0] != L'_' && !f->is_binding)
if( name[0] != L'_' && !f->is_binding && !al_contains_str( (array_list_t *)aux, name ) )
{
al_push( (array_list_t *)aux, name );
}
}
/**
Helper function for removing hidden functions
*/
static void get_names_internal_all( const void *key,
const void *val,
void *aux )
{
wchar_t *name = (wchar_t *)key;
if( !al_contains_str( (array_list_t *)aux, name ) )
{
al_push( (array_list_t *)aux, name );
}
}
void function_get_names( array_list_t *list, int get_hidden )
@@ -267,9 +297,13 @@ void function_get_names( array_list_t *list, int get_hidden )
autoload_names( list, get_hidden );
if( get_hidden )
hash_get_keys( &function, list );
{
hash_foreach2( &function, &get_names_internal_all, list );
}
else
{
hash_foreach2( &function, &get_names_internal, list );
}
}

View File

@@ -119,7 +119,8 @@ const wchar_t *name_arr[] =
L"history-token-search-backward",
L"history-token-search-forward",
L"self-insert",
L"null"
L"null",
L"eof"
}
;
@@ -155,7 +156,8 @@ const wchar_t *desc_arr[] =
L"Search backward through list of previous commands for matching token",
L"Search forward through list of previous commands for matching token",
L"Insert the pressed key",
L"Do nothing"
L"Do nothing",
L"End of file"
}
;
@@ -191,7 +193,8 @@ const wchar_t code_arr[] =
R_HISTORY_TOKEN_SEARCH_BACKWARD,
R_HISTORY_TOKEN_SEARCH_FORWARD,
R_SELF_INSERT,
R_NULL
R_NULL,
R_EOF
}
;

View File

@@ -17,7 +17,7 @@ inputrc information for key bindings.
*/
enum
{
R_BEGINNING_OF_LINE = R_NULL+1,
R_BEGINNING_OF_LINE = R_NULL+10, /* This give input_common ten slots for lowlevel keycodes */
R_END_OF_LINE,
R_FORWARD_CHAR,
R_BACKWARD_CHAR,

View File

@@ -64,7 +64,7 @@ static wint_t readb()
{
unsigned char arr[1];
int do_loop = 0;
do
{
fd_set fd;
@@ -93,17 +93,21 @@ static wint_t readb()
{
int res = interrupt_handler();
if( res )
{
return res;
}
}
do_loop = 1;
break;
}
default:
{
debug( 0, L"Error while reading input from keyboard, shutting down" );
wperror(L"read");
exit(1);
/*
The teminal has been closed. Save and exit.
*/
return R_EOF;
}
}
}
@@ -115,17 +119,17 @@ static wint_t readb()
{
debug( 3, L"Wake up on universal variable event" );
env_universal_read_all();
debug( 3, L"Return R_NULL" );
return R_NULL;
do_loop = 1;
}
}
if( FD_ISSET( 0, &fd ) )
{
if( read_blocked( 0, arr, 1 ) == -1 )
if( read_blocked( 0, arr, 1 ) != 1 )
{
debug( 0, L"Error while reading input from keyboard, shutting down" );
wperror(L"read");
exit(1);
/*
The teminal has been closed. Save and exit.
*/
return R_EOF;
}
do_loop = 0;
}
@@ -180,8 +184,8 @@ wchar_t input_common_readch( int timed )
int sz;
if( b == R_NULL )
return R_NULL;
if( (b == R_NULL) || (b == R_EOF) )
return b;
bb=b;

View File

@@ -20,7 +20,8 @@ enum
requested but none could be delivered, or when an exception
happened.
*/
R_NULL = INPUT_COMMON_RESERVED
R_NULL = INPUT_COMMON_RESERVED,
R_EOF
}
;

17
io.c
View File

@@ -213,37 +213,34 @@ io_data_t *io_get( io_data_t *io, int fd )
return 0;
}
/*
static void io_print( io_data_t *io )
void io_print( io_data_t *io )
{
if( !io )
{
fwprintf( stderr, L"\n" );
return;
}
fwprintf( stderr, L"IO fd %d, type ",
debug( 1, L"IO fd %d, type ",
io->fd );
switch( io->io_mode )
{
case IO_PIPE:
fwprintf(stderr, L"PIPE, data %d\n", io->pipe_fd[io->fd?1:0] );
debug( 1, L"PIPE, data %d", io->param1.pipe_fd[io->fd?1:0] );
break;
case IO_FD:
fwprintf(stderr, L"FD, copy %d\n", io->old_fd );
debug( 1, L"FD, copy %d", io->param1.old_fd );
break;
case IO_BUFFER:
fwprintf( stderr, L"BUFFER\n" );
debug( 1, L"BUFFER" );
break;
default:
fwprintf( stderr, L"OTHER\n" );
debug( 1, L"OTHER" );
}
io_print( io->next );
}
*/

2
io.h
View File

@@ -89,4 +89,6 @@ io_data_t *io_buffer_create();
*/
void io_buffer_read( io_data_t *d );
void io_print( io_data_t *io );
#endif

View File

@@ -5,6 +5,8 @@
Type ^C to exit the program.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

21
main.c
View File

@@ -63,6 +63,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "halloc_util.h"
#include "history.h"
/**
The string describing the single-character options accepted by the main fish binary
*/
#define GETOPT_STRING "hilnvc:p:d:"
/**
Parse init files
@@ -80,9 +84,9 @@ static int read_init()
env_set( L"__fish_help_dir", DOCDIR, 0);
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " SYSCONFDIR L" 2>/dev/null; . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd 2>/dev/null;. .fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " DATADIR L"/fish 2>/dev/null; and . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd " SYSCONFDIR L" 2>/dev/null; and . fish 2>/dev/null", 0, TOP );
eval( L"builtin cd 2>/dev/null; and . .fish 2>/dev/null", 0, TOP );
if( chdir( cwd ) == -1 )
{
@@ -165,14 +169,14 @@ int main( int argc, char **argv )
int opt = getopt_long( argc,
argv,
"hilnvc:p:d:",
GETOPT_STRING,
long_options,
&opt_index );
#else
int opt = getopt( argc,
argv,
"hilnvc:p:d:" );
GETOPT_STRING );
#endif
if( opt == -1 )
break;
@@ -259,7 +263,6 @@ int main( int argc, char **argv )
proc_init();
event_init();
exec_init();
wutil_init();
parser_init();
builtin_init();
@@ -276,7 +279,7 @@ int main( int argc, char **argv )
wchar_t *cmd_wcs = str2wcs( cmd );
res = eval( cmd_wcs, 0, TOP );
free(cmd_wcs);
reader_exit(0);
reader_exit(0, 0);
}
else
{
@@ -338,7 +341,7 @@ int main( int argc, char **argv )
}
proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, getpid(), res );
history_destroy();
complete_destroy();
proc_destroy();
@@ -348,12 +351,12 @@ int main( int argc, char **argv )
reader_destroy();
parser_destroy();
wutil_destroy();
exec_destroy();
event_destroy();
common_destroy();
halloc_util_destroy();
intern_free_all();
return res;
}

View File

@@ -944,7 +944,7 @@ int eval_args( const wchar_t *line, array_list_t *args )
int do_loop=1;
proc_push_interactive(0);
current_tokenizer = &tok;
current_tokenizer_pos = 0;
tok_init( &tok, line, 0 );
@@ -1173,9 +1173,9 @@ wchar_t *parser_current_line()
{
int lineno=1;
const wchar_t *file = parser_current_filename();
wchar_t *whole_str = tok_string( current_tokenizer );
wchar_t *line = whole_str;
const wchar_t *file;
wchar_t *whole_str;
wchar_t *line;
wchar_t *line_end;
int i;
int offset;
@@ -1183,6 +1183,14 @@ wchar_t *parser_current_line()
const wchar_t *function_name=0;
int current_line_start=0;
if( !current_tokenizer )
{
return L"";
}
file = parser_current_filename();
whole_str = tok_string( current_tokenizer );
line = whole_str;
if( !line )
return L"";
@@ -1870,6 +1878,7 @@ static int parse_job( process_t *p,
consumed=1;
is_new_block=1;
}
else if( wcscmp( L"if", nxt ) ==0 )
{
@@ -1929,7 +1938,7 @@ static int parse_job( process_t *p,
builtin_exists( (wchar_t *)al_get( args, 0 ) ) )
{
p->type = INTERNAL_BUILTIN;
is_new_block = parser_is_block( (wchar_t *)al_get( args, 0 ) );
is_new_block |= parser_is_block( (wchar_t *)al_get( args, 0 ) );
}
}
@@ -2067,6 +2076,7 @@ static int parse_job( process_t *p,
if( !make_sub_block )
{
tok_init( &subtok, end, 0 );
switch( tok_last_type( &subtok ) )
{
@@ -2092,17 +2102,18 @@ static int parse_job( process_t *p,
}
tok_destroy( &subtok );
}
if( make_sub_block )
{
int end_pos = end-tok_string( tok );
wchar_t *sub_block= wcsndup( tok_string( tok ) + current_tokenizer_pos,
end_pos - current_tokenizer_pos);
wchar_t *sub_block= halloc_wcsndup( j,
tok_string( tok ) + current_tokenizer_pos,
end_pos - current_tokenizer_pos);
p->type = INTERNAL_BLOCK;
al_set( args, 0, sub_block );
tok_set_pos( tok,
end_pos );

4
proc.c
View File

@@ -182,7 +182,7 @@ int proc_get_last_status()
job_t *job_create()
{
int free_id=0;
int free_id=1;
job_t *res;
while( job_get( free_id ) != 0 )
@@ -204,7 +204,7 @@ job_t *job_create()
job_t *job_get( int id )
{
job_t *res = first_job;
if( id == -1 )
if( id <= 0 )
{
return res;
}

5
proc.h
View File

@@ -261,7 +261,7 @@ job_t *job_create();
/**
Return the job with the specified job id.
If id is -1, return the last job used.
If id is 0 or less, return the last job used.
*/
job_t *job_get(int id);
@@ -328,7 +328,8 @@ 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().
Send a 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 );

View File

@@ -232,6 +232,11 @@ typedef struct reader_data
When this is true, the reader will exit
*/
int end_loop;
/**
If this is true, exit reader even if there are running
jobs. This happens if we press e.g. ^D twice.
*/
int prev_end_loop;
/**
Pointer to previous reader_data
@@ -299,6 +304,11 @@ static void reader_save_status();
static void reader_check_status();
static void reader_super_highlight_me_plenty( wchar_t * buff, int *color, int pos, array_list_t *error );
/**
Variable to keep track of forced exits - see \c reader_exit_forced();
*/
static int exit_forced;
/**
Give up control of terminal
@@ -370,6 +380,12 @@ static int room_for_usec(struct stat *st)
return res;
}
int reader_exit_forced()
{
return exit_forced;
}
/**
string_buffer used as temporary storage for the reader_readline function
*/
@@ -869,11 +885,14 @@ void reader_destroy()
}
void reader_exit( int do_exit )
void reader_exit( int do_exit, int forced )
{
if( data )
data->end_loop=do_exit;
end_loop=do_exit;
if( forced )
exit_forced = 1;
}
void repaint()
@@ -2230,7 +2249,6 @@ int exit_status()
*/
static int read_i()
{
int prev_end_loop=0;
reader_push(L"fish");
reader_set_complete_function( &complete );
@@ -2238,6 +2256,7 @@ static int read_i()
reader_set_test_function( &shell_test );
data->prompt_width=60;
data->prev_end_loop=0;
while( (!data->end_loop) && (!sanity_check()) )
{
@@ -2254,12 +2273,7 @@ static int read_i()
during evaluation.
*/
tmp = wcsdup( reader_readline() );
data->buff_pos=data->buff_len=0;
data->buff[data->buff_len]=L'\0';
reader_run_command( tmp );
free( tmp );
tmp = reader_readline();
if( data->end_loop)
{
@@ -2275,17 +2289,24 @@ static int read_i()
}
}
if( !prev_end_loop && has_job )
if( !reader_exit_forced() && !data->prev_end_loop && has_job )
{
writestr(_( L"There are stopped jobs\n" ));
write_prompt();
data->end_loop = 0;
prev_end_loop=1;
data->prev_end_loop=1;
}
}
else
{
prev_end_loop=0;
tmp = wcsdup( tmp );
data->buff_pos=data->buff_len=0;
data->buff[data->buff_len]=L'\0';
reader_run_command( tmp );
free( tmp );
data->prev_end_loop=0;
}
}
@@ -2442,6 +2463,14 @@ wchar_t *reader_readline()
break;
}
case R_EOF:
{
exit_forced = 1;
data->end_loop=1;
debug( 1, L"got R_EOF" );
break;
}
/* complete */
case R_COMPLETE:
{
@@ -2833,14 +2862,17 @@ wchar_t *reader_readline()
}
al_destroy( &comp );
if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
{
wperror(L"tcsetattr");
exit(1);
}
set_color( FISH_COLOR_RESET, FISH_COLOR_RESET );
if( !reader_exit_forced() )
{
if( tcsetattr(0,TCSANOW,&old_modes)) /* return to previous mode */
{
wperror(L"tcsetattr");
exit(1);
}
set_color( FISH_COLOR_RESET, FISH_COLOR_RESET );
}
return data->buff;
}

View File

@@ -21,7 +21,7 @@ int reader_read( int fd);
/**
Tell the shell that it should exit after the currently running command finishes.
*/
void reader_exit( int do_exit );
void reader_exit( int do_exit, int force );
/**
Check that the reader is in a sane state
@@ -162,5 +162,10 @@ void reader_replace_current_token( wchar_t *new_token );
*/
void reader_handle_int( int signal );
/**
This function returns true if fish is exiting by force, i.e. because stdin died
*/
int reader_exit_forced();
#endif

View File

@@ -2,7 +2,7 @@
function __fish_complete_apropos
if test (commandline -ct)
set str (commandline -ct)
apropos $str|sed -e "s/^\(.*$str\([^ ]*\).*\)$/$str\2"\t"\1/"
apropos $str|sed -e "s/^\(.*$str\([^ ]*\).*\)\$/$str\2"\t"\1/"
end
end

View File

@@ -4,6 +4,29 @@
# completions are located in the completions subdirectory.
#
#
# Assign a temporary value here for performance reasons. The real value should be set in /etc/fish.
#
set -g fish_function_path $PWD/functions/
#
# Make sure there are no invalid entries in the PATH
#
set -l erase_idx
for idx in (seq (count $PATH))
set i $PATH[$idx]
if not test -d $i
set erase_idx $erase_idx $idx
printf (_ '%s: Warning: The directory %s has been removed from your PATH, because it does not exist\n') fish $i
end
end
if count $erase_idx >/dev/null
set -e PATH[(echo $erase_idx)]
end
#
# Add a few common directories to path, if they exists. Note that pure
# console programs like makedep sometimes live in /usr/X11R6/bin, so we
@@ -17,20 +40,17 @@ if test "$USER" = root
set path_list $path_list /sbin /usr/sbin /usr/local/sbin
end
for i in $path_list
if not expr "$PATH" : "$i/*" >/dev/null
if test -d $i
set PATH $PATH $i
end
# Make a regular expressin that matches any component in the PATH. A
# trailing slash is ok. The sed call is to remove the last '\|'.
set -l path_regexp \\\((printf "^%s\\(\\|/\\)\$\\|" $PATH | sed -e "s/..\$//")\\\)
for i in (printf "%s\n" $path_list|grep -v $path_regexp)
if test -d $i
set PATH $PATH $i
end
end
#
# Assign a temporary value here for performance reasons. The real value should be set in /etc/fish.
#
set -g fish_function_path $PWD/functions/
#
# Don't need completions in non-interactive mode
#

View File

@@ -65,7 +65,7 @@ function __fish_complete_ls -d "Compleletions for ls and it's aliases"
complete $cmds -l quoting-style -x -a "literal locale shell shell-always c escape" -d (N_ "Select quoting style")
complete $cmds -l sort -x -d (N_ "Sort criteria") -a "
extension\t'Sort by file extension'
none\tDon't\ sort
none\tDon\'t\ sort
size\t'Sort by size'
time\t'Sort by modification time'
version\t'Sort by version'
@@ -106,4 +106,4 @@ function __fish_complete_ls -d "Compleletions for ls and it's aliases"
end
end
end

View File

@@ -2,6 +2,11 @@
# string has a newline before and after, so that fish will know how
# long it is.
# This event handler makes sure the prompt is repainted when fish_color_cwd changes value
function __fish_repaint --on-variable fish_color_cwd -d (N_ "Event handler, repaints the prompt when fish_color_cwd changes")
commandline -f null
end
function fish_prompt -d (N_ "Write out the prompt")
# Just calculate these once, to save a few cycles when displaying the prompt

112
signal.c
View File

@@ -55,143 +55,189 @@ static int block_count=0;
*/
static struct lookup_entry lookup[] =
{
#ifdef SIGHUP
{
SIGHUP,
L"SIGHUP",
N_( L"Terminal hung up" )
}
,
#endif
#ifdef SIGINT
{
SIGINT,
L"SIGINT",
N_( L"Quit request from job control (^C)" )
}
,
#endif
#ifdef SIGQUIT
{
SIGQUIT,
L"SIGQUIT",
N_( L"Quit request from job control with core dump (^\\)" )
}
,
#endif
#ifdef SIGILL
{
SIGILL,
L"SIGILL",
N_( L"Illegal instruction" )
}
,
#endif
#ifdef SIGTRAP
{
SIGTRAP,
L"SIGTRAP",
N_( L"Trace or breakpoint trap" )
}
,
#endif
#ifdef SIGABRT
{
SIGABRT,
L"SIGABRT",
N_( L"Abort" )
}
,
#endif
#ifdef SIGBUS
{
SIGBUS,
L"SIGBUS",
N_( L"Misaligned address error" )
}
,
#endif
#ifdef SIGFPE
{
SIGFPE,
L"SIGFPE",
N_( L"Floating point exception" )
}
,
#endif
#ifdef SIGKILL
{
SIGKILL,
L"SIGKILL",
N_( L"Forced quit" )
}
,
#endif
#ifdef SIGUSR1
{
SIGUSR1,
L"SIGUSR1",
N_( L"User defined signal 1" )
}
,
#endif
#ifdef SIGUSR2
{
SIGUSR2, L"SIGUSR2",
N_( L"User defined signal 2" )
}
,
#endif
#ifdef SIGSEGV
{
SIGSEGV,
L"SIGSEGV",
N_( L"Address boundary error" )
}
,
#endif
#ifdef SIGPIPE
{
SIGPIPE,
L"SIGPIPE",
N_( L"Broken pipe" )
}
,
#endif
#ifdef SIGALRM
{
SIGALRM,
L"SIGALRM",
N_( L"Timer expired" )
}
,
#endif
#ifdef SIGTERM
{
SIGTERM,
L"SIGTERM",
N_( L"Polite quit request" )
}
,
#endif
#ifdef SIGCHLD
{
SIGCHLD,
L"SIGCHLD",
N_( L"Child process status changed" )
}
,
#endif
#ifdef SIGCONT
{
SIGCONT,
L"SIGCONT",
N_( L"Continue previously stopped process" )
}
,
#endif
#ifdef SIGSTOP
{
SIGSTOP,
L"SIGSTOP",
N_( L"Forced stop" )
}
,
#endif
#ifdef SIGTSTP
{
SIGTSTP,
L"SIGTSTP",
N_( L"Stop request from job control (^Z)" )
}
,
#endif
#ifdef SIGTTIN
{
SIGTTIN,
L"SIGTTIN",
N_( L"Stop from terminal input" )
}
,
#endif
#ifdef SIGTTOU
{
SIGTTOU,
L"SIGTTOU",
N_( L"Stop from terminal output" )
}
,
#endif
#ifdef SIGURG
{
SIGURG,
L"SIGURG",
N_( L"Urgent socket condition" )
}
,
#endif
#ifdef SIGXCPY
{
SIGXCPU,
L"SIGXCPU",
N_( L"CPU time limit exceeded" )
}
,
#endif
#ifdef SIGXFSZ
{
SIGXFSZ,
@@ -200,12 +246,14 @@ static struct lookup_entry lookup[] =
}
,
#endif
#ifdef SIGVTALRM
{
SIGVTALRM,
L"SIGVTALRM",
N_( L"Virtual timer expired" )
}
,
#endif
#ifdef SIGPROF
{
SIGPROF,
@@ -230,12 +278,14 @@ static struct lookup_entry lookup[] =
}
,
#endif
#ifdef SIGWIO
{
SIGIO,
L"SIGIO",
N_( L"I/O on asynchronous file descriptor is possible" )
}
,
#endif
#ifdef SIGPWR
{
SIGPWR,
@@ -338,6 +388,7 @@ int wcs2sig( const wchar_t *str )
const wchar_t *sig2wcs( int sig )
{
int i;
for( i=0; lookup[i].desc ; i++ )
{
if( lookup[i].signal == sig )
@@ -345,12 +396,14 @@ const wchar_t *sig2wcs( int sig )
return lookup[i].name;
}
}
return L"Unknown";
return _(L"Unknown");
}
const wchar_t *signal_get_desc( int sig )
{
int i;
for( i=0; lookup[i].desc ; i++ )
{
if( lookup[i].signal == sig )
@@ -358,7 +411,8 @@ const wchar_t *signal_get_desc( int sig )
return _(lookup[i].desc);
}
}
return L"Unknown";
return _(L"Unknown");
}
/**
@@ -367,11 +421,16 @@ const wchar_t *signal_get_desc( int sig )
static void default_handler(int signal, siginfo_t *info, void *context)
{
event_t e;
e.type=EVENT_SIGNAL;
e.param1.signal = signal;
e.function_name=0;
event_fire( &e );
if( event_get( &e, 0 ) )
{
event_fire( &e );
}
}
/**
@@ -383,6 +442,28 @@ static void handle_winch( int sig, siginfo_t *info, void *context )
default_handler( sig, 0, 0 );
}
/**
Respond to a winch signal by checking the terminal size
*/
static void handle_hup( int sig, siginfo_t *info, void *context )
{
event_t e;
e.type=EVENT_SIGNAL;
e.param1.signal = SIGHUP;
e.function_name=0;
if( event_get( &e, 0 ) )
{
default_handler( sig, 0, 0 );
}
else
{
reader_exit( 1, 1 );
}
}
/**
Interactive mode ^C handler. Respond to int signal by setting
interrupted-flag and stopping all loops and conditionals.
@@ -431,7 +512,7 @@ void signal_set_handlers()
sigemptyset( & act.sa_mask );
act.sa_flags=SA_SIGINFO;
act.sa_sigaction = &default_handler;
/*
First reset everything to a use default_handler, a function
whose sole action is to fire of an event
@@ -479,7 +560,7 @@ void signal_set_handlers()
wperror( L"sigaction" );
exit(1);
}
act.sa_flags = SA_SIGINFO;
act.sa_sigaction= &handle_winch;
if( sigaction( SIGWINCH, &act, 0 ) )
@@ -488,6 +569,14 @@ void signal_set_handlers()
exit(1);
}
act.sa_flags = SA_SIGINFO;
act.sa_sigaction= &handle_hup;
if( sigaction( SIGHUP, &act, 0 ) )
{
wperror( L"sigaction" );
exit(1);
}
}
else
{
@@ -510,12 +599,13 @@ void signal_set_handlers()
exit(1);
}
}
}
void signal_handle( int sig, int do_handle )
{
struct sigaction act;
/*
These should always be handled
*/
@@ -527,15 +617,15 @@ void signal_handle( int sig, int do_handle )
(sig == SIGCHLD) )
return;
sigemptyset( & act.sa_mask );
sigemptyset( &act.sa_mask );
if( do_handle )
{
act.sa_flags=SA_SIGINFO;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &default_handler;
}
else
{
act.sa_flags=0;
act.sa_flags = 0;
act.sa_handler = SIG_DFL;
}
@@ -551,16 +641,20 @@ void signal_block()
sigfillset( &chldset );
sigprocmask(SIG_BLOCK, &chldset, 0);
}
block_count++;
}
void signal_unblock()
{
sigset_t chldset;
block_count--;
if( !block_count )
{
sigfillset( &chldset );
sigprocmask(SIG_UNBLOCK, &chldset, 0);
}
}

View File

@@ -611,7 +611,7 @@ void tok_next( tokenizer *tok )
wchar_t *tok_string( tokenizer *tok )
{
return tok->orig_buff;
return tok?tok->orig_buff:0;
}
wchar_t *tok_first( const wchar_t *str )

View File

@@ -2,6 +2,19 @@
<head>
<title>fish user documentation</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<!--
Override the default doxygen stylesheet to make the difference between different header levels larger
-->
<style type='text/css'>
H2
{
}
H3
{
padding-left:2%;
}
</style>
</head>
<body>

1
util.c
View File

@@ -809,6 +809,7 @@ int wcsfilecmp( const wchar_t *a, const wchar_t *b )
{
return 1;
}
int secondary_diff=0;
if( iswdigit( *a ) && iswdigit( *b ) )
{

30
wutil.c
View File

@@ -137,16 +137,28 @@ struct wdirent *wreaddir(DIR *dir )
wchar_t *wgetcwd( wchar_t *buff, size_t sz )
{
char buffc[sz*MAX_UTF8_BYTES];
char *res = getcwd( buffc, sz*MAX_UTF8_BYTES );
if( !res )
return 0;
if( (size_t)-1 == mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) )
char *buffc = malloc( sz*MAX_UTF8_BYTES);
char *res;
wchar_t *ret = 0;
if( !buffc )
{
return 0;
}
return buff;
errno = ENOMEM;
return 0;
}
res = getcwd( buffc, sz*MAX_UTF8_BYTES );
if( res )
{
if( (size_t)-1 != mbstowcs( buff, buffc, sizeof( wchar_t ) * sz ) )
{
ret = buff;
}
}
free( buffc );
return ret;
}
int wchdir( const wchar_t * dir )