ReactOS 0.4.15-dev-7711-g5627da4
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 if (!SetEnvironmentVariable(param, *p ? p : NULL))
179 {
180 retval = 1;
181 goto Quit;
182 }
183 }
184 else
185 {
186 /* Display all the environment variables with the given prefix */
187 LPTSTR pOrgParam = param;
188 BOOLEAN bFound = FALSE;
189 BOOLEAN bRestoreSpace;
190
191 /*
192 * Trim the prefix from "special" characters (only when displaying the
193 * environment variables), so that e.g. "SET ,; ,;FOO" will display all
194 * the variables starting by "FOO".
195 * The SET command allows as well to set an environment variable whose name
196 * actually contains these characters (e.g. "SET ,; ,;FOO=42"); however,
197 * by trimming the characters, doing "SET ,; ,;FOO" would not allow seeing
198 * such variables.
199 * Thus, we also save a pointer to the original variable name prefix, that
200 * we will look it up as well below.
201 */
202 while (_istspace(*param) || *param == _T(',') || *param == _T(';'))
203 ++param;
204
205 /* Just remove the very last space, if present */
206 p = _tcsrchr(param, _T(' '));
207 bRestoreSpace = (p != NULL);
208 if (!p)
209 p = param + _tcslen(param);
210 *p = _T('\0');
211
212 lpEnv = GetEnvironmentStrings();
213 if (lpEnv)
214 {
215 lpOutput = lpEnv;
216 while (*lpOutput)
217 {
218 /* Look up for both the original and truncated variable name prefix */
219 if (!_tcsnicmp(lpOutput, pOrgParam, p - pOrgParam) ||
220 !_tcsnicmp(lpOutput, param, p - param))
221 {
222 ConOutPuts(lpOutput);
223 ConOutChar(_T('\n'));
224 bFound = TRUE;
225 }
226 lpOutput += _tcslen(lpOutput) + 1;
227 }
229 }
230
231 /* Restore the truncated space for correctly
232 * displaying the error message, if any. */
233 if (bRestoreSpace)
234 *p = _T(' ');
235
236 if (!bFound)
237 {
239 retval = 1;
240 goto Quit;
241 }
242 }
243
244Quit:
245 if (BatType != CMD_TYPE)
246 {
247 if (retval != 0)
248 nErrorLevel = retval;
249 }
250 else
251 {
252 nErrorLevel = retval;
253 }
254
255 return retval;
256}
257
258static INT
260{
261 LPCTSTR p2 = p;
262 if (__iscsymf(*p))
263 {
264 ++p2;
265 while (__iscsym(*p2))
266 ++p2;
267 }
268 return (INT)(p2-p);
269}
270
271#define PARSE_IDENT(ident, identlen, p) \
272do { \
273 identlen = ident_len(p); \
274 ident = (LPTSTR)alloca((identlen + 1) * sizeof(TCHAR)); \
275 memmove(ident, p, identlen * sizeof(TCHAR)); \
276 ident[identlen] = 0; \
277 p += identlen; \
278} while (0)
279
280static INT
282{
283 LPCTSTR identVal = GetEnvVarOrSpecial(ident);
284 if (!identVal)
285 return 0;
286 else
287 return _tcstol(identVal, NULL, 0);
288}
289
290static BOOL
292{
293 switch (op)
294 {
295 case '*':
296 *lval *= rval;
297 break;
298
299 case '/':
300 {
301 if (rval == 0)
302 {
303 // FIXME: Localize
304 ConErrPuts(_T("Division by zero error.\n"));
305 nErrorLevel = 0x400023D1; // 1073750993;
306 return FALSE;
307 }
308 *lval /= rval;
309 break;
310 }
311
312 case '%':
313 {
314 if (rval == 0)
315 {
316 // FIXME: Localize
317 ConErrPuts(_T("Division by zero error.\n"));
318 nErrorLevel = 0x400023D1; // 1073750993;
319 return FALSE;
320 }
321 *lval %= rval;
322 break;
323 }
324
325 case '+':
326 *lval += rval;
327 break;
328 case '-':
329 *lval -= rval;
330 break;
331 case '&':
332 *lval &= rval;
333 break;
334 case '^':
335 *lval ^= rval;
336 break;
337 case '|':
338 *lval |= rval;
339 break;
340
341 default:
343 nErrorLevel = 0x400023CE; // 1073750990;
344 return FALSE;
345 }
346 return TRUE;
347}
348
349static BOOL
351
352static BOOL
354{
355 LPCTSTR p = *p_;
356 INT rval;
357
358 if (*p == _T('('))
359 {
360 p = skip_ws(p + 1);
361 if (!seta_stmt(&p, &rval))
362 return FALSE;
363 if (*p++ != _T(')'))
364 {
366 nErrorLevel = 0x400023CC; // 1073750988;
367 return FALSE;
368 }
369 *result = rval;
370 }
371 else if (_istdigit(*p))
372 {
373 errno = 0;
374 rval = _tcstol(p, (LPTSTR*)&p, 0);
375
376 /* Check for overflow / underflow */
377 if (errno == ERANGE)
378 {
379 // FIXME: Localize
380 ConErrPuts(_T("Invalid number. Numbers are limited to 32-bits of precision.\n"));
381 nErrorLevel = 0x400023D0; // 1073750992;
382 return FALSE;
383 }
384 /*
385 * _tcstol() stopped at the first non-digit character. If it's not a whitespace,
386 * or if it's the start of a possible identifier, this means the number being
387 * interpreted was invalid.
388 */
389 else if (*p && !_istspace(*p) && __iscsymf(*p))
390 {
391 // FIXME: Localize
392 ConErrPuts(_T("Invalid number. Numeric constants are either decimal (42), hexadecimal (0x2A), or octal (052).\n"));
393 nErrorLevel = 0x400023CF; // 1073750991;
394 return FALSE;
395 }
396 *result = rval;
397 }
398 else if (__iscsymf(*p))
399 {
401 INT identlen;
402 PARSE_IDENT(ident, identlen, p);
404 }
405 else
406 {
408 nErrorLevel = 0x400023CD; // 1073750989;
409 return FALSE;
410 }
411 *p_ = skip_ws(p);
412 return TRUE;
413}
414
415static BOOL
417{
418 LPCTSTR p = *p_;
419 TCHAR op = 0;
420 INT rval;
421
422 if (_tcschr(_T("!~-+"), *p))
423 {
424 op = *p;
425 p = skip_ws(p + 1);
426
427 if (!seta_mulTerm(&p, &rval))
428 return FALSE;
429
430 switch (op)
431 {
432 case '!':
433 rval = !rval;
434 break;
435 case '~':
436 rval = ~rval;
437 break;
438 case '-':
439 rval = -rval;
440 break;
441#if 0
442 case '+':
443 rval = rval;
444 break;
445#endif
446 }
447 }
448 else
449 {
450 if (!seta_unaryTerm(&p, &rval))
451 return FALSE;
452 }
453
454 *result = rval;
455 *p_ = p;
456 return TRUE;
457}
458
459static BOOL
461{
462 LPCTSTR p = *p_;
463 INT lval;
464
465 /* Evaluate the left-hand side */
466 if (!subTerm(&p, &lval))
467 return FALSE;
468
469 while (*p && _tcschr(ops, *p))
470 {
471 INT rval;
472 TCHAR op = *p;
473
474 p = skip_ws(p + 1);
475
476 /* Evaluate the immediate right-hand side */
477 if (!subTerm(&p, &rval))
478 return FALSE;
479
480 /* This becomes the new left-hand side for the next iteration */
481 if (!calc(&lval, op, rval))
482 return FALSE;
483 }
484
485 *result = lval;
486 *p_ = p;
487 return TRUE;
488}
489
490static BOOL
492{
493 return seta_ltorTerm(p_, result, _T("*/%"), seta_mulTerm);
494}
495
496static BOOL
498{
499 return seta_ltorTerm(p_, result, _T("+-"), seta_addTerm);
500}
501
502static BOOL
504{
505 LPCTSTR p = *p_;
506 INT lval;
507
508 /* Evaluate the left-hand side */
509 if (!seta_logShiftTerm(&p, &lval))
510 return FALSE;
511
512 /* Handle << >> operators */
513 while (*p && _tcschr(_T("<>"), *p))
514 {
515 INT rval;
516 TCHAR op = *p;
517
518 /* Check whether the next non-whitespace character is the same operator */
519 p = skip_ws(p + 1);
520 if (*p != op)
521 break;
522
523 /* Skip it */
524 p = skip_ws(p + 1);
525
526 /* Evaluate the immediate right-hand side */
527 if (!seta_logShiftTerm(&p, &rval))
528 return FALSE;
529
530 /* This becomes the new left-hand side for the next iteration */
531 switch (op)
532 {
533 case '<':
534 {
535 /* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
536 * which differs from the compiler (for example gcc) so being explicit. */
537 if (rval < 0 || rval >= (8 * sizeof(lval)))
538 lval = 0;
539 else
540 lval <<= rval;
541 break;
542 }
543
544 case '>':
545 lval >>= rval;
546 break;
547
548 default:
550 nErrorLevel = 0x400023CE; // 1073750990;
551 return FALSE;
552 }
553 }
554
555 *result = lval;
556 *p_ = p;
557 return TRUE;
558}
559
560static BOOL
562{
563 return seta_ltorTerm(p_, result, _T("&"), seta_bitAndTerm);
564}
565
566static BOOL
568{
569 return seta_ltorTerm(p_, result, _T("^"), seta_bitExclOrTerm);
570}
571
572static BOOL
574{
575 return seta_ltorTerm(p_, result, _T("|"), seta_bitOrTerm);
576}
577
578static BOOL
580{
581 LPCTSTR p = *p_;
583 TCHAR op = 0;
584 INT identlen, exprval;
585
586 PARSE_IDENT(ident, identlen, p);
587 if (identlen)
588 {
589 p = skip_ws(p);
590
591 /* Handle = assignment */
592 if (*p == _T('='))
593 {
594 op = *p;
595 p = skip_ws(p + 1);
596 }
597 /* Handle *= /= %= += -= &= ^= |= assignments */
598 else if (_tcschr(_T("*/%+-&^|"), *p))
599 {
600 op = *p;
601
602 /* Find the '=', there may be some spaces before it */
603 p = skip_ws(p + 1);
604 if (*p != _T('='))
605 {
606 op = 0;
607 goto evaluate;
608 }
609
610 /* Skip it */
611 p = skip_ws(p + 1);
612 }
613 /* Handle <<= >>= assignments */
614 else if (_tcschr(_T("<>"), *p))
615 {
616 op = *p;
617
618 /* Check whether the next non-whitespace character is the same operator */
619 p = skip_ws(p + 1);
620 if (*p != op)
621 {
622 op = 0;
623 goto evaluate;
624 }
625
626 /* Find the '=', there may be some spaces before it */
627 p = skip_ws(p + 1);
628 if (*p != _T('='))
629 {
630 op = 0;
631 goto evaluate;
632 }
633
634 /* Skip it */
635 p = skip_ws(p + 1);
636 }
637 }
638
639evaluate:
640 /* Allow to chain multiple assignments, such as: a=b=1 */
641 if (ident && op)
642 {
643 INT identval;
644 LPTSTR buf;
645
646 if (!seta_assignment(&p, &exprval))
647 return FALSE;
648
649 identval = seta_identval(ident);
650
651 switch (op)
652 {
653 /* Handle = assignment */
654 case '=':
655 identval = exprval;
656 break;
657
658 /* Handle <<= assignment */
659 case '<':
660 {
661 /* Shift left has to be a positive number, 0-31 otherwise 0 is returned,
662 * which differs from the compiler (for example gcc) so being explicit. */
663 if (exprval < 0 || exprval >= (8 * sizeof(identval)))
664 identval = 0;
665 else
666 identval <<= exprval;
667 break;
668 }
669
670 /* Handle >>= assignment */
671 case '>':
672 identval >>= exprval;
673 break;
674
675 /* Other assignments */
676 default:
677 if (!calc(&identval, op, exprval))
678 return FALSE;
679 }
680
681 buf = (LPTSTR)alloca(32 * sizeof(TCHAR));
682 _sntprintf(buf, 32, _T("%i"), identval);
683 SetEnvironmentVariable(ident, buf); // TODO FIXME - check return value
684 exprval = identval;
685 }
686 else
687 {
688 /* Restore p in case we found an identifier but not an operator */
689 p = *p_;
690 if (!seta_expr(&p, &exprval))
691 return FALSE;
692 }
693
694 *result = exprval;
695 *p_ = p;
696 return TRUE;
697}
698
699static BOOL
701{
702 LPCTSTR p = *p_;
703 INT rval;
704
705 if (!seta_assignment(&p, &rval))
706 return FALSE;
707
708 /* Loop over each statement */
709 while (*p == _T(','))
710 {
711 p = skip_ws(p + 1);
712
713 if (!seta_assignment(&p, &rval))
714 return FALSE;
715 }
716
717 *result = rval;
718 *p_ = p;
719 return TRUE;
720}
721
722static BOOL
724{
725 INT rval;
726
727 if (!*p)
728 {
730 nErrorLevel = 1;
731 return FALSE;
732 }
733 if (!seta_stmt(&p, &rval))
734 return FALSE;
735
736 /* If unparsed data remains, fail and bail out */
737 if (*p)
738 {
739 ConErrResPuts(STRING_SYNTAX_COMMAND_INCORRECT); // Actually syntax error / missing operand.
740 nErrorLevel = 0x400023CE; // 1073750990;
741 return FALSE;
742 }
743
744 /* Echo the result of the evaluation only in interactive (non-batch) mode */
745 if (!bc)
746 ConOutPrintf(_T("%i"), rval);
747
748 return TRUE;
749}
750
751#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 ConOutChar(TCHAR c)
Definition: console.c:123
VOID ConOutResPaging(BOOL StartPaging, UINT resID)
Definition: console.c:182
#define ConErrResPuts(uID)
Definition: console.h:38
#define ConErrPuts(szStr)
Definition: console.h:32
#define ConOutPrintf(szStr,...)
Definition: console.h:41
#define ConErrResPrintf(uID,...)
Definition: console.h:50
#define ConOutPuts(szStr)
Definition: console.h:29
#define STRING_INVALID_OPERAND
Definition: resource.h:215
#define STRING_EXPECTED_CLOSE_PAREN
Definition: resource.h:216
#define STRING_SYNTAX_COMMAND_INCORRECT
Definition: resource.h:218
#define STRING_SET_ENV_ERROR
Definition: resource.h:55
#define STRING_EXPECTED_NUMBER_OR_VARIABLE
Definition: resource.h:217
#define STRING_SET_HELP
Definition: resource.h:171
@ 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
#define errno
Definition: errno.h:18
static BOOL seta_bitOrTerm(LPCTSTR *p_, INT *result)
Definition: set.c:567
static INT seta_identval(LPCTSTR ident)
Definition: set.c:281
INT cmd_set(LPTSTR param)
Definition: set.c:72
static BOOL seta_assignment(LPCTSTR *p_, INT *result)
Definition: set.c:579
static BOOL seta_bitExclOrTerm(LPCTSTR *p_, INT *result)
Definition: set.c:561
static BOOL seta_mulTerm(LPCTSTR *p_, INT *result)
Definition: set.c:416
static BOOL seta_bitAndTerm(LPCTSTR *p_, INT *result)
Definition: set.c:503
static BOOL seta_expr(LPCTSTR *p_, INT *result)
Definition: set.c:573
static BOOL seta_eval(LPCTSTR expr)
Definition: set.c:723
static BOOL seta_addTerm(LPCTSTR *p_, INT *result)
Definition: set.c:491
static BOOL seta_stmt(LPCTSTR *p_, INT *result)
Definition: set.c:700
static BOOL seta_ltorTerm(LPCTSTR *p_, INT *result, LPCTSTR ops, BOOL(*subTerm)(LPCTSTR *, INT *))
Definition: set.c:460
static BOOL seta_unaryTerm(LPCTSTR *p_, INT *result)
Definition: set.c:353
#define PARSE_IDENT(ident, identlen, p)
Definition: set.c:271
static INT ident_len(LPCTSTR p)
Definition: set.c:259
static BOOL seta_logShiftTerm(LPCTSTR *p_, INT *result)
Definition: set.c:497
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:3731
LPSTR WINAPI GetEnvironmentStrings(void)
#define SetEnvironmentVariable
Definition: winbase.h:3843
_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