コード例 #1
0
ファイル: env.cpp プロジェクト: octaexon/fish-shell
static void export_func(const std::map<wcstring, wcstring> &envs, std::vector<std::string> &out)
{
	std::map<wcstring, wcstring>::const_iterator iter;
	for (iter = envs.begin(); iter != envs.end(); ++iter)
	{
		char* ks = wcs2str(iter->first.c_str());
		char* vs = wcs2str(iter->second.c_str()); 
		char *pos = vs;
		while( *pos )
		{
			if( *pos == ARRAY_SEP )
				*pos = ':';			
			pos++;
		}
        
        /* Put a string on the vector */
        out.push_back(std::string());
        std::string &str = out.back();
        
        /* Append our environment variable data to it */
        str.append(ks);
        str.append("=");
        str.append(vs);

		free(ks);
		free(vs);
	}
}
コード例 #2
0
ファイル: test.cpp プロジェクト: leok7v/uvc_mjpg_win10
static int mf_enumerate_cameras(int (*callback)(IMFSourceReader* reader)) {
    com_t<IMFAttributes> config;
    if_failed_return_result(MFCreateAttributes(&config, 1));
    if_failed_return_result(config->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
    UINT32 num = 0;
    IMFActivate** factory = null;  // [count]
    if_failed_return_result(MFEnumDeviceSources(config, &factory, &num));
    if (num == 0) {
        return 0;
    }
    for (int i = 0; i < (int)num; i++) {
        const char* sl = "";
        const char* fn= "";
        WCHAR* symbolic_link = null;
        WCHAR* friendly_name = null;
        UINT32 size = 0;
        if (OK(factory[i]->GetAllocatedString(MF_SL, &symbolic_link, &size))) { sl = wcs2str(symbolic_link); }
        if (OK(factory[i]->GetAllocatedString(MF_FN, &friendly_name, &size))) { fn = wcs2str(friendly_name); }
        com_t<IMFMediaSource> source;
        if_failed_return_result(factory[i]->ActivateObject(IID_PPV_ARGS(&source)));
        com_t<IMFSourceReader> reader;
        if_failed_return_result(MFCreateSourceReaderFromMediaSource(source, null, &reader));
        print("\nMMF camera %d %s %s\n", i, fn, sl);
        callback(reader);
        com_release(factory[i]);
    }
    CoTaskMemFree(factory);
    return S_OK;
} 
コード例 #3
0
ファイル: common.cpp プロジェクト: berdario/fish-shell
std::string wcs2string(const wcstring &input)
{
    char *tmp = wcs2str(input.c_str());
    std::string result = tmp;
    free(tmp);
    return result;
}
コード例 #4
0
ファイル: wutil.cpp プロジェクト: scorphus/fish-shell
wcstring wbasename(const wcstring &path) {
    char *tmp = wcs2str(path.c_str());
    char *narrow_res = basename(tmp);
    wcstring result = format_string(L"%s", narrow_res);
    free(tmp);
    return result;
}
コード例 #5
0
ファイル: textencoding.c プロジェクト: jogi1/camquake
char *encode_say (wchar *in)
{
	static char buf[1024];
	wchar *p;
	char *out;

	for (p = in; *p; p++)
		if (*p > 256)
			goto encode;
	strlcpy (buf, wcs2str(in), sizeof(buf));
	return buf;
encode:
	strlcpy (buf, "=`k8:", sizeof (buf));
	out = buf + strlen(buf);
	while (*in && (out - buf < sizeof(buf)/sizeof(buf[0])))
	{
		if (*in <= 255)
			*out++ = *in;
		else {
			*out++ = wc2koi(*in);
		}
		in++;
	}
	*out++ = '`';
	*out++ = '=';
	*out++ = 0;
	return buf;
}
コード例 #6
0
ファイル: env.cpp プロジェクト: octaexon/fish-shell
/**
   Set up default values for various variables if not defined.
 */
static void env_set_defaults()
{

	if( env_get_string(L"USER").missing() )
	{
		struct passwd *pw = getpwuid( getuid());
		wchar_t *unam = str2wcs( pw->pw_name );
		env_set( L"USER", unam, ENV_GLOBAL );
		free( unam );
	}

	if( env_get_string(L"HOME").missing() )
	{
		const env_var_t unam = env_get_string( L"USER" );
		char *unam_narrow = wcs2str( unam.c_str() );
		struct passwd *pw = getpwnam( unam_narrow );
		wchar_t *dir = str2wcs( pw->pw_dir );
		env_set( L"HOME", dir, ENV_GLOBAL );
		free( dir );		
		free( unam_narrow );
	}	

	env_set_pwd();
	
}
コード例 #7
0
ファイル: env.cpp プロジェクト: GarethLewin/fish-shell
/**
   Set up default values for various variables if not defined.
 */
static void env_set_defaults()
{

    if (env_get_string(L"USER").missing())
    {
        struct passwd *pw = getpwuid(getuid());
        if (pw->pw_name != NULL)
        {
            const wcstring wide_name = str2wcstring(pw->pw_name);
            env_set(L"USER", wide_name.c_str(), ENV_GLOBAL);
        }
    }

    if (env_get_string(L"HOME").missing())
    {
        const env_var_t unam = env_get_string(L"USER");
        char *unam_narrow = wcs2str(unam.c_str());
        struct passwd *pw = getpwnam(unam_narrow);
        if (pw->pw_dir != NULL)
        {
            const wcstring dir = str2wcstring(pw->pw_dir);
            env_set(L"HOME", dir.c_str(), ENV_GLOBAL);
        }
        free(unam_narrow);
    }

    env_set_pwd();

}
コード例 #8
0
ファイル: common.c プロジェクト: brentdax/fishfish
const wchar_t *wsetlocale(int category, const wchar_t *locale)
{

	char *lang = locale?wcs2str( locale ):0;
	char * res = setlocale(category,lang);

	free( lang );

	/*
	  Use ellipsis if on known unicode system, otherwise use $
	*/
	char *ctype = setlocale( LC_CTYPE, (void *)0 );
	ellipsis_char = (strstr( ctype, ".UTF")||strstr( ctype, ".utf") )?L'\u2026':L'$';

	if( !res )
		return 0;

	if( !setlocale_buff )
	{
		setlocale_buff = sb_halloc( global_context);
	}

	sb_clear( setlocale_buff );
	sb_printf( setlocale_buff, L"%s", res );

	return (wchar_t *)setlocale_buff->buff;
}
コード例 #9
0
ファイル: test.cpp プロジェクト: leok7v/uvc_mjpg_win10
static int ds_enumerate_cameras(int (*callback)(IBaseFilter* camera)) {
    com_t<ICreateDevEnum> enumerator;
    if_failed_return(CoCreateInstance(CLSID_SystemDeviceEnum, null, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)), -1);
    com_t<IEnumMoniker> class_enumerator;
    if_failed_return(enumerator->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &class_enumerator, 0), -1);
    int n = 0;
    while (class_enumerator != null) {
        com_t<IMoniker> moniker;
        ULONG fetched = 0;
        if (class_enumerator->Next(1, &moniker, &fetched) != S_OK || fetched != 1 || moniker == null) {
            break;
        }
        com_t<IPropertyBag> prop_bag;
        HRESULT hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&prop_bag));
        if (OK(hr)) {
            com_t<IBaseFilter> camera;
            if (OK(moniker->BindToObject(0, 0, IID_PPV_ARGS(&camera)))) {
                const char* dp = "";
                const char* fn = "";
                VARIANT friendly_name;
                VariantInit(&friendly_name);
                if (OK(prop_bag->Read(L"FriendlyName", &friendly_name, 0))) { fn = wcs2str(friendly_name.bstrVal); }
                VARIANT device_path;
                VariantInit(&device_path);
                if (OK(prop_bag->Read(L"DevicePath", &device_path, 0))) { dp = wcs2str(device_path.bstrVal); }
                VariantClear(&friendly_name);
                VariantClear(&device_path);
                print("\nDirectShow camera %d %s %s\n", n++, fn, dp);
                callback(camera);
            } else {
                print("%s hr=0x%08X\n", strwinerr(hr), hr);
            }
        } else {
            print("%s hr=0x%08X\n", strwinerr(hr), hr);
        }
    }
    return 0;
}
コード例 #10
0
ファイル: exec.cpp プロジェクト: moverest/fish-shell
/// This function is similar to launch_process, except it is not called after a fork (i.e. it only
/// calls exec) and therefore it can allocate memory.
static void launch_process_nofork(process_t *p) {
    ASSERT_IS_MAIN_THREAD();
    ASSERT_IS_NOT_FORKED_CHILD();

    null_terminated_array_t<char> argv_array;
    convert_wide_array_to_narrow(p->get_argv_array(), &argv_array);

    const char *const *envv = env_export_arr();
    char *actual_cmd = wcs2str(p->actual_cmd);

    // Ensure the terminal modes are what they were before we changed them.
    restore_term_mode();
    // Bounce to launch_process. This never returns.
    safe_launch_process(p, actual_cmd, argv_array.get(), envv);
}
コード例 #11
0
ファイル: test.cpp プロジェクト: leok7v/uvc_mjpg_win10
static IPin* ds_get_pin(IBaseFilter* filter, const char* pin_name) {
    com_t<IEnumPins> enum_pins;
    IPin* pin = null;		
    if_failed_return(filter->EnumPins(&enum_pins), null);
    while (enum_pins->Next(1, &pin, 0) == S_OK) {
        PIN_INFO pin_info = {0};
        pin->QueryPinInfo(&pin_info);
        com_release(pin_info.pFilter);
        if (stricmp(pin_name, wcs2str(pin_info.achName)) == 0) {
            return pin;
        }
        com_release(pin);
    }
    return null;
}
コード例 #12
0
bool env_universal_t::open_temporary_file(const wcstring &directory, wcstring *out_path, int *out_fd)
{
    /* Create and open a temporary file for writing within the given directory */
    /* Try to create a temporary file, up to 10 times. We don't use mkstemps because we want to open it CLO_EXEC. This should almost always succeed on the first try. */
    assert(! string_suffixes_string(L"/", directory));
    
    bool success = false;
    const wcstring tmp_name_template = directory + L"/fishd.tmp.XXXXXX";
    wcstring tmp_name;
    for (size_t attempt = 0; attempt < 10 && ! success; attempt++)
    {
        int result_fd = -1;
        char *narrow_str = wcs2str(tmp_name_template.c_str());
#if HAVE_MKOSTEMP
        result_fd = mkostemp(narrow_str, O_CLOEXEC);
        if (result_fd >= 0)
        {
            tmp_name = str2wcstring(narrow_str);
        }
#else
        if (mktemp(narrow_str))
        {
            /* It was successfully templated; try opening it atomically */
            tmp_name = str2wcstring(narrow_str);
            result_fd = wopen_cloexec(tmp_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0644);
        }
#endif
        
        if (result_fd >= 0)
        {
            /* Success */
            *out_fd = result_fd;
            *out_path = str2wcstring(narrow_str);
            success = true;
        }
        free(narrow_str);
    }
    if (! success)
    {
        int err = errno;
        report_error(err, L"Unable to open file '%ls'", tmp_name.c_str());
    }
    return success;
}
コード例 #13
0
ファイル: fishd.cpp プロジェクト: Soares/fish-shell
/**
   Get environment variable value. The resulting string needs to be free'd.
*/
static wchar_t *fishd_env_get( const wchar_t *key )
{
	char *nres, *nkey;
	wchar_t *res;
	
	nkey = wcs2str( key );
	nres = getenv( nkey );
	free( nkey );
	if( nres )
	{
		return str2wcs( nres );
	}
	else
	{
		res = env_universal_common_get( key );
		if( res )
			res = wcsdup( res );		
		return res;
	}
}
コード例 #14
0
ファイル: common.cpp プロジェクト: berdario/fish-shell
wcstring wsetlocale(int category, const wchar_t *locale)
{

	char *lang = NULL;
	if (locale){
		lang = wcs2str( locale );
	}
	char * res = setlocale(category,lang);
	free( lang );

	/*
	  Use ellipsis if on known unicode system, otherwise use $
	*/
	char *ctype = setlocale( LC_CTYPE, NULL );
	ellipsis_char = (strstr( ctype, ".UTF")||strstr( ctype, ".utf") )?L'\x2026':L'$';	
		
	if( !res )
		return wcstring();
    else
		return format_string(L"%s", res);
}
コード例 #15
0
ファイル: wildcard.cpp プロジェクト: anbotero/fish-shell
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards. 
 */
static int wildcard_expand_internal( const wchar_t *wc,
									 const wchar_t *base_dir,
									 expand_flags_t flags,
									 std::vector<completion_t> &out,
                                     std::set<wcstring> &completion_set,
                                     std::set<file_id_t> &visited_files
                                   )
{

	/* Points to the end of the current wildcard segment */
	const wchar_t *wc_end;

	/* Variables for traversing a directory */
	DIR *dir;
	
	/* The result returned */
	int res = 0;
	
	/* Length of the directory to search in */
	size_t base_len;

	/* Variables for testing for presense of recursive wildcards */
	const wchar_t *wc_recursive;
	int is_recursive;

	/* Slightly mangled version of base_dir */
	const wchar_t *dir_string;
	
	//	debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

	if( reader_interrupted() )
	{
		return -1;
	}
	
	if( !wc || !base_dir )
	{
		debug( 2, L"Got null string on line %d of file %s", __LINE__, __FILE__ );
		return 0;		
	}

	if( flags & ACCEPT_INCOMPLETE )
	{	
		/* 
		   Avoid excessive number of returned matches for wc ending with a * 
		*/
		size_t len = wcslen(wc);
		if( len && (wc[len-1]==ANY_STRING) )
		{
			wchar_t * foo = wcsdup( wc );
			foo[len-1]=0;
			int res = wildcard_expand_internal( foo, base_dir, flags, out, completion_set, visited_files );
			free( foo );
			return res;			
		}
	}

	/*
	  Initialize various variables
	*/

	dir_string = base_dir[0]==L'\0'?L".":base_dir;
	
	if( !(dir = wopendir( dir_string )))
	{
		return 0;
	}

	wc_end = wcschr(wc,L'/');
	base_len = wcslen( base_dir );

	/*
	  Test for recursive match string in current segment
	*/	
	wc_recursive = wcschr( wc, ANY_STRING_RECURSIVE );
	is_recursive = ( wc_recursive && (!wc_end || wc_recursive < wc_end));

	/*
	  Is this segment of the wildcard the last?
	*/
	if( !wc_end )
	{
		/*
		  Wildcard segment is the last segment,

		  Insert all matching files/directories
		*/
		if( wc[0]=='\0' )
		{
			/*
			  The last wildcard segment is empty. Insert everything if
			  completing, the directory itself otherwise.
			*/
			if( flags & ACCEPT_INCOMPLETE )
			{
                wcstring next;
				while(wreaddir(dir, next))
				{
					if( next[0] != L'.' )
					{
						wcstring long_name = make_path( base_dir, next );
						
						if( test_flags( long_name.c_str(), flags ) )
						{
							wildcard_completion_allocate( out,
														  long_name,
														  next,
														  L"",
                                                          flags);
						}
					}					
				}
			}
			else
			{
				res = 1;
                insert_completion_if_missing(base_dir, out, completion_set);
			}
		}
		else
		{
			/*
			  This is the last wildcard segment, and it is not empty. Match files/directories.
			*/
            wcstring next;
			while (wreaddir(dir, next))
			{
                const wchar_t * const name = next.c_str();
				if( flags & ACCEPT_INCOMPLETE )
				{
					
					const wcstring long_name = make_path( base_dir, next );

					/*
					  Test for matches before stating file, so as to minimize the number of calls to the much slower stat function 
					*/
					std::vector<completion_t> test;
					if( wildcard_complete( name,
										   wc,
										   L"",
										   0,
										   test,
										   0 ) )
					{
						if( test_flags( long_name.c_str(), flags ) )
						{
							wildcard_completion_allocate( out,
														  long_name,
                                                          name,
														  wc,
                                                          flags);
							
						}
					}					
				}
				else
				{
					if( wildcard_match2( name, wc, 1 ) )
					{
                        const wcstring long_name = make_path(base_dir, next);
						int skip = 0;
						
						if( is_recursive )
						{
							/*
							  In recursive mode, we are only
							  interested in adding files -directories
							  will be added in the next pass.
							*/
							struct stat buf;
							if( !wstat( long_name, &buf ) )
							{
								skip = S_ISDIR(buf.st_mode);
							}							
						}
						if (! skip)
						{
                            insert_completion_if_missing(long_name, out, completion_set);
						}
						res = 1;
					}
				}
			}
		}
	}

	if( wc_end || is_recursive )
	{
		/*
		  Wilcard segment is not the last segment.  Recursively call
		  wildcard_expand for all matching subdirectories.
		*/
		
		/*
		  wc_str is the part of the wildcarded string from the
		  beginning to the first slash
		*/
		wchar_t *wc_str;

		/*
		  new_dir is a scratch area containing the full path to a
		  file/directory we are iterating over
		*/
		wchar_t *new_dir;

		/*
		  The maximum length of a file element
		*/
		long ln=MAX_FILE_LENGTH;
		char * narrow_dir_string = wcs2str( dir_string );

		/*
		  In recursive mode, we look through the directory twice. If
		  so, this rewind is needed.
		*/
		rewinddir( dir );

		if( narrow_dir_string )
		{
			/* 
			   Find out how long the filename can be in a worst case
			   scenario
			*/
			ln = pathconf( narrow_dir_string, _PC_NAME_MAX ); 

			/*
			  If not specified, use som large number as fallback
			*/
			if( ln < 0 )
				ln = MAX_FILE_LENGTH;		
			free( narrow_dir_string );
		}
		new_dir= (wchar_t *)malloc( sizeof(wchar_t)*(base_len+ln+2)  );

		wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc);

		if( (!new_dir) || (!wc_str) )
		{
			DIE_MEM();
		}

		wcscpy( new_dir, base_dir );
		
        wcstring next;
		while (wreaddir(dir, next))
		{
			const wchar_t *name = next.c_str();
			
			/*
			  Test if the file/directory name matches the whole
			  wildcard element, i.e. regular matching.
			*/
			int whole_match = wildcard_match2( name, wc_str, 1 );
			int partial_match = 0;
			
			/* 
			   If we are doing recursive matching, also check if this
			   directory matches the part up to the recusrive
			   wildcard, if so, then we can search all subdirectories
			   for matches.
			*/
			if( is_recursive )
			{
				const wchar_t *end = wcschr( wc, ANY_STRING_RECURSIVE );
				wchar_t *wc_sub = wcsndup( wc, end-wc+1);
				partial_match = wildcard_match2( name, wc_sub, 1 );
				free( wc_sub );
			}			

			if( whole_match || partial_match )
			{
				struct stat buf;			
				char *dir_str;
				int stat_res;
				int new_res;

				wcscpy(&new_dir[base_len], name );
				dir_str = wcs2str( new_dir );
				
				if( dir_str )
				{
					stat_res = stat( dir_str, &buf );
					free( dir_str );
					
					if( !stat_res )
					{
                        // Insert a "file ID" into visited_files
                        // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                        const file_id_t file_id(buf.st_dev, buf.st_ino);
						if( S_ISDIR(buf.st_mode) && visited_files.insert(file_id).second)
						{
							size_t new_len = wcslen( new_dir );
							new_dir[new_len] = L'/';
							new_dir[new_len+1] = L'\0';
							
							/*
							  Regular matching
							*/
							if( whole_match )
							{
								const wchar_t *new_wc = L"";
								if( wc_end )
								{
									new_wc=wc_end+1;
									/*
									  Accept multiple '/' as a single direcotry separator
									*/
									while(*new_wc==L'/')
									{
										new_wc++;
									}
								}
								
								new_res = wildcard_expand_internal( new_wc,
																	new_dir, 
																	flags, 
																	out,
                                                                    completion_set,
                                                                    visited_files );

								if( new_res == -1 )
								{
									res = -1;
									break;
								}								
								res |= new_res;
								
							}
							
							/*
							  Recursive matching
							*/
							if( partial_match )
							{
								
								new_res = wildcard_expand_internal( wcschr( wc, ANY_STRING_RECURSIVE ), 
																	new_dir,
																	flags | WILDCARD_RECURSIVE, 
																	out,
                                                                    completion_set,
                                                                    visited_files);

								if( new_res == -1 )
								{
									res = -1;
									break;
								}								
								res |= new_res;
								
							}
						}								
					}
				}
			}
		}
		
		free( wc_str );
		free( new_dir );
	}
	closedir( dir );

	return res;
}
コード例 #16
0
ファイル: env.cpp プロジェクト: lnsoso/fish-shell
void env_init(const struct config_paths_t *paths /* or NULL */)
{
    /*
      env_read_only variables can not be altered directly by the user
    */

    const wchar_t * const ro_keys[] =
    {
        L"status",
        L"history",
        L"version",
        L"_",
        L"LINES",
        L"COLUMNS",
        L"PWD",
        //L"SHLVL", // will be inserted a bit lower down
        L"FISH_VERSION",
    };
    for (size_t i=0; i < sizeof ro_keys / sizeof *ro_keys; i++)
    {
        env_read_only.insert(ro_keys[i]);
    }

    /*
       Names of all dynamically calculated variables
       */
    env_electric.insert(L"history");
    env_electric.insert(L"status");
    env_electric.insert(L"umask");
    env_electric.insert(L"COLUMNS");
    env_electric.insert(L"LINES");

    top = new env_node_t;
    global_env = top;
    global = &top->env;

    /*
      Now the environemnt variable handling is set up, the next step
      is to insert valid data
    */

    /*
      Import environment variables
    */
    for (char **p = (environ ? environ : __environ); p && *p; p++)
    {
        const wcstring key_and_val = str2wcstring(*p); //like foo=bar
        size_t eql = key_and_val.find(L'=');
        if (eql == wcstring::npos)
        {
            // no equals found
            if (is_read_only(key_and_val) || is_electric(key_and_val)) continue;
            env_set(key_and_val, L"", ENV_EXPORT | ENV_GLOBAL);
        }
        else
        {
            wcstring key = key_and_val.substr(0, eql);
            if (is_read_only(key) || is_electric(key)) continue;
            wcstring val = key_and_val.substr(eql + 1);
            if (variable_is_colon_delimited_array(key))
            {
                std::replace(val.begin(), val.end(), L':', ARRAY_SEP);
            }

            env_set(key, val.c_str(), ENV_EXPORT | ENV_GLOBAL);
        }
    }

    /* Set the given paths in the environment, if we have any */
    if (paths != NULL)
    {
        env_set(FISH_DATADIR_VAR, paths->data.c_str(), ENV_GLOBAL);
        env_set(FISH_SYSCONFDIR_VAR, paths->sysconf.c_str(), ENV_GLOBAL);
        env_set(FISH_HELPDIR_VAR, paths->doc.c_str(), ENV_GLOBAL);
        env_set(FISH_BIN_DIR, paths->bin.c_str(), ENV_GLOBAL);
    }

    /*
      Set up the PATH variable
    */
    setup_path();

    /*
      Set up the USER variable
    */
    if (env_get_string(L"USER").missing_or_empty())
    {
        const struct passwd *pw = getpwuid(getuid());
        if (pw && pw->pw_name)
        {
            const wcstring uname = str2wcstring(pw->pw_name);
            env_set(L"USER", uname.c_str(), ENV_GLOBAL | ENV_EXPORT);
        }
    }

    /*
      Set up the version variables
    */
    wcstring version = str2wcstring(get_fish_version());
    env_set(L"version", version.c_str(), ENV_GLOBAL);
    env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL);

    /*
      Set up SHLVL variable
    */
    const env_var_t shlvl_str = env_get_string(L"SHLVL");
    wcstring nshlvl_str = L"1";
    if (! shlvl_str.missing())
    {
        wchar_t *end;
        long shlvl_i = wcstol(shlvl_str.c_str(), &end, 10);
        while (iswspace(*end)) ++end; /* skip trailing whitespace */
        if (shlvl_i >= 0 && *end == '\0')
        {
            nshlvl_str = to_string<long>(shlvl_i + 1);
        }
    }
    env_set(L"SHLVL", nshlvl_str.c_str(), ENV_GLOBAL | ENV_EXPORT);
    env_read_only.insert(L"SHLVL");

    /* Set up the HOME variable */
    if (env_get_string(L"HOME").missing_or_empty())
    {
        const env_var_t unam = env_get_string(L"USER");
        char *unam_narrow = wcs2str(unam.c_str());
        struct passwd *pw = getpwnam(unam_narrow);
        if (pw->pw_dir != NULL)
        {
            const wcstring dir = str2wcstring(pw->pw_dir);
            env_set(L"HOME", dir.c_str(), ENV_GLOBAL | ENV_EXPORT);
        }
        free(unam_narrow);
    }

    /* Set PWD */
    env_set_pwd();

    /* Set up universal variables. The empty string means to use the deafult path. */
    assert(s_universal_variables == NULL);
    s_universal_variables = new env_universal_t(L"");
    s_universal_variables->load();

    /* Set g_log_forks */
    env_var_t log_forks = env_get_string(L"fish_log_forks");
    g_log_forks = ! log_forks.missing_or_empty() && from_string<bool>(log_forks);

    /* Set g_use_posix_spawn. Default to true. */
    env_var_t use_posix_spawn = env_get_string(L"fish_use_posix_spawn");
    g_use_posix_spawn = (use_posix_spawn.missing_or_empty() ? true : from_string<bool>(use_posix_spawn));

    /* Set fish_bind_mode to "default" */
    env_set(FISH_BIND_MODE_VAR, DEFAULT_BIND_MODE, ENV_GLOBAL);

    /*
      Now that the global scope is fully initialized, add a toplevel local
      scope. This same local scope will persist throughout the lifetime of the
      fish process, and it will ensure that `set -l` commands run at the
      command-line don't affect the global scope.
    */
    env_push(false);
}
コード例 #17
0
/**
   Get a socket for reading from the server
*/
static int get_socket( int fork_ok )
{
	int s, len;
	struct sockaddr_un local;
	
	char *name;
	wchar_t *wdir;
	wchar_t *wuname;	
	char *dir =0, *uname=0;

	get_socket_count++;
	wdir = path;
	wuname = user;
	
	if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 
	{
		wperror(L"socket");
		return -1;
	}
	
	if( wdir )
		dir = wcs2str(wdir );
	else
		dir = strdup("/tmp");
	
	if( wuname )
		uname = wcs2str(wuname );
	else
	{
		struct passwd *pw;
		pw = getpwuid( getuid() );
		uname = strdup( pw->pw_name );
	}
	
	name = (char *)malloc( strlen(dir) +
				   strlen(uname) + 
				   strlen(SOCK_FILENAME) + 
				   2 );
	
	strcpy( name, dir );
	strcat( name, "/" );
	strcat( name, SOCK_FILENAME );
	strcat( name, uname );
	
	free( dir );
	free( uname );
	
	debug( 3, L"Connect to socket %s at fd %2", name, s );
	
	local.sun_family = AF_UNIX;
	strcpy(local.sun_path, name );
	free( name );
	len = sizeof(local);
	
	if( connect( s, (struct sockaddr *)&local, len) == -1 ) 
	{
		close( s );
		if( fork_ok && start_fishd )
		{
			debug( 2, L"Could not connect to socket %d, starting fishd", s );
			
			start_fishd();
									
			return get_socket( 0 );
		}
		
		debug( 1, L"Could not connect to universal variable server, already tried manual restart (or no command supplied). You will not be able to share variable values between fish sessions. Is fish properly installed?" );
		return -1;
	}
	
	if( (fcntl( s, F_SETFL, O_NONBLOCK ) != 0) || (fcntl( s, F_SETFD, FD_CLOEXEC ) != 0) ) 
	{
		wperror( L"fcntl" );
		close( s );		
		
		return -1;
	}

	debug( 3, L"Connected to fd %d", s );
	
	return s;
}
コード例 #18
0
ファイル: tp_triggers.c プロジェクト: jogi1/camquake
//Find and execute sound triggers. A sound trigger must be terminated by either a CR or LF.
//Returns true if a sound was found and played
qbool TP_CheckSoundTrigger (wchar *wstr)
{
	char *str;
	int i, j, start, length;
	char soundname[MAX_OSPATH];
#ifndef WITH_FTE_VFS
	FILE *f;
#else
	vfsfile_t *v;
#endif

	str = wcs2str (wstr);
 
	if (!*str)
		return false;
 
	if (!tp_soundtrigger.string[0])
		return false;
 
	for (i = strlen (str) - 1; i; i--)	{
		if (str[i] != 0x0A && str[i] != 0x0D)
			continue;
 
		for (j = i - 1; j >= 0; j--) {
			// quick check for chars that cannot be used
			// as sound triggers but might be part of a file name
			if (isalnum((unsigned char)str[j]))
				continue;	// file name or chat
 
			if (strchr(tp_soundtrigger.string, str[j]))	{
				// this might be a sound trigger
 
				start = j + 1;
				length = i - start;
 
				if (!length)
					break;
				if (length >= MAX_QPATH)
					break;
 
				strlcpy (soundname, str + start, length + 1);
				if (strstr(soundname, ".."))
					break;	// no thank you
 
				// clean up the message
				strcpy (str + j, str + i);
				qwcscpy (wstr + j, wstr + i);
 
				if (!snd_initialized)
					return false;
 
				COM_DefaultExtension (soundname, ".wav");
 
				// make sure we have it on disk (FIXME)
#ifndef WITH_FTE_VFS
				FS_FOpenFile (va("sound/%s", soundname), &f);
				if (!f)
					return false;
				fclose (f);
#else
				if (!(v = FS_OpenVFS(va("sound/%s", soundname), "rb", FS_ANY))) 
					return false;
				VFS_CLOSE(v);
#endif
 
				// now play the sound
				S_LocalSound (soundname);
				return true;
			}
			if (str[j] == '\\')
				str[j] = '/';
			if (str[j] <= ' ' || strchr("\"&'*,:;<>?\\|\x7f", str[j]))
				break;	// we don't allow these in a file name
		}
	}
 
	return false;
}
コード例 #19
0
ファイル: exec.c プロジェクト: CodeMonk/fish
void exec( job_t *j )
{
	process_t *p;
	pid_t pid;
	int mypipe[2];
	sigset_t chldset; 
	int skip_fork;
	
	io_data_t pipe_read, pipe_write;
	io_data_t *tmp;

	io_data_t *io_buffer =0;

	/*
	  Set to 1 if something goes wrong while exec:ing the job, in
	  which case the cleanup code will kick in.
	*/
	int exec_error=0;

	int needs_keepalive = 0;
	process_t keepalive;
	

	CHECK( j, );
	CHECK_BLOCK();
	
	if( no_exec )
		return;
	
	sigemptyset( &chldset );
	sigaddset( &chldset, SIGCHLD );
	
	debug( 4, L"Exec job '%ls' with id %d", j->command, j->job_id );	
	
	if( block_io )
	{
		if( j->io )
		{
			j->io = io_add( io_duplicate( j, block_io), j->io );
		}
		else
		{
			j->io=io_duplicate( j, block_io);				
		}
	}

	
	io_data_t *input_redirect;

	for( input_redirect = j->io; input_redirect; input_redirect = input_redirect->next )
	{
		if( (input_redirect->io_mode == IO_BUFFER) && 
			input_redirect->is_input )
		{
			/*
			  Input redirection - create a new gobetween process to take
			  care of buffering
			*/
			process_t *fake = halloc( j, sizeof(process_t) );
			fake->type = INTERNAL_BUFFER;
			fake->pipe_write_fd = 1;
			j->first_process->pipe_read_fd = input_redirect->fd;
			fake->next = j->first_process;
			j->first_process = fake;
			break;
		}
	}
	
	if( j->first_process->type==INTERNAL_EXEC )
	{
		/*
		  Do a regular launch -  but without forking first...
		*/
		signal_block();

		/*
		  setup_child_process makes sure signals are properly set
		  up. It will also call signal_unblock
		*/
		if( !setup_child_process( j, 0 ) )
		{
			/*
			  launch_process _never_ returns
			*/
			launch_process( j->first_process );
		}
		else
		{
			job_set_flag( j, JOB_CONSTRUCTED, 1 );
			j->first_process->completed=1;
			return;
		}

	}	

	pipe_read.fd=0;
	pipe_write.fd=1;
	pipe_read.io_mode=IO_PIPE;
	pipe_read.param1.pipe_fd[0] = -1;
	pipe_read.param1.pipe_fd[1] = -1;
	pipe_read.is_input = 1;

	pipe_write.io_mode=IO_PIPE;
	pipe_write.is_input = 0;
	pipe_read.next=0;
	pipe_write.next=0;
	pipe_write.param1.pipe_fd[0]=pipe_write.param1.pipe_fd[1]=-1;
	
	j->io = io_add( j->io, &pipe_write );
	
	signal_block();

	/*
	  See if we need to create a group keepalive process. This is
	  a process that we create to make sure that the process group
	  doesn't die accidentally, and is often needed when a
	  builtin/block/function is inside a pipeline, since that
	  usually means we have to wait for one program to exit before
	  continuing in the pipeline, causing the group leader to
	  exit.
	*/
	
	if( job_get_flag( j, JOB_CONTROL ) )
	{
		for( p=j->first_process; p; p = p->next )
		{
			if( p->type != EXTERNAL )
			{
				if( p->next )
				{
					needs_keepalive = 1;
					break;
				}
				if( p != j->first_process )
				{
					needs_keepalive = 1;
					break;
				}
				
			}
			
		}
	}
		
	if( needs_keepalive )
	{
		keepalive.pid = exec_fork();

		if( keepalive.pid == 0 )
		{
			keepalive.pid = getpid();
			set_child_group( j, &keepalive, 1 );
			pause();			
			exit(0);
		}
		else
		{
			set_child_group( j, &keepalive, 0 );			
		}
	}
	
	/*
	  This loop loops over every process_t in the job, starting it as
	  appropriate. This turns out to be rather complex, since a
	  process_t can be one of many rather different things.

	  The loop also has to handle pipelining between the jobs.
	*/

	for( p=j->first_process; p; p = p->next )
	{
		mypipe[1]=-1;
		skip_fork=0;
		
		pipe_write.fd = p->pipe_write_fd;
		pipe_read.fd = p->pipe_read_fd;
//		debug( 0, L"Pipe created from fd %d to fd %d", pipe_write.fd, pipe_read.fd );
		

		/* 
		   This call is used so the global environment variable array
		   is regenerated, if needed, before the fork. That way, we
		   avoid a lot of duplicate work where EVERY child would need
		   to generate it, since that result would not get written
		   back to the parent. This call could be safely removed, but
		   it would result in slightly lower performance - at least on
		   uniprocessor systems.
		*/
		if( p->type == EXTERNAL )
			env_export_arr( 1 );
		
		
		/*
		  Set up fd:s that will be used in the pipe 
		*/
		
		if( p == j->first_process->next )
		{
			j->io = io_add( j->io, &pipe_read );
		}
		
		if( p->next )
		{
//			debug( 1, L"%ls|%ls" , p->argv[0], p->next->argv[0]);
			
			if( exec_pipe( mypipe ) == -1 )
			{
				debug( 1, PIPE_ERROR );
				wperror (L"pipe");
				exec_error=1;
				break;
			}

			memcpy( pipe_write.param1.pipe_fd, mypipe, sizeof(int)*2);
		}
		else
		{
			/*
			  This is the last element of the pipeline.
			  Remove the io redirection for pipe output.
			*/
			j->io = io_remove( j->io, &pipe_write );
			
		}

		switch( p->type )
		{
			case INTERNAL_FUNCTION:
			{
				const wchar_t * orig_def;
				wchar_t * def=0;
				array_list_t *named_arguments;
				int shadows;
				

				/*
				  Calls to function_get_definition might need to
				  source a file as a part of autoloading, hence there
				  must be no blocks.
				*/

				signal_unblock();
				orig_def = function_get_definition( p->argv[0] );
				named_arguments = function_get_named_arguments( p->argv[0] );
				shadows = function_get_shadows( p->argv[0] );

				signal_block();
				
				if( orig_def )
				{
					def = halloc_register( j, wcsdup(orig_def) );
				}
				if( def == 0 )
				{
					debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] );
					break;
				}

				parser_push_block( shadows?FUNCTION_CALL:FUNCTION_CALL_NO_SHADOW );
				
				current_block->param2.function_call_process = p;
				current_block->param1.function_call_name = halloc_register( current_block, wcsdup( p->argv[0] ) );
						

				/*
				  set_argv might trigger an event
				  handler, hence we need to unblock
				  signals.
				*/
				signal_unblock();
				parse_util_set_argv( p->argv+1, named_arguments );
				signal_block();
								
				parser_forbid_function( p->argv[0] );

				if( p->next )
				{
					io_buffer = io_buffer_create( 0 );					
					j->io = io_add( j->io, io_buffer );
				}
				
				internal_exec_helper( def, TOP, j->io );
				
				parser_allow_function();
				parser_pop_block();
				
				break;				
			}
			
			case INTERNAL_BLOCK:
			{
				if( p->next )
				{
					io_buffer = io_buffer_create( 0 );					
					j->io = io_add( j->io, io_buffer );
				}
								
				internal_exec_helper( p->argv[0], TOP, j->io );			
				break;
				
			}

			case INTERNAL_BUILTIN:
			{
				int builtin_stdin=0;
				int fg;
				int close_stdin=0;

				/*
				  If this is the first process, check the io
				  redirections and see where we should be reading
				  from.
				*/
				if( p == j->first_process )
				{
					io_data_t *in = io_get( j->io, 0 );
					
					if( in )
					{
						switch( in->io_mode )
						{
							
							case IO_FD:
							{
								builtin_stdin = in->param1.old_fd;
								break;
							}
							case IO_PIPE:
							{
								builtin_stdin = in->param1.pipe_fd[0];
								break;
							}
							
							case IO_FILE:
							{
								builtin_stdin=wopen( in->param1.filename,
                                              in->param2.flags, OPEN_MASK );
								if( builtin_stdin == -1 )
								{
									debug( 1, 
										   FILE_ERROR,
										   in->param1.filename );
									wperror( L"open" );
								}
								else
								{
									close_stdin = 1;
								}
								
								break;
							}
	
							case IO_CLOSE:
							{
								/*
								  FIXME:

								  When
								  requesting
								  that
								  stdin
								  be
								  closed,
								  we
								  really
								  don't
								  do
								  anything. How
								  should
								  this
								  be
								  handled?
								 */
								builtin_stdin = -1;
								
								break;
							}
							
							default:
							{
								builtin_stdin=-1;
								debug( 1, 
									   _( L"Unknown input redirection type %d" ),
									   in->io_mode);
								break;
							}
						
						}
					}
				}
				else
				{
					builtin_stdin = pipe_read.param1.pipe_fd[0];
				}

				if( builtin_stdin == -1 )
				{
					exec_error=1;
					break;
				}
				else
				{
					int old_out = builtin_out_redirect;
					int old_err = builtin_err_redirect;

					/* 
					   Since this may be the foreground job, and since
					   a builtin may execute another foreground job,
					   we need to pretend to suspend this job while
					   running the builtin, in order to avoid a
					   situation where two jobs are running at once.

					   The reason this is done here, and not by the
					   relevant builtins, is that this way, the
					   builtin does not need to know what job it is
					   part of. It could probably figure that out by
					   walking the job list, but it seems more robust
					   to make exec handle things.
					*/
					
					builtin_push_io( builtin_stdin );
					
					builtin_out_redirect = has_fd( j->io, 1 );
					builtin_err_redirect = has_fd( j->io, 2 );		

					fg = job_get_flag( j, JOB_FOREGROUND );
					job_set_flag( j, JOB_FOREGROUND, 0 );
					
					signal_unblock();
					
					p->status = builtin_run( p->argv, j->io );
					
					builtin_out_redirect=old_out;
					builtin_err_redirect=old_err;
					
					signal_block();
					
					/*
					  Restore the fg flag, which is temporarily set to
					  false during builtin execution so as not to confuse
					  some job-handling builtins.
					*/
					job_set_flag( j, JOB_FOREGROUND, fg );
				}
				
				/*
				  If stdin has been redirected, close the redirection
				  stream.
				*/
				if( close_stdin )
				{
					exec_close( builtin_stdin );
				}				
				break;				
			}
		}
		
		if( exec_error )
		{
			break;
		}
		
		switch( p->type )
		{

			case INTERNAL_BLOCK:
			case INTERNAL_FUNCTION:
			{
				int status = proc_get_last_status();
						
				/*
				  Handle output from a block or function. This usually
				  means do nothing, but in the case of pipes, we have
				  to buffer such io, since otherwise the internal pipe
				  buffer might overflow.
				*/
				if( !io_buffer )
				{
					/*
					  No buffer, so we exit directly. This means we
					  have to manually set the exit status.
					*/
					if( p->next == 0 )
					{
						proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
					}
					p->completed = 1;
					break;
				}

				j->io = io_remove( j->io, io_buffer );
				
				io_buffer_read( io_buffer );
				
				if( io_buffer->param2.out_buffer->used != 0 )
				{
					pid = exec_fork();

					if( pid == 0 )
					{
						
						/*
						  This is the child process. Write out the contents of the pipeline.
						*/
						p->pid = getpid();
						setup_child_process( j, p );

						exec_write_and_exit(io_buffer->fd, 
											io_buffer->param2.out_buffer->buff,
											io_buffer->param2.out_buffer->used,
											status);
					}
					else
					{
						/* 
						   This is the parent process. Store away
						   information on the child, and possibly give
						   it control over the terminal.
						*/
						p->pid = pid;						
						set_child_group( j, p, 0 );
												
					}					
					
				}
				else
				{
					if( p->next == 0 )
					{
						proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status);
					}
					p->completed = 1;
				}
				
				io_buffer_destroy( io_buffer );
				
				io_buffer=0;
				break;
				
			}


			case INTERNAL_BUFFER:
			{
		
				pid = exec_fork();
				
				if( pid == 0 )
				{
					/*
					  This is the child process. Write out the
					  contents of the pipeline.
					*/
					p->pid = getpid();
					setup_child_process( j, p );
					
					exec_write_and_exit( 1,
										 input_redirect->param2.out_buffer->buff, 
										 input_redirect->param2.out_buffer->used,
										 0);
				}
				else
				{
					/* 
					   This is the parent process. Store away
					   information on the child, and possibly give
					   it control over the terminal.
					*/
					p->pid = pid;						
					set_child_group( j, p, 0 );	
				}	

				break;				
			}
			
			case INTERNAL_BUILTIN:
			{
				int skip_fork;
				
				/*
				  Handle output from builtin commands. In the general
				  case, this means forking of a worker process, that
				  will write out the contents of the stdout and stderr
				  buffers to the correct file descriptor. Since
				  forking is expensive, fish tries to avoid it wehn
				  possible.
				*/

				/*
				  If a builtin didn't produce any output, and it is
				  not inside a pipeline, there is no need to fork
				*/
				skip_fork =
					( !sb_out->used ) &&
					( !sb_err->used ) &&
					( !p->next );
	
				/*
				  If the output of a builtin is to be sent to an internal
				  buffer, there is no need to fork. This helps out the
				  performance quite a bit in complex completion code.
				*/

				io_data_t *io = io_get( j->io, 1 );
				int buffer_stdout = io && io->io_mode == IO_BUFFER;
				
				if( ( !sb_err->used ) && 
					( !p->next ) &&
					( sb_out->used ) && 
					( buffer_stdout ) )
				{
					char *res = wcs2str( (wchar_t *)sb_out->buff );
					b_append( io->param2.out_buffer, res, strlen( res ) );
					skip_fork = 1;
					free( res );
				}

				for( io = j->io; io; io=io->next )
				{
					if( io->io_mode == IO_FILE && wcscmp(io->param1.filename, L"/dev/null" ))
					{
						skip_fork = 0;
					}
				}
				
				if( skip_fork )
				{
					p->completed=1;
					if( p->next == 0 )
					{
						debug( 3, L"Set status of %ls to %d using short circut", j->command, p->status );
						
						int status = proc_format_status(p->status);
						proc_set_last_status( job_get_flag( j, JOB_NEGATE )?(!status):status );
					}
					break;
				}

				/*
				  Ok, unfortunatly, we have to do a real fork. Bummer.
				*/
								
				pid = exec_fork();
				if( pid == 0 )
				{

					/*
					  This is the child process. Setup redirections,
					  print correct output to stdout and stderr, and
					  then exit.
					*/
					p->pid = getpid();
					setup_child_process( j, p );
					do_builtin_io( sb_out->used ? (wchar_t *)sb_out->buff : 0, sb_err->used ? (wchar_t *)sb_err->buff : 0 );
					
					exit( p->status );
						
				}
				else
				{
					/* 
					   This is the parent process. Store away
					   information on the child, and possibly give
					   it control over the terminal.
					*/
					p->pid = pid;
						
					set_child_group( j, p, 0 );
										
				}					
				
				break;
			}
			
			case EXTERNAL:
			{
				pid = exec_fork();
				if( pid == 0 )
				{
					/*
					  This is the child process. 
					*/
					p->pid = getpid();
					setup_child_process( j, p );
					launch_process( p );
					
					/*
					  launch_process _never_ returns...
					*/
				}
				else
				{
					/* 
					   This is the parent process. Store away
					   information on the child, and possibly fice
					   it control over the terminal.
					*/
					p->pid = pid;

					set_child_group( j, p, 0 );
															
				}
				break;
			}
			
		}

		if( p->type == INTERNAL_BUILTIN )
			builtin_pop_io();
				
		/* 
		   Close the pipe the current process uses to read from the
		   previous process_t
		*/
		if( pipe_read.param1.pipe_fd[0] >= 0 )
			exec_close( pipe_read.param1.pipe_fd[0] );
		/* 
		   Set up the pipe the next process uses to read from the
		   current process_t
		*/
		if( p->next )
			pipe_read.param1.pipe_fd[0] = mypipe[0];
		
		/* 
		   If there is a next process in the pipeline, close the
		   output end of the current pipe (the surrent child
		   subprocess already has a copy of the pipe - this makes sure
		   we don't leak file descriptors either in the shell or in
		   the children).
		*/
		if( p->next )
		{
			exec_close(mypipe[1]);
		}		
	}

	/*
	  The keepalive process is no longer needed, so we terminate it
	  with extreme prejudice
	*/
	if( needs_keepalive )
	{
		kill( keepalive.pid, SIGKILL );
	}
	
	signal_unblock();	

	debug( 3, L"Job is constructed" );

	j->io = io_remove( j->io, &pipe_read );

	for( tmp = block_io; tmp; tmp=tmp->next )
		j->io = io_remove( j->io, tmp );
	
	job_set_flag( j, JOB_CONSTRUCTED, 1 );

	if( !job_get_flag( j, JOB_FOREGROUND ) )
	{
		proc_last_bg_pid = j->pgid;
	}

	if( !exec_error )
	{
		job_continue (j, 0);
	}
	
}
コード例 #20
0
ファイル: exec.c プロジェクト: CodeMonk/fish
/**
   This function is executed by the child process created by a call to
   fork(). It should be called after \c setup_child_process. It calls
   execve to replace the fish process image with the command specified
   in \c p. It never returns.
*/
static void launch_process( process_t *p )
{
    FILE* f;
	int err;
	
//	debug( 1, L"exec '%ls'", p->argv[0] );

	char **argv = wcsv2strv( (const wchar_t **) p->argv);
	char **envv = env_export_arr( 0 );
	
	execve ( wcs2str(p->actual_cmd), 
		 argv,
		 envv );
	
	err = errno;
	
	/* 
	   Something went wrong with execve, check for a ":", and run
	   /bin/sh if encountered. This is a weird predecessor to the shebang
	   that is still sometimes used since it is supported on Windows.
	*/
	f = wfopen(p->actual_cmd, "r");
	if( f )
	{
		char begin[1] = {0};
		size_t read;
		
		read = fread(begin, 1, 1, f);
		fclose( f );
		
		if( (read==1) && (begin[0] == ':') )
		{
			int count = 0;
			int i = 1;
			wchar_t **res;
            char **res_real;
			
			while( p->argv[count] != 0 )
				count++;
			
			res = malloc( sizeof(wchar_t*)*(count+2));
			
			res[0] = L"/bin/sh";
			res[1] = p->actual_cmd;
			
			for( i=1;  p->argv[i]; i++ ){
				res[i+1] = p->argv[i];
			}
			
			res[i+1] = 0;
			p->argv = res;
			p->actual_cmd = L"/bin/sh";

			res_real = wcsv2strv( (const wchar_t **) res);
			
			execve ( wcs2str(p->actual_cmd), 
				 res_real,
				 envv );
		}
	}
	
	errno = err;
	debug( 0, 
	       _( L"Failed to execute process '%ls'. Reason:" ),
	       p->actual_cmd );
	
	switch( errno )
	{
		
		case E2BIG:
		{
			size_t sz = 0;
			char **p;

			string_buffer_t sz1;
			string_buffer_t sz2;
			
			long arg_max = -1;
						
			sb_init( &sz1 );
			sb_init( &sz2 );
						
			for(p=argv; *p; p++)
			{
				sz += strlen(*p)+1;
			}
			
			for(p=envv; *p; p++)
			{
				sz += strlen(*p)+1;
			}
			
			sb_format_size( &sz1, sz );

			arg_max = sysconf( _SC_ARG_MAX );
			
			if( arg_max > 0 )
			{
				
				sb_format_size( &sz2, arg_max );
				
				debug( 0,
				       L"The total size of the argument and environment lists (%ls) exceeds the operating system limit of %ls.",
				       (wchar_t *)sz1.buff,
				       (wchar_t *)sz2.buff);
			}
			else
			{
				debug( 0,
				       L"The total size of the argument and environment lists (%ls) exceeds the operating system limit.",
				       (wchar_t *)sz1.buff);
			}
			
			debug( 0, 
			       L"Try running the command again with fewer arguments.");
			sb_destroy( &sz1 );
			sb_destroy( &sz2 );
			
			exit(STATUS_EXEC_FAIL);
			
			break;
		}

		case ENOEXEC:
		{
			wperror(L"exec");
			
			debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
			exit(STATUS_EXEC_FAIL);
		}

		case ENOENT:
		{
			wchar_t *interpreter = get_interpreter( p->actual_cmd );
			
			if( interpreter && waccess( interpreter, X_OK ) )
			{
				debug(0, L"The file '%ls' specified the interpreter '%ls', which is not an executable command.", p->actual_cmd, interpreter );
			}
			else
			{
				debug(0, L"The file '%ls' or a script or ELF interpreter does not exist, or a shared library needed for file or interpreter cannot be found.", p->actual_cmd);
			}
			
			exit(STATUS_EXEC_FAIL);
		}

		case ENOMEM:
		{
			debug(0, L"Out of memory");
			exit(STATUS_EXEC_FAIL);
		}

		default:
		{
			wperror(L"exec");
			
			//		debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd);
			exit(STATUS_EXEC_FAIL);
		}
	}
	
}
コード例 #21
0
int main(int argc, char *argv[]) {
    program_name = L"fish_indent";
    set_main_thread();
    setup_fork_guards();
    // Using the user's default locale could be a problem if it doesn't use UTF-8 encoding. That's
    // because the fish project assumes Unicode UTF-8 encoding in all of its scripts.
    //
    // TODO: Auto-detect the encoding of the script. We should look for a vim style comment
    // (e.g., "# vim: set fileencoding=<encoding-name>:") or an emacs style comment
    // (e.g., "# -*- coding: <encoding-name> -*-").
    setlocale(LC_ALL, "");
    env_init();
    input_init();

    // Types of output we support.
    enum {
        output_type_plain_text,
        output_type_file,
        output_type_ansi,
        output_type_html
    } output_type = output_type_plain_text;
    const char *output_location = "";
    bool do_indent = true;

    const char *short_opts = "+d:hvwiD:";
    const struct option long_opts[] = {{"debug-level", required_argument, NULL, 'd'},
        {"debug-stack-frames", required_argument, NULL, 'D'},
        {"dump-parse-tree", no_argument, NULL, 'P'},
        {"no-indent", no_argument, NULL, 'i'},
        {"help", no_argument, NULL, 'h'},
        {"version", no_argument, NULL, 'v'},
        {"write", no_argument, NULL, 'w'},
        {"html", no_argument, NULL, 1},
        {"ansi", no_argument, NULL, 2},
        {NULL, 0, NULL, 0}
    };

    int opt;
    while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
        switch (opt) {
        case 0: {
            fwprintf(stderr, _(L"getopt_long() unexpectedly returned zero\n"));
            exit(127);
            break;
        }
        case 'P': {
            dump_parse_tree = true;
            break;
        }
        case 'h': {
            print_help("fish_indent", 1);
            exit(0);
            break;
        }
        case 'v': {
            fwprintf(stderr, _(L"%ls, version %s\n"), program_name, get_fish_version());
            exit(0);
            break;
        }
        case 'w': {
            output_type = output_type_file;
            break;
        }
        case 'i': {
            do_indent = false;
            break;
        }
        case 1: {
            output_type = output_type_html;
            break;
        }
        case 2: {
            output_type = output_type_ansi;
            break;
        }
        case 'd': {
            char *end;
            long tmp;

            errno = 0;
            tmp = strtol(optarg, &end, 10);

            if (tmp >= 0 && tmp <= 10 && !*end && !errno) {
                debug_level = (int)tmp;
            } else {
                fwprintf(stderr, _(L"Invalid value '%s' for debug-level flag"), optarg);
                exit(1);
            }
            break;
        }
        case 'D': {
            char *end;
            long tmp;

            errno = 0;
            tmp = strtol(optarg, &end, 10);

            if (tmp > 0 && tmp <= 128 && !*end && !errno) {
                debug_stack_frames = (int)tmp;
            } else {
                fwprintf(stderr, _(L"Invalid value '%s' for debug-stack-frames flag"), optarg);
                exit(1);
            }
            break;
        }
        default: {
            // We assume getopt_long() has already emitted a diagnostic msg.
            exit(1);
            break;
        }
        }
    }

    argc -= optind;
    argv += optind;

    wcstring src;
    if (argc == 0) {
        if (output_type == output_type_file) {
            fwprintf(stderr, _(L"Expected file path to read/write for -w:\n\n $ %ls -w foo.fish\n"),
                     program_name);
            exit(1);
        }
        src = read_file(stdin);
    } else if (argc == 1) {
        FILE *fh = fopen(*argv, "r");
        if (fh) {
            src = read_file(fh);
            fclose(fh);
            output_location = *argv;
        } else {
            fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), *argv, strerror(errno));
            exit(1);
        }
    } else {
        fwprintf(stderr, _(L"Too many arguments\n"));
        exit(1);
    }

    const wcstring output_wtext = prettify(src, do_indent);

    // Maybe colorize.
    std::vector<highlight_spec_t> colors;
    if (output_type != output_type_plain_text) {
        highlight_shell_no_io(output_wtext, colors, output_wtext.size(), NULL,
                              env_vars_snapshot_t::current());
    }

    std::string colored_output;
    switch (output_type) {
    case output_type_plain_text: {
        colored_output = no_colorize(output_wtext);
        break;
    }
    case output_type_file: {
        FILE *fh = fopen(output_location, "w");
        if (fh) {
            fputs(wcs2str(output_wtext), fh);
            fclose(fh);
            exit(0);
        } else {
            fwprintf(stderr, _(L"Opening \"%s\" failed: %s\n"), output_location,
                     strerror(errno));
            exit(1);
        }
        break;
    }
    case output_type_ansi: {
        colored_output = ansi_colorize(output_wtext, colors);
        break;
    }
    case output_type_html: {
        colored_output = html_colorize(output_wtext, colors);
        break;
    }
    }

    fputs(colored_output.c_str(), stdout);
    return 0;
}
コード例 #22
0
static int try_get_socket_once(void)
{
    int s;

    wchar_t *wdir;
    wchar_t *wuname;
    char *dir = 0;

    wdir = path;
    wuname = user;

    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    {
        wperror(L"socket");
        return -1;
    }

    if (wdir)
        dir = wcs2str(wdir);
    else
        dir = strdup("/tmp");

    std::string uname;
    if (wuname)
    {
        uname = wcs2string(wuname);
    }
    else
    {
        struct passwd *pw = getpwuid(getuid());
        if (pw && pw->pw_name)
        {
            uname = pw->pw_name;
        }
    }

    std::string name;
    name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2);
    name.append(dir);
    name.append("/");
    name.append(SOCK_FILENAME);
    name.append(uname);

    free(dir);

    debug(3, L"Connect to socket %s at fd %d", name.c_str(), s);

    struct sockaddr_un local = {};
    local.sun_family = AF_UNIX;
    strncpy(local.sun_path, name.c_str(), (sizeof local.sun_path) - 1);

    if (connect(s, (struct sockaddr *)&local, sizeof local) == -1)
    {
        close(s);

        /* If it fails on first try, it's probably no serious error, but fishd hasn't been launched yet.
         This happens (at least) on the first concurrent session. */
        if (get_socket_count > 1)
            wperror(L"connect");

        return -1;
    }

    if ((make_fd_nonblocking(s) != 0) || (fcntl(s, F_SETFD, FD_CLOEXEC) != 0))
    {
        wperror(L"fcntl");
        close(s);

        return -1;
    }

    debug(3, L"Connected to fd %d", s);

    return s;
}
コード例 #23
0
ファイル: screen.cpp プロジェクト: anbotero/fish-shell
void s_write( screen_t *s,
	      const wchar_t *prompt,
	      const wchar_t *commandline, 
	      size_t explicit_len,
	      const int *c, 
	      const int *indent,
	      size_t cursor_pos )
{
	screen_data_t::cursor_t cursor_arr;

	size_t prompt_width;
	size_t screen_width;

	int current_line_width = 0, newline_count = 0, explicit_portion_width = 0;
    size_t max_line_width = 0;
	
	CHECK( s, );
	CHECK( prompt, );
	CHECK( commandline, );
	CHECK( c, );
	CHECK( indent, );

	/*
	  If we are using a dumb terminal, don't try any fancy stuff,
	  just print out the text.
	 */
	if( is_dumb() )
	{
		char *prompt_narrow = wcs2str( prompt );
		char *buffer_narrow = wcs2str( commandline );
		
		write_loop( 1, "\r", 1 );
		write_loop( 1, prompt_narrow, strlen( prompt_narrow ) );
		write_loop( 1, buffer_narrow, strlen( buffer_narrow ) );

		free( prompt_narrow );
		free( buffer_narrow );
		
		return;
	}
	
	prompt_width = calc_prompt_width( prompt );
	screen_width = common_get_width();

	s_check_status( s );

	/*
	  Ignore prompts wider than the screen - only print a two
	  character placeholder...

	  It would be cool to truncate the prompt, but because it can
	  contain escape sequences, this is harder than you'd think.
	*/
	if( prompt_width >= screen_width )
	{
		prompt = L"> ";
		prompt_width = 2;
	}
	
	/*
	  Completely ignore impossibly small screens
	*/
	if( screen_width < 4 )
	{
		return;
	}

	/*
	  Check if we are overflowing
	 */
    size_t last_char_that_fits = 0;
	for( size_t i=0; commandline[i]; i++ )
	{
		if( commandline[i] == L'\n' )
		{
			if( current_line_width > max_line_width )
				max_line_width = current_line_width;
			current_line_width = indent[i]*INDENT_STEP;
            newline_count++;
		}
		else
		{
            int width = fish_wcwidth(commandline[i]);
			current_line_width += width;
            if (i < explicit_len)
                explicit_portion_width += width;
                
            if (prompt_width + current_line_width < screen_width)
                last_char_that_fits = i;
		}
	}
	if( current_line_width > max_line_width )
		max_line_width = current_line_width;

    s->desired.resize(0);
	s->desired.cursor.x = s->desired.cursor.y = 0;
    
    /* If we cannot fit with the autosuggestion, but we can fit without it, truncate the autosuggestion. We limit this check to just one line to avoid confusion; not sure how well this would work with multiple lines */
    wcstring truncated_autosuggestion_line;
    if (newline_count == 0 && prompt_width + max_line_width >= screen_width && prompt_width + explicit_portion_width < screen_width)
    {
        assert(screen_width - prompt_width >= 1);
        max_line_width = screen_width - prompt_width - 1;
        truncated_autosuggestion_line = wcstring(commandline, 0, last_char_that_fits);
        commandline = truncated_autosuggestion_line.c_str();
    }
	for( size_t i=0; i<prompt_width; i++ )
	{
		s_desired_append_char( s, L' ', 0, 0, prompt_width );
	}

	/*
	  If overflowing, give the prompt its own line to improve the
	  situation.
	 */
	if( max_line_width + prompt_width >= screen_width )
	{
		s_desired_append_char( s, L'\n', 0, 0, 0 );
		prompt_width=0;
	}
	
    size_t i;
	for( i=0; commandline[i]; i++ )
	{
		int col = c[i];
		
		if( i == cursor_pos )
		{
			col = 0;
		}
		
		if( i == cursor_pos )
		{
            cursor_arr = s->desired.cursor;
		}
		
		s_desired_append_char( s, commandline[i], col, indent[i], prompt_width );
		
	}
	if( i == cursor_pos )
	{
        cursor_arr = s->desired.cursor;
	}
	
    s->desired.cursor = cursor_arr;
	s_update( s, prompt );
	s_save_status( s );
}
コード例 #24
0
ファイル: fish_tests.c プロジェクト: CodeMonk/fish
/**
   Test wide/narrow conversion by creating random strings and
   verifying that the original string comes back thorugh double
   conversion.
*/
static void test_convert()
{
/*	char o[] = 
		{
			-17, -128, -121, -68, 0
		}
	;
	
	wchar_t *w = str2wcs(o);
	char *n = wcs2str(w);

	int i;
	
	for( i=0; o[i]; i++ )
	{
		bitprint(o[i]);;
		//wprintf(L"%d ", o[i]);
	}
	wprintf(L"\n");

	for( i=0; w[i]; i++ )
	{
		wbitprint(w[i]);;
		//wprintf(L"%d ", w[i]);
	}
	wprintf(L"\n");

	for( i=0; n[i]; i++ )
	{
		bitprint(n[i]);;
		//wprintf(L"%d ", n[i]);
	}
	wprintf(L"\n");

	return;
*/


	int i;
	buffer_t sb;
	
	say( L"Testing wide/narrow string conversion" );

	b_init( &sb );
	
	for( i=0; i<ESCAPE_TEST_COUNT; i++ )
	{
		wchar_t *w;
		char *o, *n;
		
		char c;
		
		sb.used=0;
		
		while( rand() % ESCAPE_TEST_LENGTH )
		{
			c = rand ();
			b_append( &sb, &c, 1 );
		}
		c = 0;
		b_append( &sb, &c, 1 );
		
		o = (char *)sb.buff;
		w = str2wcs(o);
		n = wcs2str(w);
		
		if( !o || !w || !n )
		{
			err( L"Conversion cycle of string %s produced null pointer on %s", o, w?L"str2wcs":L"wcs2str" );
		}
		
		if( strcmp(o, n) )
		{
			err( L"%d: Conversion cycle of string %s produced different string %s", i, o, n );
		}
		free( w );
		free( n );
		
	}

}