some more win32k 64 bit fixes
[reactos.git] / reactos / base / shell / cmd / set.c
1 /*
2 * SET.C - set internal command.
3 *
4 *
5 * History:
6 *
7 * 06/14/97 (Tim Norman)
8 * changed static var in set() to a cmd_alloc'd space to pass to putenv.
9 * need to find a better way to do this, since it seems it is wasting
10 * memory when variables are redefined.
11 *
12 * 07/08/1998 (John P. Price)
13 * removed call to show_environment in set command.
14 * moved test for syntax before allocating memory in set command.
15 * misc clean up and optimization.
16 *
17 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
18 * added config.h include
19 *
20 * 28-Jul-1998 (John P Price <linux-guru@gcfl.net>)
21 * added set_env function to set env. variable without needing set command
22 *
23 * 09-Dec-1998 (Eric Kohl)
24 * Added help text ("/?").
25 *
26 * 24-Jan-1999 (Eric Kohl)
27 * Fixed Win32 environment handling.
28 * Unicode and redirection safe!
29 *
30 * 25-Feb-1999 (Eric Kohl)
31 * Fixed little bug.
32 *
33 * 30-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>)
34 * Remove all hardcode string to En.rc
35 */
36
37 #include <precomp.h>
38
39 #ifdef INCLUDE_CMD_SET
40
41
42 /* initial size of environment variable buffer */
43 #define ENV_BUFFER_SIZE 1024
44
45 static BOOL
46 seta_eval ( LPCTSTR expr );
47
48 static LPCTSTR
49 skip_ws ( LPCTSTR p )
50 {
51 return p + _tcsspn ( p, _T(" \t") );
52 }
53
54 INT cmd_set (LPTSTR cmd, LPTSTR param)
55 {
56 TCHAR szMsg[RC_STRING_MAX_SIZE];
57 INT i;
58 LPTSTR p;
59
60 if ( !_tcsncmp (param, _T("/?"), 2) )
61 {
62 ConOutResPaging(TRUE,STRING_SET_HELP);
63 return 0;
64 }
65
66 /* remove escapes */
67 if ( param[0] ) for ( i = 0; param[i+1]; i++ )
68 {
69 if ( param[i] == _T('^') )
70 {
71 memmove ( &param[i], &param[i+1], _tcslen(&param[i]) * sizeof(TCHAR) );
72 }
73 }
74
75 /* if no parameters, show the environment */
76 if (param[0] == _T('\0'))
77 {
78 LPTSTR lpEnv;
79 LPTSTR lpOutput;
80 INT len;
81
82 lpEnv = (LPTSTR)GetEnvironmentStrings ();
83 if (lpEnv)
84 {
85 lpOutput = lpEnv;
86 while (*lpOutput)
87 {
88 len = _tcslen(lpOutput);
89 if (len)
90 {
91 if (*lpOutput != _T('='))
92 ConOutPuts (lpOutput);
93 lpOutput += (len + 1);
94 }
95 }
96 FreeEnvironmentStrings (lpEnv);
97 }
98
99 return 0;
100 }
101
102 /* the /A does *NOT* have to be followed by a whitespace */
103 if ( !_tcsnicmp (param, _T("/A"), 2) )
104 {
105 BOOL Success = seta_eval ( skip_ws(param+2) );
106 if(!Success)
107 {
108 /*might seem random but this is what windows xp does */
109 nErrorLevel = 9165;
110 }
111 /* TODO FIXME - what are we supposed to return? */
112 return Success;
113 }
114
115 if ( !_tcsnicmp (param, _T("/"), 1) )
116 {
117 LoadString(CMD_ModuleHandle, STRING_SYNTAX_COMMAND_INCORRECT, szMsg, RC_STRING_MAX_SIZE);
118 ConErrPrintf (szMsg, param);
119 return 0;
120 }
121
122 p = _tcschr (param, _T('='));
123 if (p)
124 {
125 /* set or remove environment variable */
126 if (p == param)
127 {
128 /* handle set =val case */
129 LoadString(CMD_ModuleHandle, STRING_SYNTAX_COMMAND_INCORRECT, szMsg, RC_STRING_MAX_SIZE);
130 ConErrPrintf (szMsg, param);
131 return 0;
132 }
133
134 *p = _T('\0');
135 p++;
136 if (*p == _T('\0'))
137 {
138 p = NULL;
139 }
140 SetEnvironmentVariable (param, p);
141 }
142 else
143 {
144 /* display environment variable */
145 LPTSTR pszBuffer;
146 DWORD dwBuffer;
147
148 pszBuffer = (LPTSTR)cmd_alloc (ENV_BUFFER_SIZE * sizeof(TCHAR));
149 dwBuffer = GetEnvironmentVariable (param, pszBuffer, ENV_BUFFER_SIZE);
150 if (dwBuffer == 0)
151 {
152 LoadString(CMD_ModuleHandle, STRING_PATH_ERROR, szMsg, RC_STRING_MAX_SIZE);
153 ConErrPrintf (szMsg, param);
154 return 0;
155 }
156 else if (dwBuffer > ENV_BUFFER_SIZE)
157 {
158 pszBuffer = (LPTSTR)cmd_realloc (pszBuffer, dwBuffer * sizeof (TCHAR));
159 GetEnvironmentVariable (param, pszBuffer, dwBuffer);
160 }
161 ConOutPrintf (_T("%s\n"), pszBuffer);
162
163 cmd_free (pszBuffer);
164
165 return 0;
166 }
167
168 return 0;
169 }
170
171 static INT
172 ident_len ( LPCTSTR p )
173 {
174 LPCTSTR p2 = p;
175 if ( __iscsymf(*p) )
176 {
177 ++p2;
178 while ( __iscsym(*p2) )
179 ++p2;
180 }
181 return p2-p;
182 }
183
184 #define PARSE_IDENT(ident,identlen,p) \
185 identlen = ident_len(p); \
186 ident = (LPTSTR)alloca ( ( identlen + 1 ) * sizeof(TCHAR) ); \
187 memmove ( ident, p, identlen * sizeof(TCHAR) ); \
188 ident[identlen] = 0; \
189 p += identlen;
190
191 static BOOL
192 seta_identval ( LPCTSTR ident, INT* result )
193 {
194 LPCTSTR identVal = GetEnvVarOrSpecial ( ident );
195 if ( !identVal )
196 {
197 /* TODO FIXME - what to do upon failure? */
198 *result = 0;
199 return FALSE;
200 }
201 *result = _ttoi ( identVal );
202 return TRUE;
203 }
204
205 static BOOL
206 calc ( INT* lval, TCHAR op, INT rval )
207 {
208 switch ( op )
209 {
210 case '*':
211 *lval *= rval;
212 break;
213 case '/':
214 *lval /= rval;
215 break;
216 case '%':
217 *lval %= rval;
218 break;
219 case '+':
220 *lval += rval;
221 break;
222 case '-':
223 *lval -= rval;
224 break;
225 case '&':
226 *lval &= rval;
227 break;
228 case '^':
229 *lval ^= rval;
230 break;
231 case '|':
232 *lval |= rval;
233 break;
234 default:
235 ConErrResPuts ( STRING_INVALID_OPERAND );
236 return FALSE;
237 }
238 return TRUE;
239 }
240
241 static BOOL
242 seta_stmt ( LPCTSTR* p_, INT* result );
243
244 static BOOL
245 seta_unaryTerm ( LPCTSTR* p_, INT* result )
246 {
247 LPCTSTR p = *p_;
248 if ( *p == _T('(') )
249 {
250 INT rval;
251 p = skip_ws ( p + 1 );
252 if ( !seta_stmt ( &p, &rval ) )
253 return FALSE;
254 if ( *p != _T(')') )
255 {
256 ConErrResPuts ( STRING_EXPECTED_CLOSE_PAREN );
257 return FALSE;
258 }
259 *result = rval;
260 p = skip_ws ( p + 1 );
261 }
262 else if ( isdigit(*p) )
263 {
264 *result = _ttoi ( p );
265 p = skip_ws ( p + _tcsspn ( p, _T("1234567890") ) );
266 }
267 else if ( __iscsymf(*p) )
268 {
269 LPTSTR ident;
270 INT identlen;
271 PARSE_IDENT(ident,identlen,p);
272 if ( !seta_identval ( ident, result ) )
273 return FALSE;
274 }
275 else
276 {
277 ConErrResPuts ( STRING_EXPECTED_NUMBER_OR_VARIABLE );
278 return FALSE;
279 }
280 *p_ = p;
281 return TRUE;
282 }
283
284 static BOOL
285 seta_mulTerm ( LPCTSTR* p_, INT* result )
286 {
287 LPCTSTR p = *p_;
288 TCHAR op = 0;
289 INT rval;
290 if ( _tcschr(_T("!~-"),*p) )
291 {
292 op = *p;
293 p = skip_ws ( p + 1 );
294 }
295 if ( !seta_unaryTerm ( &p, &rval ) )
296 return FALSE;
297 switch ( op )
298 {
299 case '!':
300 rval = !rval;
301 break;
302 case '~':
303 rval = ~rval;
304 break;
305 case '-':
306 rval = -rval;
307 break;
308 }
309
310 *result = rval;
311 *p_ = p;
312 return TRUE;
313 }
314
315 static BOOL
316 seta_ltorTerm ( LPCTSTR* p_, INT* result, LPCTSTR ops, BOOL (*subTerm)(LPCTSTR*,INT*) )
317 {
318 LPCTSTR p = *p_;
319 INT lval;
320 if ( !subTerm ( &p, &lval ) )
321 return FALSE;
322 while ( *p && _tcschr(ops,*p) )
323 {
324 INT rval;
325 TCHAR op = *p;
326
327 p = skip_ws ( p+1 );
328
329 if ( !subTerm ( &p, &rval ) )
330 return FALSE;
331
332 if ( !calc ( &lval, op, rval ) )
333 return FALSE;
334 }
335
336 *result = lval;
337 *p_ = p;
338 return TRUE;
339 }
340
341 static BOOL
342 seta_addTerm ( LPCTSTR* p_, INT* result )
343 {
344 return seta_ltorTerm ( p_, result, _T("*/%"), seta_mulTerm );
345 }
346
347 static BOOL
348 seta_logShiftTerm ( LPCTSTR* p_, INT* result )
349 {
350 return seta_ltorTerm ( p_, result, _T("+-"), seta_addTerm );
351 }
352
353 static BOOL
354 seta_bitAndTerm ( LPCTSTR* p_, INT* result )
355 {
356 LPCTSTR p = *p_;
357 INT lval;
358 if ( !seta_logShiftTerm ( &p, &lval ) )
359 return FALSE;
360 while ( *p && _tcschr(_T("<>"),*p) && p[0] == p[1] )
361 {
362 INT rval;
363 TCHAR op = *p;
364
365 p = skip_ws ( p+2 );
366
367 if ( !seta_logShiftTerm ( &p, &rval ) )
368 return FALSE;
369
370 switch ( op )
371 {
372 case '<':
373 lval <<= rval;
374 break;
375 case '>':
376 lval >>= rval;
377 break;
378 default:
379 ConErrResPuts ( STRING_INVALID_OPERAND );
380 return FALSE;
381 }
382 }
383
384 *result = lval;
385 *p_ = p;
386 return TRUE;
387 }
388
389 static BOOL
390 seta_bitExclOrTerm ( LPCTSTR* p_, INT* result )
391 {
392 return seta_ltorTerm ( p_, result, _T("&"), seta_bitAndTerm );
393 }
394
395 static BOOL
396 seta_bitOrTerm ( LPCTSTR* p_, INT* result )
397 {
398 return seta_ltorTerm ( p_, result, _T("^"), seta_bitExclOrTerm );
399 }
400
401 static BOOL
402 seta_expr ( LPCTSTR* p_, INT* result )
403 {
404 return seta_ltorTerm ( p_, result, _T("|"), seta_bitOrTerm );
405 }
406
407 static BOOL
408 seta_assignment ( LPCTSTR* p_, INT* result )
409 {
410 LPCTSTR p = *p_;
411 LPTSTR ident;
412 TCHAR op = 0;
413 INT identlen, exprval;
414
415 PARSE_IDENT(ident,identlen,p);
416 if ( identlen )
417 {
418 if ( *p == _T('=') )
419 op = *p, p = skip_ws(p+1);
420 else if ( _tcschr ( _T("*/%+-&^|"), *p ) && p[1] == _T('=') )
421 op = *p, p = skip_ws(p+2);
422 else if ( _tcschr ( _T("<>"), *p ) && *p == p[1] && p[2] == _T('=') )
423 op = *p, p = skip_ws(p+3);
424 }
425
426 /* allow to chain multiple assignments, such as: a=b=1 */
427 if ( ident && op )
428 {
429 INT identval;
430 LPTSTR buf;
431
432 if ( !seta_assignment ( &p, &exprval ) )
433 return FALSE;
434
435 if ( !seta_identval ( ident, &identval ) )
436 identval = 0;
437 switch ( op )
438 {
439 case '=':
440 identval = exprval;
441 break;
442 case '<':
443 identval <<= exprval;
444 break;
445 case '>':
446 identval >>= exprval;
447 break;
448 default:
449 if ( !calc ( &identval, op, exprval ) )
450 return FALSE;
451 }
452 buf = (LPTSTR)alloca ( 32 * sizeof(TCHAR) );
453 _sntprintf ( buf, 32, _T("%i"), identval );
454 SetEnvironmentVariable ( ident, buf ); // TODO FIXME - check return value
455 exprval = identval;
456 }
457 else
458 {
459 /* restore p in case we found an ident but not an op */
460 p = *p_;
461 if ( !seta_expr ( &p, &exprval ) )
462 return FALSE;
463 }
464
465 *result = exprval;
466 *p_ = p;
467 return TRUE;
468 }
469
470 static BOOL
471 seta_stmt ( LPCTSTR* p_, INT* result )
472 {
473 LPCTSTR p = *p_;
474 INT rval;
475
476 if ( !seta_assignment ( &p, &rval ) )
477 return FALSE;
478 while ( *p == _T(',') )
479 {
480 p = skip_ws ( p+1 );
481
482 if ( !seta_assignment ( &p, &rval ) )
483 return FALSE;
484 }
485
486 *result = rval;
487 *p_ = p;
488 return TRUE;
489 }
490
491 static BOOL
492 seta_eval ( LPCTSTR p )
493 {
494 INT rval;
495 if ( !*p )
496 {
497 ConErrResPuts ( STRING_SYNTAX_COMMAND_INCORRECT );
498 return FALSE;
499 }
500 if ( !seta_stmt ( &p, &rval ) )
501 return FALSE;
502 ConOutPrintf ( _T("%i"), rval );
503 return TRUE;
504 }
505
506 #endif