ReactOS 0.4.15-dev-8434-g155a7c7
set.c
Go to the documentation of this file.
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 hardcoded strings in En.rc
35 */
36
37#include "precomp.h"
38
39#ifdef INCLUDE_CMD_SET
40
41/* Initial size of environment variable buffer */
42#define ENV_BUFFER_SIZE 1024
43
44static BOOL
46
47static LPCTSTR
49{
50 while (*p && *p <= _T(' '))
51 ++p;
52 return p;
53}
54
55/* Used to check for and handle:
56 * SET "var=value", SET /P "var=prompt", and SET /P var="prompt" */
57static LPTSTR
59{
60 TCHAR *end;
61 if (*p == _T('"'))
62 {
63 p = (LPTSTR)skip_ws(p + 1);
64 /* If a matching quote is found, truncate the string */
65 end = _tcsrchr(p, _T('"'));
66 if (end)
67 *end = _T('\0');
68 }
69 return p;
70}
71
73{
74 INT retval = 0;
75 LPTSTR p;
76 LPTSTR lpEnv;
77 LPTSTR lpOutput;
78
79 if (!_tcsncmp(param, _T("/?"), 2))
80 {
82 return 0;
83 }
84
86
87 /* If no parameters, show the environment */
88 if (param[0] == _T('\0'))
89 {
91 if (lpEnv)
92 {
93 lpOutput = lpEnv;
94 while (*lpOutput)
95 {
96 /* Do not display the special '=X:' environment variables */
97 if (*lpOutput != _T('='))
98 {
99 ConOutPuts(lpOutput);
100 ConOutChar(_T('\n'));
101 }
102 lpOutput += _tcslen(lpOutput) + 1;
103 }
105 }
106
107 retval = 0;
108 goto Quit;
109 }
110
111 /* The /A does *NOT* have to be followed by a whitespace */
112 if (!_tcsnicmp(param, _T("/A"), 2))
113 {
115
116 /* Save error level since seta_eval() modifies it, as
117 * we need to set it later according to specific rules. */
118 INT nOldErrorLevel = nErrorLevel;
119
122 if (!Success)
123 {
124#if 0
125 /* Might seem random but this is what windows xp does -- This is a message ID */
126 retval = 9165;
127#endif
128 retval = nErrorLevel;
129 nErrorLevel = nOldErrorLevel;
130 }
131 else
132 {
133 retval = 0;
134 }
135 goto Quit;
136 }
137
138 if (!_tcsnicmp(param, _T("/P"), 2))
139 {
140 TCHAR value[1023];
142 p = _tcschr(param, _T('='));
143 if (!p)
144 {
146 retval = 1;
147 goto Quit;
148 }
149
150 *p++ = _T('\0');
153
155 {
156 retval = 1;
157 goto Quit;
158 }
159 retval = 0;
160 goto Quit;
161 }
162
164
165 p = _tcschr(param, _T('='));
166 if (p)
167 {
168 /* Set or remove the environment variable */
169 if (p == param)
170 {
171 /* Handle set =val case */
173 retval = 1;
174 goto Quit;
175 }
176
177 *p++ = _T('\0');
178
179#ifdef FEATURE_DYNAMIC_TRACE
180 /* Check for dynamic TRACE ON/OFF */
181 if (!_tcsicmp(param, _T("CMDTRACE")))
182 g_bDynamicTrace = !_tcsicmp(p, _T("ON"));
183#endif
184
185 if (!SetEnvironmentVariable(param, *p ? p : NULL))
186 {
187 retval = 1;
188 goto Quit;
189 }
190 }
191 else
192 {
193 /* Display all the environment variables with the given prefix */
194 LPTSTR pOrgParam = param;
195 BOOLEAN bFound = FALSE;
196 BOOLEAN bRestoreSpace;
197
198 /*
199 * Trim the prefix from "special" characters (only when displaying the
200 * environment variables), so that e.g. "SET ,; ,;FOO" will display all
201 * the variables starting by "FOO".
202 * The SET command allows as well to set an environment variable whose name
203 * actually contains these characters (e.g. "SET ,; ,;FOO=42"); however,
204 * by trimming the characters, doing "SET ,; ,;FOO" would not allow seeing
205 * such variables.
206 * Thus, we also save a pointer to the original variable name prefix, that
207 * we will look it up as well below.
208 */
209 while (_istspace(*param) || *param == _T(',') || *param == _T(';'))
210 ++param;
211
212 /* Just remove the very last space, if present */
213 p = _tcsrchr(param, _T(' '));
214 bRestoreSpace = (p != NULL);
215 if (!p)
216 p = param + _tcslen(param);
217 *p = _T('\0');
218
219 lpEnv = GetEnvironmentStrings();
220 if (lpEnv)
221 {
222 lpOutput = lpEnv;
223 while (*lpOutput)
224 {
225 /* Look up for both the original and truncated variable name prefix */
226 if (!_tcsnicmp(lpOutput, pOrgParam, p - pOrgParam) ||
227 !_tcsnicmp(lpOutput, param, p - param))
228 {
229 ConOutPuts(lpOutput);
230 ConOutChar(_T('\n'));
231 bFound = TRUE;
232 }
233 lpOutput += _tcslen(lpOutput) + 1;
234 }
236 }
237
238 /* Restore the truncated space for correctly
239 * displaying the error message, if any. */
240 if (bRestoreSpace)
241 *p = _T(' ');
242
243 if (!bFound)
244 {
246 retval = 1;
247 goto Quit;
248 }
249 }
250
251Quit:
252 if (BatType != CMD_TYPE)
253 {
254 if (retval != 0)
255 nErrorLevel = retval;
256 }
257 else
258 {
259 nErrorLevel = retval;
260 }
261
262 return retval;
263}
264
265static INT
267{
268 LPCTSTR p2 = p;
269 if (__iscsymf(*p))
270 {
271 ++p2;
272 while (__iscsym(*p2))
273 ++p2;
274 }
275 return (INT)(p2-p);
276}
277
278#define PARSE_IDENT(ident, identlen, p) \
279do { \
280 identlen = ident_len(p); \
281 ident = (LPTSTR)alloca((identlen + 1) * sizeof(TCHAR)); \
282 memmove(ident, p, identlen * sizeof(TCHAR)); \
283 ident[identlen] = 0; \
284 p += identlen; \
285} while (0)
286
287static INT
289{
290 LPCTSTR identVal = GetEnvVarOrSpecial(ident);
291 if (!identVal)
292 return 0;
293 else
294 return _tcstol(identVal, NULL, 0);
295}
296
297static BOOL
299{
300 switch (op)
301 {
302 case '*':
303 *lval *= rval;
304 break;
305
306 case '/':
307 {
308 if (rval == 0)
309 {
311 nErrorLevel = 0x400023D1; // 1073750993;
312 return FALSE;
313 }
314 *lval /= rval;
315 break;
316 }
317
318 case '%':
319 {
320 if (rval == 0)
321 {
323 nErrorLevel = 0x400023D1; // 1073750993;
324 return FALSE;
325 }
326 *lval %= rval;
327 break;
328 }
329
330 case '+':
331 *lval += rval;
332 break;
333 case '-':
334 *lval -= rval;
335 break;
336 case '&':
337 *lval &= rval;
338 break;
339 case '^':
340 *lval ^= rval;
341 break;
342 case '|':
343 *lval |= rval;
344 break;
345
346 default:
348 nErrorLevel = 0x400023CE; // 1073750990;
349 return FALSE;
350 }
351 return TRUE;
352}
353
354static BOOL
356
357static BOOL
359{
360 LPCTSTR p = *p_;
361 INT rval;
362
363 if (*p == _T('('))
364 {
365 p = skip_ws(p + 1);
366 if (!seta_stmt(&p, &rval))
367 return FALSE;
368 if (*p++ != _T(')'))
369 {
371 nErrorLevel = 0x400023CC; // 1073750988;
372 return FALSE;
373 }
374 *result = rval;
375 }
376 else if (_istdigit(*p))
377 {
378 errno = 0;
379 rval = _tcstol(p, (LPTSTR*)&p, 0);
380
381 /* Check for overflow / underflow */
382 if (errno == ERANGE)
383 {
385 nErrorLevel = 0x400023D0; // 1073750992;
386 return FALSE;
387 }
388 /*
389 * _tcstol() stopped at the first non-digit character. If it's not a whitespace,
390 * or if it's the start of a possible identifier, this means the number being
391 * interpreted was invalid.
392 */
393 else if (*p && !_istspace(*p) && __iscsymf(*p))
394 {
396 nErrorLevel = 0x400023CF; // 1073750991;
397 return FALSE;
398 }
399 *result = rval;
400 }
401 else if (__iscsymf(*p))
402 {
404 INT identlen;
405 PARSE_IDENT(ident, identlen, p);
407 }
408 else
409 {
411 nErrorLevel = 0x400023CD; // 1073750989;
412 return FALSE;
413 }
414 *p_ = skip_ws(p);
415 return TRUE;
416}
417
418static BOOL
420{
421 LPCTSTR p = *p_;
422 TCHAR op = 0;
423 INT rval;
424
425 if (_tcschr(_T("!~-+"), *p))
426 {
427 op = *p;
428 p = skip_ws(p + 1);
429
430 if (!seta_mulTerm(&p, &rval))
431 return FALSE;
432
433 switch (op)
434 {
435 case '!':
436 rval = !rval;
437 break;
438 case '~':
439 rval = ~rval;
440 break;
441 case '-':
442 rval = -rval;
443 break;
444#if 0
445 case '+':
446 rval = rval;
447 break;
448#endif
449 }
450 }
451 else
452 {
453 if (!seta_unaryTerm(&p, &rval))
454 return FALSE;
455 }
456
457 *result = rval;
458 *p_ = p;
459 return TRUE;
460}
461
462static BOOL
464{
465 LPCTSTR p = *p_;
466 INT lval;
467
468 /* Evaluate the left-hand side */
469 if (!subTerm(&p, &lval))
470 return FALSE;
471
472 while (*p && _tcschr(ops, *p))
473 {
474 INT rval;
475 TCHAR op = *p;
476
477 p = skip_ws(p + 1);
478
479 /* Evaluate the immediate right-hand side */
480 if (!subTerm(&p, &rval))
481 return FALSE;
482
483 /* This becomes the new left-hand side for the next iteration */
484 if (!calc(&lval, op, rval))
485 return FALSE;
486 }
487
488 *result = lval;
489 *p_ = p;
490 return TRUE;
491}
492
493static BOOL
495{
496 return seta_ltorTerm(p_, result, _T("*/%"), seta_mulTerm);
497}
498
499static BOOL
501{
502 return seta_ltorTerm(p_, result, _T("+-"), seta_addTerm);
503}
504
505static BOOL
507{
508 LPCTSTR p = *p_;
509 INT lval;
510
511 /* Evaluate the left-hand side */
512 if (!seta_logShiftTerm(&p, &lval))
513 return FALSE;
514
515 /* Handle << >> operators */
516 while (*p && _tcschr(_T("<>"), *p))
517 {
518 INT rval;
519 TCHAR op = *p;
520
521 /* Check whether the next non-whitespace character is the same operator */
522 p = skip_ws(p + 1);
523 if (*p != op)
524 break;
525
526 /* Skip it */
527 p = skip_ws(p + 1);
528
529 /* Evaluate the immediate right-hand side */
530 if (!seta_logShiftTerm(&p, &rval))
531 return FALSE;
532
533 /* This becomes the new left-hand side for the next iteration */
534 switch (op)
535 {
536 case '<':
537 {
538 /* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
539 * which differs from the compiler (for example gcc) so being explicit. */
540 if (rval < 0 || rval >= (8 * sizeof(lval)))
541 lval = 0;
542 else
543 lval <<= rval;
544 break;
545 }
546
547 case '>':
548 lval >>= rval;
549 break;
550
551 default:
553 nErrorLevel = 0x400023CE; // 1073750990;
554 return FALSE;
555 }
556 }
557
558 *result = lval;
559 *p_ = p;
560 return TRUE;
561}
562
563static BOOL
565{
566 return seta_ltorTerm(p_, result, _T("&"), seta_bitAndTerm);
567}
568
569static BOOL
571{
572 return seta_ltorTerm(p_, result, _T("^"), seta_bitExclOrTerm);
573}
574
575static BOOL
577{
578 return seta_ltorTerm(p_, result, _T("|"), seta_bitOrTerm);
579}
580
581static BOOL
583{
584 LPCTSTR p = *p_;
586 TCHAR op = 0;
587 INT identlen, exprval;
588
589 PARSE_IDENT(ident, identlen, p);
590 if (identlen)
591 {
592 p = skip_ws(p);
593
594 /* Handle = assignment */
595 if (*p == _T('='))
596 {
597 op = *p;
598 p = skip_ws(p + 1);
599 }
600 /* Handle *= /= %= += -= &= ^= |= assignments */
601 else if (_tcschr(_T("*/%+-&^|"), *p))
602 {
603 op = *p;
604
605 /* Find the '=', there may be some spaces before it */
606 p = skip_ws(p + 1);
607 if (*p != _T('='))
608 {
609 op = 0;
610 goto evaluate;
611 }
612
613 /* Skip it */
614 p = skip_ws(p + 1);
615 }
616 /* Handle <<= >>= assignments */
617 else if (_tcschr(_T("<>"), *p))
618 {
619 op = *p;
620
621 /* Check whether the next non-whitespace character is the same operator */
622 p = skip_ws(p + 1);
623 if (*p != op)
624 {
625 op = 0;
626 goto evaluate;
627 }
628
629 /* Find the '=', there may be some spaces before it */
630 p = skip_ws(p + 1);
631 if (*p != _T('='))
632 {
633 op = 0;
634 goto evaluate;
635 }
636
637 /* Skip it */
638 p = skip_ws(p + 1);
639 }
640 }
641
642evaluate:
643 /* Allow to chain multiple assignments, such as: a=b=1 */
644 if (ident && op)
645 {
646 INT identval;
647 LPTSTR buf;
648
649 if (!seta_assignment(&p, &exprval))
650 return FALSE;
651
652 identval = seta_identval(ident);
653
654 switch (op)
655 {
656 /* Handle = assignment */
657 case '=':
658 identval = exprval;
659 break;
660
661 /* Handle <<= assignment */
662 case '<':
663 {
664 /* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
665 * which differs from the compiler (for example gcc) so being explicit. */
666 if (exprval < 0 || exprval >= (8 * sizeof(identval)))
667 identval = 0;
668 else
669 identval <<= exprval;
670 break;
671 }
672
673 /* Handle >>= assignment */
674 case '>':
675 identval >>= exprval;
676 break;
677
678 /* Other assignments */
679 default:
680 if (!calc(&identval, op, exprval))
681 return FALSE;
682 }
683
684 buf = (LPTSTR)alloca(32 * sizeof(TCHAR));
685 _sntprintf(buf, 32, _T("%i"), identval);
686 SetEnvironmentVariable(ident, buf); // TODO FIXME - check return value
687 exprval = identval;
688 }
689 else
690 {
691 /* Restore p in case we found an identifier but not an operator */
692 p = *p_;
693 if (!seta_expr(&p, &exprval))
694 return FALSE;
695 }
696
697 *result = exprval;
698 *p_ = p;
699 return TRUE;
700}
701
702static BOOL
704{
705 LPCTSTR p = *p_;
706 INT rval;
707
708 if (!seta_assignment(&p, &rval))
709 return FALSE;
710
711 /* Loop over each statement */
712 while (*p == _T(','))
713 {
714 p = skip_ws(p + 1);
715
716 if (!seta_assignment(&p, &rval))
717 return FALSE;
718 }
719
720 *result = rval;
721 *p_ = p;
722 return TRUE;
723}
724
725static BOOL
727{
728 INT rval;
729
730 if (!*p)
731 {
733 nErrorLevel = 1;
734 return FALSE;
735 }
736 if (!seta_stmt(&p, &rval))
737 return FALSE;
738
739 /* If unparsed data remains, fail and bail out */
740 if (*p)
741 {
742 ConErrResPuts(STRING_SYNTAX_COMMAND_INCORRECT); // Actually syntax error / missing operand.
743 nErrorLevel = 0x400023CE; // 1073750990;
744 return FALSE;
745 }
746
747 /* Echo the result of the evaluation only in interactive (non-batch) mode */
748 if (!bc)
749 ConOutPrintf(_T("%i"), rval);
750
751 return TRUE;
752}
753
754#endif
unsigned char BOOLEAN
#define ERANGE
Definition: acclib.h:92
PBATCH_CONTEXT bc
Definition: batch.c:67
BATCH_TYPE BatType
Definition: batch.c:66
INT nErrorLevel
Definition: cmd.c:158
LPCTSTR GetEnvVarOrSpecial(LPCTSTR varName)
Definition: cmd.c:904
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
#define ConErrResPuts(uID)
Definition: console.h:38
#define ConOutPrintf(szStr,...)
Definition: console.h:41
#define ConErrResPrintf(uID,...)
Definition: console.h:50
#define ConOutPuts(szStr)
Definition: console.h:29
BOOL g_bDynamicTrace
Definition: trace.c:13
#define STRING_ERROR_INVALID_NUMBER2
Definition: resource.h:19
#define STRING_INVALID_OPERAND
Definition: resource.h:217
#define STRING_EXPECTED_CLOSE_PAREN
Definition: resource.h:218
#define STRING_ERROR_INVALID_NUMBER1
Definition: resource.h:18
#define STRING_ERROR_DIVISION_BY_ZERO
Definition: resource.h:20
#define STRING_SYNTAX_COMMAND_INCORRECT
Definition: resource.h:220
#define STRING_SET_ENV_ERROR
Definition: resource.h:62
#define STRING_EXPECTED_NUMBER_OR_VARIABLE
Definition: resource.h:219
#define STRING_SET_HELP
Definition: resource.h:173
@ CMD_TYPE
Definition: batch.h:19
calc_t calc
Definition: winmain.c:247
static VOID StripQuotes(LPSTR in)
Definition: cmdcons.c:116
float rval
Definition: cylfrac.c:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
UINT op
Definition: effect.c:236
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
@ Success
Definition: eventcreate.c:712
unsigned int BOOL
Definition: ntddk_ex.h:94
GLuint GLuint end
Definition: gl.h:1545
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLfloat GLfloat p
Definition: glext.h:8902
GLfloat param
Definition: glext.h:5796
GLuint64EXT * result
Definition: glext.h:11304
#define __iscsym(_c)
Definition: ctype.h:691
#define __iscsymf(_c)
Definition: ctype.h:690
#define _istspace
Definition: tchar.h:1504
#define _istdigit
Definition: tchar.h:1494
#define _tcsncmp
Definition: tchar.h:1428
#define _tcstol
Definition: tchar.h:594
#define _tcschr
Definition: tchar.h:1406
static VOID ConInString(LPWSTR lpInput, DWORD dwLength)
Definition: label.c:56
#define alloca
Definition: malloc.h:357
#define _tcsrchr
Definition: utility.h:116
VOID ConOutChar(TCHAR c)
Definition: util.c:233
#define errno
Definition: errno.h:18
static BOOL seta_bitOrTerm(LPCTSTR *p_, INT *result)
Definition: set.c:570
static INT seta_identval(LPCTSTR ident)
Definition: set.c:288
INT cmd_set(LPTSTR param)
Definition: set.c:72
static BOOL seta_assignment(LPCTSTR *p_, INT *result)
Definition: set.c:582
static BOOL seta_bitExclOrTerm(LPCTSTR *p_, INT *result)
Definition: set.c:564
static BOOL seta_mulTerm(LPCTSTR *p_, INT *result)
Definition: set.c:419
static BOOL seta_bitAndTerm(LPCTSTR *p_, INT *result)
Definition: set.c:506
static BOOL seta_expr(LPCTSTR *p_, INT *result)
Definition: set.c:576
static BOOL seta_eval(LPCTSTR expr)
Definition: set.c:726
static BOOL seta_addTerm(LPCTSTR *p_, INT *result)
Definition: set.c:494
static BOOL seta_stmt(LPCTSTR *p_, INT *result)
Definition: set.c:703
static BOOL seta_ltorTerm(LPCTSTR *p_, INT *result, LPCTSTR ops, BOOL(*subTerm)(LPCTSTR *, INT *))
Definition: set.c:463
static BOOL seta_unaryTerm(LPCTSTR *p_, INT *result)
Definition: set.c:358
#define PARSE_IDENT(ident, identlen, p)
Definition: set.c:278
static INT ident_len(LPCTSTR p)
Definition: set.c:266
static BOOL seta_logShiftTerm(LPCTSTR *p_, INT *result)
Definition: set.c:500
static LPTSTR GetQuotedString(TCHAR *p)
Definition: set.c:58
static LPCTSTR skip_ws(LPCTSTR p)
Definition: set.c:48
Definition: query.h:87
int32_t INT
Definition: typedefs.h:58
Definition: pdh_main.c:94
#define _T(x)
Definition: vfdio.h:22
#define FreeEnvironmentStrings
Definition: winbase.h:3796
LPSTR WINAPI GetEnvironmentStrings(void)
#define SetEnvironmentVariable
Definition: winbase.h:3908
_In_ ULONG _In_ ULONG_PTR ident
Definition: winddi.h:3994
char TCHAR
Definition: xmlstorage.h:189
#define _tcsnicmp
Definition: xmlstorage.h:207
const CHAR * LPCTSTR
Definition: xmlstorage.h:193
#define _sntprintf
Definition: xmlstorage.h:201
CHAR * LPTSTR
Definition: xmlstorage.h:192
#define _tcslen
Definition: xmlstorage.h:198
#define _tcsicmp
Definition: xmlstorage.h:205