#include "config.h" #include #include #include #include #include #include #include #include #include "fallback.h" #include "util.h" #include "common.h" #include "env.h" #include "wutil.h" #include "halloc.h" #include "halloc_util.h" #include "path.h" #include "expand.h" /** Unexpected error in path_get_path() */ #define MISSING_COMMAND_ERR_MSG _( L"Error while searching for command '%ls'" ) wchar_t *path_get_path( void *context, const wchar_t *cmd ) { wchar_t *path; CHECK( cmd, 0 ); debug( 3, L"path_get_path( '%ls' )", cmd ); if(wcschr( cmd, L'/' ) != 0 ) { if( waccess( cmd, X_OK )==0 ) { struct stat buff; wstat( cmd, &buff ); if( S_ISREG(buff.st_mode) ) return halloc_wcsdup( context, cmd ); else return 0; } } else { path = env_get(L"PATH"); if( path == 0 ) { if( CONTAINS( PREFIX L"/bin", L"/bin", L"/usr/bin" ) ) { path = L"/bin" ARRAY_SEP_STR L"/usr/bin"; } else { path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin"; } } /* Allocate string long enough to hold the whole command */ wchar_t *new_cmd = halloc( context, 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 ); } return 0; } wchar_t *path_get_cdpath( void *context, wchar_t *dir ) { wchar_t *res = 0; if( !dir ) return 0; if( dir[0] == L'/'|| (wcsncmp( dir, L"./", 2 )==0) ) { struct stat buf; if( wstat( dir, &buf ) == 0 ) { if( S_ISDIR(buf.st_mode) ) { res = halloc_wcsdup( context, dir ); } } } else { wchar_t *path; wchar_t *path_cpy; wchar_t *nxt_path; wchar_t *state; wchar_t *whole_path; path = env_get(L"CDPATH"); if( !path || !wcslen(path) ) { path = L"."; } nxt_path = path; path_cpy = wcsdup( path ); if( !path_cpy ) { DIE_MEM(); } for( nxt_path = wcstok( path_cpy, ARRAY_SEP_STR, &state ); nxt_path != 0; nxt_path = wcstok( 0, ARRAY_SEP_STR, &state) ) { wchar_t *expanded_path = expand_tilde( wcsdup(nxt_path) ); // debug( 2, L"woot %ls\n", expanded_path ); int path_len = wcslen( expanded_path ); if( path_len == 0 ) { free(expanded_path ); continue; } whole_path = wcsdupcat2( expanded_path, ( expanded_path[path_len-1] != L'/' )?L"/":L"", dir, (void *)0 ); free(expanded_path ); struct stat buf; if( wstat( whole_path, &buf ) == 0 ) { if( S_ISDIR(buf.st_mode) ) { res = whole_path; halloc_register( context, whole_path ); break; } } free( whole_path ); } free( path_cpy ); } return res; } wchar_t *path_get_config( void *context) { wchar_t *xdg_dir, *home; int done = 0; wchar_t *res = 0; xdg_dir = env_get( L"XDG_CONFIG_HOME" ); if( xdg_dir ) { res = wcsdupcat( xdg_dir, L"/fish" ); if( !create_directory( res ) ) { done = 1; } else { free( res ); } } else { home = env_get( L"HOME" ); if( home ) { res = wcsdupcat( home, L"/.config/fish" ); if( !create_directory( res ) ) { done = 1; } else { free( res ); } } } if( done ) { halloc_register_function( context, &free, res ); return res; } else { debug( 0, _(L"Unable to create a configuration directory for fish. Your personal settings will not be saved. Please set the $XDG_CONFIG_HOME variable to a directory where the current user has write access." )); return 0; } }