diff --git a/lib/master.pike.in b/lib/master.pike.in index 96068f00c674f0b0ca285872eb941239485051b0..5675c806bbbf821cc550fe80f0a6c6633eb1418b 100644 --- a/lib/master.pike.in +++ b/lib/master.pike.in @@ -6,7 +6,7 @@ // Pike is distributed under GPL, LGPL and MPL. See the file COPYING // for more information. // -// $Id: master.pike.in,v 1.433 2008/06/02 17:29:25 mast Exp $ +// $Id: master.pike.in,v 1.434 2008/06/05 14:58:28 mast Exp $ #pike __REAL_VERSION__ //#pragma strict_types @@ -558,6 +558,7 @@ static class Pike_7_4_master { inherit Pike_7_2_master; local static object Pike_7_4_compat_handler; + void error(string f, mixed ... args); local mixed resolv(string identifier, string|void current_file) { if (!Pike_7_4_compat_handler) { @@ -591,11 +592,69 @@ static class Pike_7_6_master } return Pike_7_6_compat_handler->resolv(identifier, current_file); } + array get_backtrace (object|array err); object get_compat_master(int major, int minor) { if ((major == 7) && (minor > 2)) return Pike_7_4_master::this; return Pike_7_4_master::get_compat_master(major, minor); } + + //! Mapping containing the environment variables. + //! + //! The mapping currently has the following structure: + //! @mapping + //! @member array(string) index + //! Note that the index is @[lower_case()]'d on NT. + //! @array + //! @elem string varname + //! Variable name with case intact. + //! @elem string value + //! Variable value. + //! @endarray + //! @endmapping + //! + //! @note + //! This mapping should not be accessed directly; use @[getenv()] + //! and @[putenv()] instead. This mapping is not publicly + //! accessible in pikes newer than 7.6. + //! + //! @note + //! This mapping is not compatible with @[Process.create_process()]; + //! use the mapping returned from calling @[getenv()] without arguments + //! instead. + //! + //! @bugs + //! This mapping is not the real environment; it is just a copy of + //! the environment made at startup. + local mapping(string:array(string)) environment; + + local string|mapping(string:string) getenv(string|void s) + { + if(!s) return [mapping(string:string)]aggregate_mapping( @(values(environment)*({}) ) ); +#ifdef __NT__ + s = lower_case(s); +#endif + return environment[s] && environment[s][1]; + } + + local void putenv(string varname, string|void value) + { + // Try to update the real enviroment too, but ignore errors since + // the fake environment could accommodate wide strings, strings + // with NULs etc. + catch {Builtin._putenv (varname, value);}; + string index = varname; +#ifdef __NT__ + index = lower_case(varname); + if (environment[index] && environment[index][0]) + varname = environment[index][0]; +#endif + if (value) { + environment[index] = ({ varname, value }); + } else { + m_delete(environment, index); + } + } } //! Namespaces for compat masters. @@ -923,62 +982,117 @@ Stat master_file_stat(string x) #define master_file_stat file_stat #endif // FILE_STAT_CACHE -//! Mapping containing the environment variables. + +static mapping(string:string) environment; + +#ifdef __NT__ +static void set_lc_env (mapping(string:string) env) +{ + environment = ([]); + foreach (env; string var; string val) + environment[lower_case (var)] = val; +} +#endif + +//! @decl string getenv (string varname, void|int force_update) +//! @decl mapping(string:string) getenv (void|int force_update) //! -//! The mapping currently has the following structure: -//! @mapping -//! @member array(string) index -//! Note that the index is @[lower_case()]'d on NT. -//! @array -//! @elem string varname -//! Variable name with case intact. -//! @elem string value -//! Variable value. -//! @endarray -//! @endmapping +//! Queries the environment variables. The first variant returns the +//! value of a specific variable or zero if it doesn't exist in the +//! environment. The second variant returns the whole environment as a +//! mapping. Destructive opreations on the mapping will not affect the +//! internal environment representation. //! -//! @note -//! This mapping should not be accessed directly; use @[getenv()] -//! and @[putenv()] instead. +//! A cached copy of the real environment is kept to make this +//! function quicker. If the optional flag @[force_update] is nonzero +//! then the real environment is queried and the cache is updated from +//! it. That can be necessary if the environment changes through other +//! means than @[putenv], typically from a C-level library. +//! +//! Variable names and values cannot be wide strings nor contain +//! @expr{'\0'@} characters. Variable names also cannot contain +//! @expr{'='@} characters. //! //! @note -//! This mapping is not compatible with @[Process.create_process()]; -//! use the mapping returned from calling @[getenv()] without arguments -//! instead. +//! On NT the environment variable name is case insensitive. //! -//! @bugs -//! This mapping is not the real environment; it is just a copy of -//! the environment made at startup. When this bug is fixed this -//! mapping might disappear altogether, which is another good reason -//! to not use it directly. -mapping(string:array(string)) environment=([]); +//! @seealso +//! @[putenv()] +string|mapping(string:string) getenv (void|int|string var, + void|int force_update) +{ + // Variants doesn't seem to work well yet. + if (stringp (var)) { + if (!environment || force_update) { +#ifdef __NT__ + set_lc_env (Builtin._getenv()); +#else + environment = Builtin._getenv(); +#endif + } + +#ifdef __NT__ + return environment[lower_case (var)]; +#else + return environment[var]; +#endif + } + + else { + force_update = var; + mapping(string:string) res; -//! @decl string getenv(string varname) -//! @decl mapping(string:string) getenv() -//! @appears getenv + if (force_update) { + res = Builtin._getenv(); +#ifdef __NT__ + set_lc_env (res); +#else + environment = res + ([]); +#endif + } + + else { +#ifdef __NT__ + // Can't use the cached environment since variable names have been + // lowercased there. + res = Builtin._getenv(); + if (!environment) set_lc_env (res); +#else + if (!environment) environment = Builtin._getenv(); + res = environment + ([]); +#endif + } + + return res; + } +} + +void putenv (string varname, void|string value) +//! Sets the environment variable @[varname] to @[value]. //! -//! When called with no arguments, a mapping with all current environment -//! variables will be returned. Destructive opreations on the mapping -//! will not affect the internal environment representation. +//! If @[value] is omitted or zero, the environment variable +//! @[varname] will be removed. //! -//! If the @[varname] argument has been given, the value of the environment -//! variable with the name @[varname] will be returned. If no such -//! environment variable exists, @expr{0@} (zero) will be returned. +//! @[varname] and @[value] cannot be wide strings nor contain +//! @expr{'\0'@} characters. @[varname] also cannot contain +//! @expr{'='@} characters. //! -//! On NT the environment variable name is case insensitive. +//! @note +//! On NT the environment variable name is case insensitive. +//! +//! @seealso +//! @[getenv()] //! -//! @bugs -//! This function doesn't really query the environment, it only -//! accesses a pike internal mapping that is initialized from the -//! environment on startup and that @[putenv] updates. -string|mapping(string:string) getenv(string|void s) { - if(!s) return [mapping(string:string)]aggregate_mapping( @(values(environment)*({}) ) ); + Builtin._putenv (varname, value); + if (environment) { #ifdef __NT__ - s = lower_case(s); + varname = lower_case (varname); #endif - return environment[s] && environment[s][1]; + if (value) environment[varname] = value; + else m_delete (environment, varname); + } } @@ -1012,63 +1126,6 @@ program compile_file(string filename, } - -#if 0 -variant mapping(string:string) getenv() -{ - return environment + ([]); -} - -variant string getenv(string s) -{ - return environment[s]; -} - -function(:mapping(string:string))|function(string:string) getenv(s) -{ - if(!s) return environment + ([]); - return environment[s]; -} - -// mapping(string:string) getenv() | -string getenv(string s) -{ - if(!s) return environment + ([]); - return environment[s]; -} -#endif /* 0 */ - -//! @appears putenv -//! Sets the environment variable @[varname] to @[value]. -//! -//! If @[value] is omitted or zero, the environment variable -//! @[varname] will be removed. -//! -//! @note -//! On NT the environment variable name is case insensitive. -//! -//! @bugs -//! This function doesn't really update the environment, it just -//! updates a pike internal mapping that @[getenv] uses. -//! -//! @seealso -//! @[getenv()] -//! -void putenv(string varname, string|void value) -{ - string index = varname; -#ifdef __NT__ - index = lower_case(varname); - if (environment[index] && environment[index][0]) - varname = environment[index][0]; -#endif - if (value) { - environment[index] = ({ varname, value }); - } else { - m_delete(environment, index); - } -} - //! @appears normalize_path //! Replaces "\" with "/" if runing on MS Windows. It is //! adviced to use @[System.normalize_path] instead. @@ -1827,9 +1884,11 @@ static void create() #endif system_module_path=pike_module_path; - if (master() && master() != this_object()) { + if (master() && master() != this_object() && + (compat_major < 7 || (compat_major == 7 && compat_minor <= 6)) { // getenv() and putenv() will get confused if we don't do this. - environment = master()->environment || environment; + // This is only for pike <= 7.6 compat. + if (mapping e = master()->environment) environment = e; } } @@ -3063,10 +3122,8 @@ static mixed main_resolv(string sym, CompatResolver|void resolver) { //! This function is called when all the driver is done with all setup //! of modules, efuns, tables etc. etc. and is ready to start executing -//! _real_ programs. It receives the arguments not meant for the driver -//! and an array containing the environment variables on the same form as -//! a C program receives them. -void _main(array(string) orig_argv, array(string) env) +//! _real_ programs. It receives the arguments not meant for the driver. +void _main(array(string) orig_argv) { array(string) argv=copy_value(orig_argv); int debug,trace,run_tool; @@ -3080,19 +3137,6 @@ void _main(array(string) orig_argv, array(string) env) _backend_thread = this_thread(); #endif - foreach(env, string a) - if( sscanf(a, "%s=%s", a, string b)==2 ) { -#ifdef __NT__ - if(a=="") { - sscanf(b, "%s=%s", a, b); - a="="+a; - } -#endif - putenv(a, b); - } - else - werror("Broken environment var %s\n",a); - #ifndef NOT_INSTALLED { array parts = (getenv("PIKE_INCLUDE_PATH")||"")/PATH_SEPARATOR-({""}); @@ -3120,6 +3164,8 @@ void _main(array(string) orig_argv, array(string) env) " " + "\n"); }; + Version cur_compat_ver; + if(sizeof(argv)>1 && sizeof(argv[1]) && argv[1][0]=='-') { array q; @@ -3261,6 +3307,32 @@ void _main(array(string) orig_argv, array(string) env) } } + cur_compat_ver = Version (compat_major, compat_minor); + if (compat_major != -1) { + object compat_master = get_compat_master (compat_major, compat_minor); + + if (cur_compat_ver <= Version (7, 6)) { + mapping(string:array(string)) compat_env = ([]); + foreach (Builtin._getenv(); string var; string val) { +#ifdef __NT__ + compat_env[lower_case (var)] = ({var, val}); +#else + compat_env[var] = ({var, val}); +#endif + } + compat_master->environment = compat_env; + } + + // Kludge: Override the efuns with the right compat versions. + // Note that this approach is a bit simplistic since it only + // reflects the compat chosen with -V, not #pike etc. If that + // isn't good enough we'll need compat dispatchers in these + // functions. The right solution is to move the constants + // mapping from the C level to the master. + foreach (master_efuns + compat_master->master_efuns, string e) + add_constant (e, compat_master[e]); + } + foreach(q, array opts) { switch(opts[0]) @@ -3302,7 +3374,7 @@ void _main(array(string) orig_argv, array(string) env) program prog; mixed compile_err = catch {; - if(Version(compat_major,compat_minor) <= Version(7,4)) + if(cur_compat_ver <= Version(7,4)) prog = compile_string( "mixed create(int argc, array(string) argv,array(string) env){"+ opts[1]+";}"); @@ -3312,11 +3384,16 @@ void _main(array(string) orig_argv, array(string) env) string code = opts[1]; while(sscanf(code, "%sCHAR(%1s)%s", code, string c, string rest)==3) code += c[0] + rest; - prog = compile_string( - "#define NOT(X) !(X)\n" - "mixed run(int argc, array(string) argv," - "mapping(string:string) env){"+ - code+";}"); + if (cur_compat_ver <= Version (7, 6)) + prog = compile_string( + "#define NOT(X) !(X)\n" + "mixed run(int argc, array(string) argv," + "mapping(string:string) env){"+ + code+";}"); + else + prog = compile_string( + "#define NOT(X) !(X)\n" + "mixed run(int argc, array(string) argv){" + code + ";}"); } }; @@ -3340,10 +3417,12 @@ void _main(array(string) orig_argv, array(string) env) // eval_instruction in interpret.c so that the debug and // trace levels set above take effect in the bytecode // evaluator. - if(Version(compat_major,compat_minor) <= Version(7,4)) - prog (sizeof(argv),argv,env); - else + if(cur_compat_ver <= Version(7,4)) + prog (sizeof(argv),argv,getenv()); + else if (cur_compat_ver <= Version (7, 6)) ret = prog()->run(sizeof(argv),argv,getenv()); + else + ret = prog()->run(sizeof(argv),argv); }; predef::trace(trace); if (err) { @@ -3368,6 +3447,8 @@ void _main(array(string) orig_argv, array(string) env) argv = tmp->get_args(argv,1); } + else + cur_compat_ver = Version (compat_major, compat_minor); switch (postparseaction) { @@ -3489,7 +3570,7 @@ void _main(array(string) orig_argv, array(string) env) // to eval_instruction in interpret.c so that the debug and // trace levels set above take effect in the bytecode evaluator. object script; - if(Version(compat_major,compat_minor) <= Version(7,4)) { + if(cur_compat_ver <= Version(7,4)) { script=prog(); } else { @@ -3497,7 +3578,10 @@ void _main(array(string) orig_argv, array(string) env) } if(!script->main) error("Error: %s has no main().\n", argv[0]); - ret=script->main(sizeof(argv),argv,env); + if (cur_compat_ver <= Version (7, 6)) + ret=script->main(sizeof(argv),argv,getenv()); + else + ret=script->main(sizeof(argv),argv); }; // Disable tracing. trace = predef::trace(trace); @@ -5389,4 +5473,3 @@ local object get_compat_master(int major, int minor) if ((major == 7) && (minor > 4)) return Pike_7_6_master::this; return Pike_7_6_master::get_compat_master(major, minor); } -