2
* This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3
* http://www.gnu.org/licenses/gpl-3.0.html
10
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
15
#include <wx/checklst.h>
18
#include "configmanager.h"
21
#include "macrosmanager.h"
22
#include "logmanager.h"
25
#include "envvars_common.h"
27
// Uncomment this for tracing of method calls in C::B's DebugLog:
28
//#define TRACE_ENVVARS
30
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
32
const wxString nsEnvVars::EnvVarsSep = _T("|");
33
const wxString nsEnvVars::EnvVarsDefault = _T("default");
35
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
37
void nsEnvVars::EnvVarsDebugLog(const wxChar* msg, ...)
39
// load and apply configuration (to application only)
40
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
44
// get whether to print debug message to debug log or not
45
bool debug_log = cfg->ReadBool(_T("/debug_log"));
52
va_start(arg_list, msg);
53
log_msg = wxString::FormatV(msg, arg_list);
56
Manager::Get()->GetLogManager()->DebugLog(log_msg);
59
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
61
wxArrayString nsEnvVars::EnvvarStringTokeniser(const wxString& str)
64
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarStringTokeniser")));
66
// tokenise string like:
67
// C:\Path;"D:\Other Path"
71
wxString search = str;
72
search.Trim(true).Trim(false);
74
// trivial case: string is empty or consists of blanks only
79
bool inside_quot = false;
81
while (pos < search.Length())
83
wxString current_char = search.GetChar(pos);
85
// for e.g. /libpath:"C:\My Folder"
86
if (current_char.CompareTo(_T("\""))==0) // equality
87
inside_quot = !inside_quot;
89
if ((current_char.CompareTo(nsEnvVars::EnvVarsSep)==0) && (!inside_quot))
98
token.Append(current_char);
101
// Append final token
102
if ((pos==search.Length()) && (!inside_quot) && (!token.IsEmpty()))
107
}// EnvvarStringTokeniser
109
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
111
wxArrayString nsEnvVars::GetEnvvarSetNames()
114
Manager::Get()->GetLogManager()->DebugLog(F(_T("GetEnvvarSetNames")));
117
wxArrayString set_names;
119
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
122
set_names.Add(nsEnvVars::EnvVarsDefault);
126
// Read all envvar sets available
127
wxArrayString sets = cfg->EnumerateSubPaths(_T("/sets"));
128
unsigned int num_sets = sets.GetCount();
129
EV_DBGLOG(_T("EnvVars: Found %d envvar sets in config."), num_sets);
132
set_names.Add(nsEnvVars::EnvVarsDefault);
135
for (unsigned int i=0; i<num_sets; ++i)
137
wxString set_name = sets[i];
138
if (set_name.IsEmpty())
139
set_name.Printf(_T("Set%d"), i);
141
set_names.Add(set_name);
146
}// GetEnvvarSetNames
148
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
150
wxString nsEnvVars::GetActiveSetName()
153
Manager::Get()->GetLogManager()->DebugLog(F(_T("GetActiveSetName")));
156
wxString active_set = nsEnvVars::EnvVarsDefault;
158
// load and apply configuration (to application only)
159
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
163
// try to get the envvar set name of the currently active global envvar set
164
wxString active_set_cfg = cfg->Read(_T("/active_set"));
165
if (!active_set_cfg.IsEmpty())
166
active_set = active_set_cfg;
168
EV_DBGLOG(_T("EnvVars: Obtained '%s' as active envvar set from config."), active_set.c_str());
172
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
174
wxString nsEnvVars::GetSetPathByName(const wxString& set_name, bool check_exists,
178
Manager::Get()->GetLogManager()->DebugLog(F(_T("GetSetPathByName")));
181
wxString set_path = _T("/sets/")+nsEnvVars::EnvVarsDefault; // fall back solution
185
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
186
if (!cfg || set_path.IsEmpty())
190
return _T("/sets/")+set_name;
192
// Read all envvar sets available
193
wxArrayString sets = cfg->EnumerateSubPaths(_T("/sets"));
194
unsigned int num_sets = sets.GetCount();
195
for (unsigned int i=0; i<num_sets; ++i)
197
if (set_name.IsSameAs(sets[i]))
199
set_path = (_T("/sets/")+set_name);
200
break; // Early exit of for-loop
207
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
209
wxArrayString nsEnvVars::GetEnvvarsBySetPath(const wxString& set_path)
212
Manager::Get()->GetLogManager()->DebugLog(F(_T("GetEnvvarsBySetPath")));
215
wxArrayString envvars;
216
EV_DBGLOG(_T("EnvVars: Searching for envvars in path '%s'."), set_path.c_str());
218
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
219
if (!cfg || set_path.IsEmpty())
222
wxArrayString envvars_keys = cfg->EnumerateKeys(set_path);
223
unsigned int num_envvars = envvars_keys.GetCount();
224
for (unsigned int i=0; i<num_envvars; ++i)
226
wxString envvar = cfg->Read(set_path+_T("/")+envvars_keys[i]);
227
if (!envvar.IsEmpty())
230
EV_DBGLOG(_T("EnvVars: Warning: empty envvar detected and skipped."));
232
EV_DBGLOG(_T("EnvVars: Read %d/%d envvars in path '%s'."),
233
envvars.GetCount(), num_envvars, set_path.c_str());
236
}// GetEnvvarsBySetPath
238
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
240
bool nsEnvVars::EnvvarSetExists(const wxString& set_name)
243
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarSetExists")));
246
if (set_name.IsEmpty())
249
wxString set_path = nsEnvVars::GetSetPathByName(set_name, true, false);
250
if (set_name.IsEmpty())
256
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
258
bool nsEnvVars::EnvvarVeto(const wxString& key, wxCheckListBox* lstEnvVars, int sel)
261
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarVeto")));
264
if (wxGetEnv(key, NULL))
267
if (platform::windows) recursion = _T("PATH=%PATH%;C:\\NewPath");
268
else recursion = _T("PATH=$PATH:/new_path");
271
warn_exist.Printf(_("Warning: Environment variable '%s' is already set.\n"
272
"Continue with updating it's value?\n"
273
"(Recursions like '%s' will be considered.)"),
274
key.c_str(), recursion.c_str());
276
if (cbMessageBox(warn_exist, _("Confirmation"),
277
wxYES_NO | wxICON_QUESTION) == wxID_NO)
279
if (lstEnvVars && (sel>=0))
280
lstEnvVars->Check(sel, false); // Unset to visualise it's NOT set
281
return true; // User has vetoed the operation
288
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
290
bool nsEnvVars::EnvvarsClear(wxCheckListBox* lstEnvVars)
293
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarsClear")));
296
wxString envsNotUnSet(wxEmptyString);
298
// Unset all (checked) variables of lstEnvVars
299
for (int i=0; i<(int)lstEnvVars->GetCount(); ++i)
301
// Note: It's better not to just clear all because wxUnsetEnv would
302
// fail in case an envvar is not set (not checked).
303
if (lstEnvVars->IsChecked(i))
305
wxString key = lstEnvVars->GetString(i).BeforeFirst(_T('=')).Trim(true).Trim(false);
308
if (!nsEnvVars::EnvvarDiscard(key))
310
// Setting env.-variable failed. Remember this key to report later.
311
if (envsNotUnSet.IsEmpty())
314
envsNotUnSet << _T(", ") << key;
322
if (!envsNotUnSet.IsEmpty())
325
msg.Printf( _("There was an error unsetting the following environment variables:\n%s"),
326
envsNotUnSet.c_str() );
327
cbMessageBox(msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
334
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
336
bool nsEnvVars::EnvvarDiscard(const wxString &key)
339
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarDiscard")));
342
// Replace all macros the user might have setup for the key
343
wxString the_key = key;
344
Manager::Get()->GetMacrosManager()->ReplaceMacros(the_key);
346
if (!wxUnsetEnv(the_key))
348
Manager::Get()->GetLogManager()->Log(F(
349
_("Unsetting environment variable '%s' failed."), the_key.c_str()));
350
EV_DBGLOG(_T("EnvVars: Unsetting environment variable '%s' failed."),
358
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
360
bool nsEnvVars::EnvvarApply(const wxString& key, const wxString& value,
361
wxCheckListBox* lstEnvVars, int sel)
364
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarApply")));
367
// Key: Replace all macros the user might have used
368
wxString the_key = key;
369
Manager::Get()->GetMacrosManager()->ReplaceMacros(the_key);
371
// Value: First, expand stuff like:
372
// set PATH=%PATH%;C:\NewPath OR export PATH=$PATH:/new_path
373
// After, replace all macros the user might have used in addition
374
wxString the_value = value;
376
bool is_set = wxGetEnv(the_key, &value_set);
380
if (platform::windows) recursion = _T("%")+the_key+_("%");
381
else recursion = _T("$")+the_key;
383
if (the_value.Contains(recursion))
385
// Avoid endless recursion if the value set contains e.g. $PATH, too
386
if (value_set.Contains(recursion))
388
EV_DBGLOG(_T("EnvVars: Setting environment variable '%s' failed "
389
"due to unsresolvable recursion."), the_key.c_str());
390
if (lstEnvVars && (sel>=0))
391
lstEnvVars->Check(sel, false); // Unset to visualise it's NOT set
394
the_value.Replace(recursion.c_str(), value_set.c_str());
397
Manager::Get()->GetMacrosManager()->ReplaceMacros(the_value);
399
EV_DBGLOG(_T("EnvVars: Trying to set environment variable '%s' to value '%s'..."), the_key.c_str(), the_value.c_str());
400
if (!wxSetEnv(the_key, the_value))
402
EV_DBGLOG(_T("EnvVars: Setting environment variable '%s' failed."), the_key.c_str());
403
if (lstEnvVars && (sel>=0))
404
lstEnvVars->Check(sel, false); // Unset to visualise it's NOT set
411
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
413
bool nsEnvVars::EnvvarArrayApply(const wxArrayString& envvar,
414
wxCheckListBox* lstEnvVars)
417
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarApply")));
420
if (envvar.GetCount() == 3)
422
wxString check = envvar[0];
423
wxString key = envvar[1];
424
wxString value = envvar[2];
426
bool bCheck = check.Trim(true).Trim(false).IsSameAs(_T("1"))?true:false;
427
key.Trim(true).Trim(false);
428
value.Trim(true).Trim(false);
433
sel = lstEnvVars->Append(key + _T(" = ") + value);
434
lstEnvVars->Check(sel, bCheck);
439
if (EnvvarApply(key, value, lstEnvVars, sel))
443
return true; // No need to apply -> success, too.
449
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
451
void nsEnvVars::EnvvarSetApply(const wxString& set_name, bool even_if_active)
454
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarSetApply")));
457
// Load and apply envvar set from config (to application only)
458
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
462
// Stores the currently active envar set that has been successfully applied at last
463
static wxString last_set_applied = wxEmptyString;
465
wxString set_to_apply = set_name;
466
if (set_to_apply.IsEmpty())
467
set_to_apply = nsEnvVars::GetActiveSetName();
469
// Early exit for a special case requested by even_if_active parameter
470
if (!even_if_active && set_to_apply.IsSameAs(last_set_applied))
472
EV_DBGLOG(_T("EnvVars: Set '%s' will not be applied (already active)."),
473
set_to_apply.c_str());
477
// Show currently activated set in debug log (for reference)
478
wxString set_path = nsEnvVars::GetSetPathByName(set_to_apply);
479
EV_DBGLOG(_T("EnvVars: Active envvar set is '%s', config path '%s'."),
480
set_to_apply.c_str(), set_path.c_str());
482
// Read and apply all envvars from currently active set in config
483
wxArrayString vars = nsEnvVars::GetEnvvarsBySetPath(set_path);
484
size_t envvars_total = vars.GetCount();
485
size_t envvars_applied = 0;
486
for (unsigned int i=0; i<envvars_total; ++i)
488
// Format: [checked?]|[key]|[value]
489
wxArrayString var_array = nsEnvVars::EnvvarStringTokeniser(vars[i]);
490
if (nsEnvVars::EnvvarArrayApply(var_array))
493
EV_DBGLOG(_T("EnvVars: Invalid envvar in '%s' at position #%d."),
494
set_path.c_str(), i);
499
last_set_applied = set_to_apply;
500
EV_DBGLOG(_T("EnvVars: %d/%d envvars applied within C::B focus."),
501
envvars_applied, envvars_total);
505
// ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----
507
void nsEnvVars::EnvvarSetDiscard(const wxString& set_name)
510
Manager::Get()->GetLogManager()->DebugLog(F(_T("EnvvarSetDiscard")));
513
// load and apply envvar set from config (to application only)
514
ConfigManager *cfg = Manager::Get()->GetConfigManager(_T("envvars"));
518
wxString set_to_discard = set_name;
519
if (set_to_discard.IsEmpty())
520
set_to_discard = nsEnvVars::GetActiveSetName();
522
// Show currently activated set in debug log (for reference)
523
wxString set_path = nsEnvVars::GetSetPathByName(set_to_discard);
524
EV_DBGLOG(_T("EnvVars: Active envvar set is '%s', config path '%s'."),
525
set_to_discard.c_str(), set_path.c_str());
527
// Read and apply all envvars from currently active set in config
528
wxArrayString vars = nsEnvVars::GetEnvvarsBySetPath(set_path);
529
size_t envvars_total = vars.GetCount();
530
size_t envvars_discarded = 0;
531
for (unsigned int i=0; i<envvars_total; ++i)
533
// Format: [checked?]|[key]|[value]
534
wxArrayString var_array = nsEnvVars::EnvvarStringTokeniser(vars[i]);
535
if (var_array.GetCount()==3)
537
wxString check = var_array[0];
538
bool bCheck = check.Trim(true).Trim(false).IsSameAs(_T("1"))?true:false;
539
if (!bCheck || (bCheck && nsEnvVars::EnvvarDiscard(var_array[1]))) // key
543
EV_DBGLOG(_T("EnvVars: Invalid envvar in '%s' at position #%d."),
544
set_path.c_str(), i);
549
EV_DBGLOG(_T("EnvVars: %d/%d envvars discarded within C::B focus."),
550
envvars_discarded, envvars_total);