I have done many test to better understand the way set/p operates especially when used with input-redirection.
set/p can add a variable and give it a value.
set/p can NOT remove a variable.
Trying to use set/p to set a variable to an empty string will not give a clear message but set errorlevel to 1.
This can be interpreted as 'Error: no data/input'
When reading from stream the same thing happens when encountering empty lines.
This is also the reason you have to reset the variable yourself inside the read-loop.
Set /p will not reset the variable if current input is empty as with an empty line.
special note: set/p can set errorlevel but never resets the errorlevel to zero !!!
So if your batchfile checks errorlevel somewhere be sure to reset errorlevel in the read-loop.
The fastest way to reset errorlevel seems to be with 'verify>nul'
Code: Select all
set /p line=
if errorlevel 1 set "line=" & verify>nul
I have been experimenting a lot with the set /p command
apparently this is how 'set/p VAR=' works
Reading characters:
Characters are read from the inputstream and put in a characterbuffer until one of three conditions is true:
Condition 1: The last 2 read char are CRLF. (a complete line)
Condition 2: There are 1024 characters in the charbuffer. (buffer full)
Condition 3: A timeout, usually caused by end-of-stream. (time-out error-condition)
Processing the charbuffer:
All control-characters from the end of the char-buffer are discarded (possible dataloss)
If there is a NUL character in the charbuffer all characters following the first NUL in the charbuffer
will be discarded (dataloss)
Moving from charbuffer to Var.
If charbuffer is empty report errorcondition:
...set errorlevel to 1 (meaning No value entered)
If charbuffer is not empty:
... Move the string from charbuffer to the variable named in the set/p command.
Set/p is done and returns control to the batchfile.
Some remarks regarding control-characters (ASCII 0-31)
All control char except NUL can be read and put in a variable by use of the set/p read from stream.
The end-of-line combination CRLF will be discarded. However single CR and LF can be put in a variable as long
as they are not combined to a CRLF pair and there is at least one non-control character following the control character.
Remark: Because TAB is also a control-char TAB can not be used to 'protect' control characters from being skipped.
All normal chars like letters numbers, even a space can 'protect' control characters.
In pseudo-code
Code: Select all
initially charbuffer is empty
:innerloop
REM reading characters
repeat
get char from input (stream or manual input and store in charbuffer)
until - char buffer full (number of chars in charbuffer is 1024)
OR - last two char added to charbuffer are CRLF
OR - a timeout occurred when requesting next char (usually meaning end-of-input-stream)
REM Processing the charbuffer:
loop charbuffer from first received to last received char:
if char == NUL delete this char and all following chars in the charbuffer.
loop charbuffer from last received to (first or to a non-controlchar character)
if char is control-char remove this char from the charbuffer
(REM this loop removes all trailing control chars including the CRLF)
REM Moving from charbuffer to Var.
If charbuffer is empty (REM report errorcondition: Note: Var value remains unchanged!
set errorlevel to 1 (meaning No value entered)
else
Move the string from charbuffer to the variable named in the set/p command.
REM Set/p ends it's inner loop.
Control is returned to the batchfile or command prompt.
of course for manual input the entered values can be changed by using backspace etc.
On return in the batchfile there are 2 states possible.
1: the error-state, errorlevel is set, no input found, don't use Var-value because its
value is from a previous loop
Error-state can be caused by an empty line but also by timeout (end-of-stream)
2: no error-state, we got some value in our Var-variable.
This value can be one of the following
- a complete non-empty line
- an incomplete non-empty line caused bij time-out (end-of-input-stream)
- a data-chunk of max 1024 characters, not line-oriented
TODO's
[1]
What is the length of the timeout used internally by set/p.
[2]
I'm not sure if a timeout can occur before the inputstream is empty.
It might be that the inner loop from the set/p command can be stopped by for example the pause-key.
If this can be done it will result in set/p returning 2 half lines instead of 1 line.
So far I have tested the time-out behavior only in the end-of-stream siituation.
[3]
Test if time-polling can be used for better handling of the error-state.
That is to determine if the error was caused by an empty line/lines in the inputstream
or was caused by timeout on end-of-input-stream situation.
[4]
Test if special characters like ^ & ! % " ' = might cause problems when read using set/p
| have not yet tested these but i don't expect these to have special handling in set/p
[5]
Everything I might have missed or misinterpreted in my tests.
OJB