|
1 // env.cpp |
|
2 // |
|
3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 |
|
13 #include "ioutils.h" |
|
14 #include "command_base.h" |
|
15 #include <fshell/stringhash.h> |
|
16 #include <fshell/ltkutils.h> |
|
17 #include <fshell/descriptorutils.h> |
|
18 |
|
19 using namespace IoUtils; |
|
20 using LtkUtils::RStringHash; |
|
21 using LtkUtils::TStringHashIter; |
|
22 |
|
23 #define iVars (*reinterpret_cast<RStringHash<HBufC*>*>(iVarsImpl)) |
|
24 #define ConstVarsFor(x) (*reinterpret_cast<const RStringHash<HBufC*>*>((x)->iVarsImpl)) |
|
25 #define iConstVars ConstVarsFor(this) |
|
26 |
|
27 // |
|
28 // Constants. |
|
29 // |
|
30 |
|
31 _LIT(KEnvPwd, "PWD"); |
|
32 _LIT(KDefaultPwd, "c:\\"); |
|
33 _LIT(KChildError, "?"); |
|
34 _LIT(KEnvEscapeChar, "ESCAPE"); |
|
35 |
|
36 // |
|
37 // CEnvironment. |
|
38 // |
|
39 |
|
40 EXPORT_C CEnvironment* CEnvironment::NewL() |
|
41 { |
|
42 CEnvironment* self = new(ELeave) CEnvironment(); |
|
43 CleanupStack::PushL(self); |
|
44 self->ConstructL(); |
|
45 self->SetPwdL(KDefaultPwd); |
|
46 self->SetL(KChildError, KErrNone); |
|
47 CleanupStack::Pop(self); |
|
48 return self; |
|
49 } |
|
50 |
|
51 EXPORT_C CEnvironment* CEnvironment::NewL(const CEnvironment& aEnv) |
|
52 { |
|
53 CEnvironment* self = CEnvironment::NewL(); |
|
54 CleanupStack::PushL(self); |
|
55 self->CopyL(aEnv); |
|
56 CleanupStack::Pop(self); |
|
57 return self; |
|
58 } |
|
59 |
|
60 EXPORT_C CEnvironment* CEnvironment::CreateSharedEnvironmentL() |
|
61 { |
|
62 CEnvironment* newenv = new(ELeave) CEnvironment(this); |
|
63 CleanupStack::PushL(newenv); |
|
64 newenv->ConstructL(); |
|
65 CleanupStack::Pop(newenv); |
|
66 return newenv; |
|
67 } |
|
68 |
|
69 EXPORT_C CEnvironment::~CEnvironment() |
|
70 { |
|
71 RemoveAll(); |
|
72 iLock.Close(); |
|
73 } |
|
74 |
|
75 EXPORT_C void CEnvironment::RemoveAll() |
|
76 { |
|
77 // Note this doesn't affect iParentEnv |
|
78 if (iLock.Handle()) |
|
79 { |
|
80 iLock.Wait(); |
|
81 TStringHashIter<HBufC*> iter(iVars); |
|
82 while (iter.NextValue() != NULL) |
|
83 { |
|
84 delete *iter.CurrentValue(); |
|
85 } |
|
86 iVars.Close(); |
|
87 iLock.Signal(); |
|
88 } |
|
89 } |
|
90 |
|
91 CEnvironment::CEnvironment() |
|
92 { |
|
93 __ASSERT_COMPILE(sizeof(iVarsImpl) == sizeof(RStringHash<HBufC*>)); |
|
94 // Have to placement new iVars because we hide the type |
|
95 new(iVarsImpl) RStringHash<HBufC*>; |
|
96 } |
|
97 |
|
98 CEnvironment::CEnvironment(CEnvironment* aParentEnv) |
|
99 : iParentEnv(aParentEnv) |
|
100 { |
|
101 new(iVarsImpl) RStringHash<HBufC*>; |
|
102 } |
|
103 |
|
104 void CEnvironment::ConstructL() |
|
105 { |
|
106 User::LeaveIfError(iLock.CreateLocal()); |
|
107 } |
|
108 |
|
109 void CEnvironment::Lock() const |
|
110 { |
|
111 iLock.Wait(); |
|
112 if (iParentEnv) iParentEnv->iLock.Wait(); |
|
113 } |
|
114 |
|
115 void CEnvironment::Unlock() const |
|
116 { |
|
117 if (iParentEnv) iParentEnv->iLock.Signal(); |
|
118 iLock.Signal(); |
|
119 } |
|
120 |
|
121 void CEnvironment::WaitLC() const |
|
122 { |
|
123 Lock(); |
|
124 CleanupStack::PushL(TCleanupItem(Signal, const_cast<CEnvironment*>(this))); |
|
125 } |
|
126 |
|
127 void CEnvironment::Signal(TAny* aSelf) |
|
128 { |
|
129 static_cast<CEnvironment*>(aSelf)->Unlock(); |
|
130 } |
|
131 |
|
132 EXPORT_C void CEnvironment::SetL(const TDesC& aKey, TInt aValue) |
|
133 { |
|
134 TBuf<32> buf; |
|
135 buf.AppendNum(aValue); |
|
136 SetL(aKey, buf); |
|
137 } |
|
138 |
|
139 EXPORT_C void CEnvironment::SetL(const TDesC& aKey, const TDesC& aValue) |
|
140 { |
|
141 WaitLC(); |
|
142 |
|
143 HBufC** valPtr = iVars.Find(aKey); |
|
144 HBufC* currentValue = NULL; |
|
145 if (valPtr) currentValue = *valPtr; |
|
146 |
|
147 if (valPtr == NULL && iParentEnv) |
|
148 { |
|
149 // If we don't have it, and we have a parent env, we should pass the request through to it. |
|
150 iParentEnv->SetL(aKey, aValue); |
|
151 } |
|
152 else |
|
153 { |
|
154 if (currentValue) |
|
155 { |
|
156 // If we already have a value in the hash, just update it if possible |
|
157 TPtr ptr = currentValue->Des(); |
|
158 if (ptr.MaxLength() >= aValue.Length()) |
|
159 { |
|
160 ptr.Copy(aValue); |
|
161 CleanupStack::PopAndDestroy(); // Release lock |
|
162 return; |
|
163 } |
|
164 } |
|
165 } |
|
166 |
|
167 HBufC* newVal = aValue.AllocLC(); |
|
168 iVars.InsertL(aKey, newVal); |
|
169 delete currentValue; |
|
170 CleanupStack::Pop(newVal); |
|
171 CleanupStack::PopAndDestroy(); // Release lock |
|
172 } |
|
173 |
|
174 HBufC* CEnvironment::Get(const TDesC& aKey) const |
|
175 { |
|
176 HBufC*const* valPtr = iConstVars.Find(aKey); |
|
177 if (valPtr == NULL && iParentEnv) |
|
178 { |
|
179 return iParentEnv->Get(aKey); |
|
180 } |
|
181 else if (valPtr) |
|
182 { |
|
183 return *valPtr; |
|
184 } |
|
185 else |
|
186 { |
|
187 return NULL; |
|
188 } |
|
189 } |
|
190 |
|
191 HBufC* CEnvironment::GetL(const TDesC& aKey) const |
|
192 { |
|
193 HBufC* var = Get(aKey); |
|
194 if (var == NULL) User::Leave(KErrNotFound); |
|
195 return var; |
|
196 } |
|
197 |
|
198 EXPORT_C TInt CEnvironment::GetAsInt(const TDesC& aKey) const |
|
199 { |
|
200 Lock(); |
|
201 HBufC* var = Get(aKey); |
|
202 __ASSERT_ALWAYS(var, Panic(EEnvVarNotFound1)); |
|
203 TLex lex(*var); |
|
204 TInt result = 0; |
|
205 lex.Val(result); |
|
206 Unlock(); |
|
207 return result; |
|
208 } |
|
209 |
|
210 EXPORT_C TInt CEnvironment::GetAsIntL(const TDesC& aKey) const |
|
211 { |
|
212 WaitLC(); |
|
213 HBufC* var = GetL(aKey); |
|
214 TLex lex(*var); |
|
215 TInt ret = 0; |
|
216 lex.Val(ret); |
|
217 CleanupStack::PopAndDestroy(); // Release lock |
|
218 return ret; |
|
219 } |
|
220 |
|
221 EXPORT_C const TDesC& CEnvironment::GetAsDes(const TDesC& aKey) const |
|
222 { |
|
223 Lock(); |
|
224 HBufC* var = Get(aKey); |
|
225 __ASSERT_ALWAYS(var, Panic(EEnvVarNotFound2)); |
|
226 Unlock(); |
|
227 return *var; |
|
228 } |
|
229 |
|
230 EXPORT_C const TDesC& CEnvironment::GetAsDesL(const TDesC& aKey) const |
|
231 { |
|
232 WaitLC(); |
|
233 const TDesC& des = *GetL(aKey); |
|
234 CleanupStack::PopAndDestroy(); // Release lock |
|
235 return des; |
|
236 } |
|
237 |
|
238 EXPORT_C TInt CEnvironment::Remove(const TDesC& aKey) |
|
239 { |
|
240 Lock(); |
|
241 HBufC** valPtr = iVars.Find(aKey); |
|
242 |
|
243 TInt ret = KErrNone; |
|
244 if (valPtr == NULL && iParentEnv) |
|
245 { |
|
246 // Not in ours, look at parent env |
|
247 ret = iParentEnv->Remove(aKey); |
|
248 } |
|
249 else if (valPtr && *valPtr) |
|
250 { |
|
251 // In ours |
|
252 delete *valPtr; |
|
253 if (iParentEnv) |
|
254 { |
|
255 // Need to remember we've removed it |
|
256 *valPtr = NULL; |
|
257 } |
|
258 else |
|
259 { |
|
260 iVars.Remove(aKey); |
|
261 } |
|
262 } |
|
263 else |
|
264 { |
|
265 // Not in ours and no parent env, or in ours and null |
|
266 ret = KErrNotFound; |
|
267 } |
|
268 |
|
269 Unlock(); |
|
270 return ret; |
|
271 } |
|
272 |
|
273 EXPORT_C void CEnvironment::RemoveL(const TDesC& aKey) |
|
274 { |
|
275 User::LeaveIfError(Remove(aKey)); |
|
276 } |
|
277 |
|
278 void CEnvironment::CopyL(const CEnvironment& aEnv) |
|
279 { |
|
280 RemoveAll(); |
|
281 WaitLC(); |
|
282 aEnv.WaitLC(); |
|
283 |
|
284 RPointerArray<HBufC> keys; |
|
285 LtkUtils::CleanupResetAndDestroyPushL(keys); |
|
286 aEnv.GetKeysL(keys); |
|
287 for (TInt i = 0; i < keys.Count(); i++) |
|
288 { |
|
289 SetL(*keys[i], aEnv.GetAsDes(*keys[i])); |
|
290 } |
|
291 |
|
292 CleanupStack::PopAndDestroy(3); // keys, WaitLC x 2. |
|
293 } |
|
294 |
|
295 class TDesRead |
|
296 { |
|
297 public: |
|
298 TDesRead(const TDesC8& aDes); |
|
299 TInt32 ReadInt32(); |
|
300 TPtrC ReadDes(); |
|
301 private: |
|
302 const TDesC8& iDes; |
|
303 TInt iPos; |
|
304 }; |
|
305 class TDesWrite |
|
306 { |
|
307 public: |
|
308 TDesWrite(LtkUtils::RLtkBuf8& aDes); |
|
309 void WriteL(TInt32 aInt); |
|
310 void WriteL(const TDesC& aDes); |
|
311 private: |
|
312 LtkUtils::RLtkBuf8& iDes; |
|
313 }; |
|
314 |
|
315 EXPORT_C void CEnvironment::InternalizeL(const TDesC8& aDes) |
|
316 { |
|
317 WaitLC(); |
|
318 |
|
319 TDesRead desRead(aDes); |
|
320 TInt varCount = desRead.ReadInt32(); |
|
321 while (varCount--) |
|
322 { |
|
323 TPtrC key = desRead.ReadDes(); |
|
324 TPtrC val = desRead.ReadDes(); |
|
325 SetL(key, val); |
|
326 } |
|
327 |
|
328 CleanupStack::PopAndDestroy(); // Release lock |
|
329 } |
|
330 |
|
331 EXPORT_C HBufC8* CEnvironment::ExternalizeLC() const |
|
332 { |
|
333 WaitLC(); |
|
334 LtkUtils::RLtkBuf8 buf; |
|
335 CleanupClosePushL(buf); |
|
336 TDesWrite desWrite(buf); |
|
337 |
|
338 RPointerArray<HBufC> keys; |
|
339 LtkUtils::CleanupResetAndDestroyPushL(keys); |
|
340 GetKeysL(keys); |
|
341 desWrite.WriteL(keys.Count()); |
|
342 for (TInt i = 0; i < keys.Count(); i++) |
|
343 { |
|
344 desWrite.WriteL(*keys[i]); |
|
345 desWrite.WriteL(GetAsDes(*keys[i])); |
|
346 } |
|
347 CleanupStack::PopAndDestroy(&keys); |
|
348 CleanupStack::Pop(&buf); |
|
349 CleanupStack::PopAndDestroy(); // Release lock |
|
350 HBufC8* res = buf.ToHBuf(); |
|
351 CleanupStack::PushL(res); |
|
352 return res; |
|
353 } |
|
354 |
|
355 TInt StringCompare(const HBufC& aLeft, const HBufC& aRight) |
|
356 { |
|
357 return aLeft.Compare(aRight); |
|
358 } |
|
359 |
|
360 EXPORT_C void CEnvironment::GetKeysL(RPointerArray<HBufC>& aResult) const |
|
361 { |
|
362 WaitLC(); |
|
363 aResult.ResetAndDestroy(); |
|
364 TStringHashIter<HBufC*> iter(iConstVars); |
|
365 while (iter.NextValue() != NULL) |
|
366 { |
|
367 if (*iter.CurrentValue() != NULL) |
|
368 { |
|
369 HBufC* key = iter.CurrentKey()->AllocLC(); |
|
370 aResult.AppendL(key); |
|
371 CleanupStack::Pop(key); |
|
372 } |
|
373 } |
|
374 |
|
375 if (iParentEnv) |
|
376 { |
|
377 RPointerArray<HBufC> parentKeys; |
|
378 LtkUtils::CleanupResetAndDestroyPushL(parentKeys); |
|
379 iParentEnv->GetKeysL(parentKeys); |
|
380 for (TInt i = parentKeys.Count()-1; i >= 0; i--) |
|
381 { |
|
382 HBufC* key = parentKeys[i]; |
|
383 if (iConstVars.Find(*key) == NULL) |
|
384 { |
|
385 // Only add stuff in parent that isn't also in ours |
|
386 aResult.AppendL(key); |
|
387 parentKeys.Remove(i); |
|
388 } |
|
389 } |
|
390 CleanupStack::PopAndDestroy(&parentKeys); |
|
391 } |
|
392 |
|
393 // Make sure the resulting array is alphabetic, as RStringHash doesn't guarantee that (unlike RVarSet) |
|
394 aResult.Sort(TLinearOrder<HBufC>(&StringCompare)); |
|
395 CleanupStack::PopAndDestroy(); // Release lock |
|
396 } |
|
397 |
|
398 EXPORT_C TBool CEnvironment::IsDefined(const TDesC& aKey) const |
|
399 { |
|
400 iLock.Wait(); |
|
401 TBool ret = (Get(aKey) != NULL); |
|
402 iLock.Signal(); |
|
403 return ret; |
|
404 } |
|
405 |
|
406 EXPORT_C TBool CEnvironment::IsInt(const TDesC& aKey) const |
|
407 { |
|
408 iLock.Wait(); |
|
409 HBufC* val = Get(aKey); |
|
410 iLock.Signal(); |
|
411 |
|
412 if (val == NULL) return EFalse; |
|
413 |
|
414 TLex lex(*val); |
|
415 TBool atLeastOneDigit(EFalse); |
|
416 while (!lex.Eos()) |
|
417 { |
|
418 if (lex.Get().IsDigit()) |
|
419 { |
|
420 atLeastOneDigit = ETrue; |
|
421 } |
|
422 else |
|
423 { |
|
424 return EFalse; |
|
425 } |
|
426 } |
|
427 return atLeastOneDigit; |
|
428 } |
|
429 |
|
430 EXPORT_C TBool CEnvironment::IsDes(const TDesC& aKey) const |
|
431 { |
|
432 return IsDefined(aKey); |
|
433 } |
|
434 |
|
435 EXPORT_C TInt CEnvironment::Count() const |
|
436 { |
|
437 iLock.Wait(); |
|
438 TInt ret = iConstVars.Count(); |
|
439 iLock.Signal(); |
|
440 return ret; |
|
441 } |
|
442 |
|
443 EXPORT_C void CEnvironment::SetPwdL(const TDesC& aPwd) |
|
444 { |
|
445 SetL(KEnvPwd, aPwd); |
|
446 } |
|
447 |
|
448 EXPORT_C const TDesC& CEnvironment::Pwd() const |
|
449 { |
|
450 return GetAsDes(KEnvPwd); |
|
451 } |
|
452 |
|
453 EXPORT_C TChar CEnvironment::EscapeChar() const |
|
454 { |
|
455 iLock.Wait(); |
|
456 HBufC* var = Get(KEnvEscapeChar); |
|
457 TUint16 escape = '^'; |
|
458 if (var) |
|
459 { |
|
460 escape = (*var)[0]; |
|
461 } |
|
462 iLock.Signal(); |
|
463 return TChar(escape); |
|
464 } |
|
465 |
|
466 // Declare aKey so that changes aren't reflected in the parent environment |
|
467 EXPORT_C void CEnvironment::SetLocalL(const TDesC& aKey) |
|
468 { |
|
469 if (iParentEnv == NULL) |
|
470 { |
|
471 // Nothing needed if there is no parent, then everything is effectively local anyway |
|
472 return; |
|
473 } |
|
474 |
|
475 WaitLC(); |
|
476 HBufC** currentValPtr = iVars.Find(aKey); |
|
477 if (currentValPtr) |
|
478 { |
|
479 // It's already local |
|
480 CleanupStack::PopAndDestroy(); // Release lock |
|
481 return; |
|
482 } |
|
483 |
|
484 // Local vals start out undefined, regardless of what the parent's value is |
|
485 iVars.InsertL(aKey, NULL); |
|
486 |
|
487 CleanupStack::PopAndDestroy(); // Release lock |
|
488 } |
|
489 |
|
490 // |
|
491 // TDesRead. |
|
492 // |
|
493 |
|
494 TDesRead::TDesRead(const TDesC8& aDes) |
|
495 : iDes(aDes), iPos(0) |
|
496 { |
|
497 } |
|
498 |
|
499 TInt32 TDesRead::ReadInt32() |
|
500 { |
|
501 TInt32 int32; |
|
502 TPckg<TInt32> intPckg(int32); |
|
503 intPckg.Copy(iDes.Mid(iPos, sizeof(TInt32))); |
|
504 iPos += sizeof(TInt32); |
|
505 return int32; |
|
506 } |
|
507 |
|
508 TPtrC TDesRead::ReadDes() |
|
509 { |
|
510 const TInt length = ReadInt32(); |
|
511 const TInt size = length * 2; |
|
512 if (iPos & 1) iPos++; // 16-bit descriptors are 2-byte aligned |
|
513 TPtrC8 ptr8 = iDes.Mid(iPos, size); |
|
514 TPtrC result((const TUint16*)ptr8.Ptr(), length); |
|
515 iPos += size; |
|
516 return result; |
|
517 } |
|
518 |
|
519 |
|
520 // |
|
521 // TDesWrite. |
|
522 // |
|
523 |
|
524 TDesWrite::TDesWrite(LtkUtils::RLtkBuf8& aDes) |
|
525 : iDes(aDes) |
|
526 { |
|
527 } |
|
528 |
|
529 void TDesWrite::WriteL(TInt32 aInt) |
|
530 { |
|
531 TPckgC<TInt32> intPckg(aInt); |
|
532 iDes.AppendL(intPckg); |
|
533 } |
|
534 |
|
535 void TDesWrite::WriteL(const TDesC& aDes) |
|
536 { |
|
537 WriteL(aDes.Length()); |
|
538 if (iDes.Size() & 1) iDes.AppendL('.'); // Pad so the desc is 2-byte aligned |
|
539 TPtrC8 ptr((TUint8*)aDes.Ptr(), aDes.Size()); |
|
540 iDes.AppendL(ptr); |
|
541 } |
|
542 |