jeb wrote: ↑13 Jun 2023 04:53
First, a minor problem.
- I would use a different context detection
Code: Select all
if "%=^%=" == "%=%=" ( echo batch-context ) else echo cmd-context
Because "%~f0"=="%~dpnx0" can be disturbed, by
Code: Select all
set "~f0"=="=& "^& XXXXXXXXXXXXX"
if "%~f0"=="%~dpnx0" ( echo batch-context ) else echo cmd-context
< no output at all >
I forgot about that. This is ingenious, thanks.
jeb wrote: ↑13 Jun 2023 04:53
It's not possible, because CALL/GOTO can't call any function, SETLOCAL doesn't work, ...
Without these, your only way to loop anything, is to use FOR-loops, it's like the
(batch-)macro technique.
Macros won't work either as
setlocal doesn't work.
With functions, one way of "emulating" their behaviour that I've considered is:
Code: Select all
call :is_batch_context || (
...do some stuff...
)
...irrelevant code...
:is_batch_context > Result
exit /b 0 "If this is callable, then we're operating in a batch context"
But you're right - not having access to subroutines hurts.
jeb wrote: ↑13 Jun 2023 04:53
1. sanitizing hazardous characters in a command-line context without toggling delayed expansion
- When and what do you want to sanitize? Examples needed
CMDCMDLINE, DOSKEY macros etc. Say I wanted to parse the following and prepend opening parentheses with indentation within a DOSKEY alias:
Code: Select all
pwd!=(for /f "skip=9 tokens=1,2,*" %j in ('"fsutil reparsepoint query ."') do @(if "%~j"=="Print" if "%~k"=="Name:" if not "%~l"=="" (echo(%~l))) || (chdir)
The end result would be:
Code: Select all
pwd!=(
for /f "skip=9 tokens=1,2,*" %j in (
'"fsutil reparsepoint query ."'
) do @(
if "%~j"=="Print" if "%~k"=="Name:" if not "%~l"=="" (
echo(%~l
)
)
) || (
chdir
)
Impossible without variable substitution.
Or examining CMDCMDLINE in a code snippet
curled into
cmd.exe:
Code: Select all
set "cmd=!CMDCMDLINE!"
for /f "tokens=1,* delims=/" %p in ("!cmd://=!") do (
...do some stuff...
)
If I don't use delayed expansion here then every metacharacter (<>|&) is dangerous. If I do, then ^ and ! get trimmed. I can't mutate CMDCMDLINE either because of
its questionable behaviour - I have to copy/clone it first. Honestly I have no idea how to proceed.
jeb wrote: ↑13 Jun 2023 04:53
2. create a check for command-line context ... but doesn't work when the code has been already evaluated in a parentheses block (e.g. goto 2>nul)
- I don't understand how your code is written in that case. Even if it's already evaluated, it still should be correct. Please show an example
Code: Select all
:exit (exit_code: number?) > Abort
set "exit_code=%~1"
(
(goto) & (goto)
call :exit %exit_code% || (
title %0 &@rem Here, I need top-level context name
"%ComSpec%" /d @exit /b %exit_code% 2>nul
)
) 2>nul
Too early to save
%0 to a variable, too late to retrieve it.
title here can be any command - I just want to operate on
%0 here.
Something that crossed my mind just now - maybe
call set between the
gotos is the way?
jeb wrote: ↑13 Jun 2023 04:53
3a. obtaining the caller script, if any, from any context...
- It can only work in batch context, what do you expect in cmdline-context?
3b. do I just move up the scopes until the first character is not a colon?
- Yes, that's the common way (common for the four people in the world who uses this at all)
My bad - I meant label context here, not command-line context (this doesn't make sense in command-line context anyway). I simply want to know what the global
%0 is from within a label in order to reliably obtain the title with or without parentheses. Currently I use the code above, but it's a one-way ride.