2

I am coding a rather complected Batch file for use in the creation of D&D characters. Part of this involves displaying long sentences, and after the specified window width the program will split words apart and tack the chopped off portion onto the next line. Is there anyway to just make it push the word which will be split up to the next line?

Mark
  • 3,609
  • 1
  • 22
  • 33
Sean McLain
  • 317
  • 2
  • 3
  • 12

3 Answers3

4

The Batch file below is a basic line-wrap on words program.

@echo off
setlocal EnableDelayedExpansion

rem Get the window width
for /F "skip=4 tokens=2 delims=:" %%a in ('mode con') do set /A width=%%a-1 & goto continue
:continue

rem Read the file given by first param and show its contents with no word split

set "output="
rem For each line in input file
for /F "delims=" %%a in (%1) do (
   rem For each word in input line
   for %%b in (%%a) do (
      rem Add the new word
      set "newOutput=!output! %%b"
      rem If new word don't exceed window width
      if "!newOutput:~%width%,1!" equ "" (
         rem Keep it
         set "output=!newOutput!"
      ) else (
         rem Show the output before the new word
         echo !output!
         rem and store the new word
         set "output=%%b"
      )
   )
)
rem Show the last output, if any
if defined output echo !output!

You may modify this Batch file in order to fulfill your specific needs. Be aware that this program may have problems with special Batch characters, but these problems may be fixed.

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Will this work in the batch file as it is running? If it dose do I slap this code at the beginning of the Batch file after @echo off but before the rest or what? – Sean McLain Jan 06 '14 at 10:18
2
@ECHO OFF
SETLOCAL
:: This sets up %lines% and %columns% in use
FOR /f "tokens=1,2delims=: " %%a IN ('mode con:') DO IF NOT "%%b"=="" SET /a %%a=%%b

:: FOR TESTING PURPOSES, set LINES and COLUMNS
ECHO lines and columns found= %lines% and %columns%
SET /a lines=10, columns=40
ECHO lines and columns FORCED= %lines% and %columns%
pause

:: I'll read from a textfile for convenience. Any text required needs just CALL :OUTPUT text to display
:: But let's clear the screen to start...
CALL :clsnp
SET "remainder="
FOR /f "delims=" %%a IN (q20943733.txt) DO (
 CALL :OUTPUT %%a
)
GOTO :EOF

:: :clsnp to clear screen then new page
:: :newpage to continue to a new page

:clsnp
cls
:newpage
SET /a linesleft=%lines% - 1
GOTO :eof

:: Output some text

:output
SET "remainder=%*"
SET remainder=%remainder:"=%
:outloop
SET /a lastsp=%columns% - 1
CALL :splitline
ECHO(%line%
SET /a linesleft -=1
IF %linesleft% leq 0 (pause&CALL :newpage)
IF DEFINED remainder GOTO outloop
GOTO :eof

:splitline
SET /a lastsp-=1
CALL SET line=%%remainder:~%lastsp%,1%%
IF NOT DEFINED line SET line=%remainder%&SET "remainder="&GOTO :EOF
IF NOT "%line%"==" " GOTO splitline
CALL SET line=%%remainder:~0,%lastsp%%%
SET /a lastsp+=1
CALL SET remainder=%%remainder:~%lastsp%%%
GOTO :eof

Well, this was an interesting problem - and warning - batch has some problems dealing with certain characters like %^&|<> so essentially - just avoid them.

It's normal to start a batch with @echo off and setlocal (or setlocal enabledelayedexpansion)

The lines beginning :: are comments. :: is unofficial, but commonly-used and is less intrusive than REM Comments can be omitted, of course - but can also be useful when you come to maintain your work later.

The first FOR loop establishes some variables, most importantly LINES and COLUMNS so that the batch can calculate the required width and pagelength.

The next few lines are for testing purposes only. My console is set for 780 lines and 171 columns, so I've displayed the values found, then forced them to deliberately small values in order to test the routine. That block of code can be deleted if you wish, but if you simply comment it out, you can easily change the values forced for your own testing.

The next step is to clear the screen and initialise the count of lines-left-on-a-page. All you need do here is CALL :clsnp If you simply want to re-start a "page" (after prompting for a response, for instance) just CALL :newpage (it's easier and better understood than repeating the SET)

Next, I simply used random text from a textfile named q20943733.txt as the strings to be output and formatted.

Outputting is really simple. Just CALL :OUTPUT Some text to be output or CALL :OUTPUT %variable% or even CALL :OUTPUT You have %hitpoints% hitpoints and %gold% gold pieces and the OUTPUT routine will format the text, breaking lines between words. if required.

CALL :OUTPUT Strength %strength% 
CALL :output Hitpoints %hitpoints%
call :output %gold% gold pieces

would display these three characteristics - and it's probably easier to read than an ECHO

The routines :clsnp onwards are probably best placed at the end of your batch. You just need to replace the reading of the textfile with your game mechanics...

One last little tip: here's a useful routine:

:getresponse
set "response="
set /p response="%* "
if defined response goto :eof
goto getresponse

If you then code CALL :getresponse Which direction ? then you'll get a prompt Which direction ? and the response from the user will be available in %response% when the routine returns...

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • I don't quite understand how I would implement this code. Dose this mean I would have to take the text to be displayed out of the program as is, put it into individual .txt files and have this code before a program which somehow displays the contents of the .txt files when needed? If so how do I do that? Half of the point of what I am programming is to have the text displayed in the command prompt window for atmosphere (This is supposed to look like an old 1980's program.) – Sean McLain Jan 07 '14 at 06:38
  • No - I simply used a text file for testing, as I said. Look at the last-but-one highlighted code box. There you have three lines of output. If the text to be displayed on any of those lines exceeds the width of the console, it will be split on a space between two - or more- lines. The argument given to the `output` routine may be up to about 8,000 characters long. You might for instance produce a report of 'your potions' which may read `3 doses unidentified bubbling smoky yellow potion in a leather-bound cut-crystal bottle with pink top` then on to the next and so on. Put this in a loop, – Magoo Jan 07 '14 at 06:57
  • call :output with each description and let the routine have its way. It will pause when the screen is full and then fill the next page until the entire list is processed. No doubt then you'd want to prompt with a question and accept some user-response (the `getresponse` routine) after which you need to call either `clsnp` to clear the screen or `newpage` to tell `output` that it can now let messages through until it fills the screen again. – Magoo Jan 07 '14 at 07:02
0

I took Magoo's answer and expanded on it, partly because I was a bit confused on how to use his, partly because it had some issues (mainly with special characters, e.g. ampersands), and partly to add more functionality. It was all part of a bigger script I was writing, and I was just having fun with it and learning stuff. I want to stress that this is built upon Magoo's work, without which I'm not sure I would have been able to figure out how to do it (his code is still at the core, responsible for the actual wrapping), and certainly it would have taken much longer than it did. The code for the length determining function came from jeb's answer here, which I modified slightly in order to handle special characters and because his code would short the count by one (something I was going to mention there, but can't since it's closed and I can't comment due to lack of privileges). The code is heavily commented, so I won't explain any of it here. Just put it all after the rest of your code or in a separate batch file (though if I'm not mistaken, that would add some complexity to how you would call it). As mentioned, I can't comment, so if you have questions, unless that rule doesn't apply to your own answers, I unfortunately won't be able to respond. Anyways, I hope this helps someone.

REM  Function to determine length of string passed to it. Needs to be placed after primary script code.
:length
setlocal EnableDelayedExpansion
SET STR=%*
REM  Change any ampersands in input to ASCII placeholder so function can process it
SET "STR=!STR:&=!"
REM  Remove triple-quotes from input since quotes are needed to pass ampersands (and possibly other characters) to the function for it to work properly, but may not be desired in final output, so using triple-quotes will allow them to be used but not displayed
SET "STR=!STR:"""=!"
rem !FOR %%a IN (%*) DO SET STR=!STR! %%a
rem !FOR /F "tokens=* delims= " %%a IN ("!STR!") DO SET STR=%%a
SET STR_REMAINDER=!STR!

SET /A STR_LEN=0
FOR %%p IN (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) DO (
  If NOT "!STR_REMAINDER:~%%p,1!" == "" ( 
    SET /A STR_LEN+=%%p
    SET "STR_REMAINDER=!STR_REMAINDER:~%%p!"
  )
)
REM  Add 1 to counted length since it doesn't check "!STR_REMAINDER:~0,1!" which would check for a single character, and doing so wouldn't help since it would just add 0 (%%p) and therefore not change the count
SET /A STR_LEN+=1

endlocal & SET /A STR_LEN=%STR_LEN%
exit /b

REM  Function to center text passed to it. Needs to be placed after primary script code. Use :centerwrap function; this function will be called from there.
:center
setlocal EnableDelayedExpansion
SET STR=%*
REM  Change any ampersands in input to ASCII placeholder so function can process it
SET "STR=!STR:&=!"
REM  Remove ASCII character used to retain leading spaces (indent)
SET "STR=!STR:=!"
REM  Remove triple-quotes from input since quotes are needed to pass ampersands (and possibly other characters) to the function for it to work properly, but may not be desired in final output, so using triple-quotes will allow them to be used but not displayed
SET "STR=!STR:"""=!"
SET STR_REMAINDER=!STR!

SET /A STR_LEN=0
FOR %%p IN (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) DO (
  If NOT "!STR_REMAINDER:~%%p,1!" == "" ( 
    SET /A STR_LEN+=%%p
    SET "STR_REMAINDER=!STR_REMAINDER:~%%p!"
  )
)
REM  Add 1 to counted length since it doesn't check "!STR_REMAINDER:~0,1!" which would check for a single character, and doing so wouldn't help since it would just add 0 (%%p) and therefore not change the count
SET /A STR_LEN+=1

REM  Set base offset by subtracting half of STR_LEN from half of columns (midpoint of window width)
SET /A OFFSET="( !COLUMNS! / 2 ) - ( !STR_LEN! / 2 )"

REM  Set variable to determine whether to shift lines that don't center exactly one space to the left or to the right. If # of columns AND string length are even or odd it will center exactly, but if column # is even and string length is odd, line will be off-center slightly to the right, and if column # is odd and string length is even line will be off-center slightly to the right, so this will either tell the function to shift to the left in the prior case or to the right in the latter.
SET SHIFT=LEFT

REM  Determine if window columns (width) # is even or odd
SET /A COL_1="( !COLUMNS! / 2 ) * 10"
SET /A COL_2="( !COLUMNS! * 10 ) / 2"
If !COL_1! equ !COL_2! (
  SET COLS=EVEN
) Else (
  SET COLS=ODD
)

REM  Determine if string length is even or odd and use that and whether column number is even or odd to determine offset
SET /A STR_LEN_1="( !STR_LEN! / 2 ) * 10"
SET /A STR_LEN_2="( !STR_LEN! * 10 ) / 2"

If !STR_LEN_1! equ !STR_LEN_2! (
  REM  String length is even
  If "!COLS!" == "ODD" (
    If /I "!SHIFT!" == "RIGHT" (
      SET /A OFFSET+=1
    )
  )
) Else (
  REM  String length is odd
  If "!COLS!" == "EVEN" (
    If /I "!SHIFT!" == "LEFT" (
      SET /A OFFSET-=1
    )
  )
)

REM  Create variable full of spaces then create variable combining only the first !OFFSET! characters (spaces) followed by the text to be displayed, then echo the variable to display the resultant centered text
SET "SPACES=                                                                                                                                                                                                                                 "
SET "CENTERED_STR=!SPACES:~0,%OFFSET%!%STR%"
REM  Change ASCII placeholders assigned earlier back to " and & before output is displayed
SET "CENTERED_STR=!CENTERED_STR:="!"
SET "CENTERED_STR=!CENTERED_STR:=&!"
echo !CENTERED_STR!
endlocal
exit /b

REM  Function to display text passed to it and word-wrap it so newlines occur on spaces and not mid-word. Needs to be placed after primary script code. To use type "call :function_name [x] [y] [Text to be wrapped]" (without the quotes or brackets), x and y are parameters for use only in indent and justify functions. All functions run through :wrap and therefore perform the basic word-wrap function. To pass spaces at the beginning of the string through, use a dot (.) as the first character (e.g. "call :wrap .      text" or "call :hangjustify 15 5 .        text"). This is necessary to have the spaces included since these functions use the call parameters as input and therefore don't see anything until the first non-space character. The dot will simply be removed and the spaces will be retained. It's not necessary to do this for functions that call the param_check_and_trim function (those with x/y variables), but there is no harm in doing so. Note that certain characters may not be able to be passed to these functions (e.g. ^ will be ignored, though that could theoretically be changed if desired). Quotes (") and parentheses are fine, however, and closing parentheses don't need to be escaped unless inside an if statement, just like with echo, i.e. (text^), and can simply be entered normally, i.e. (text), though escaping them won't affect anything as carets are removed. Ampersands (&) can also be used, though if the text sent to the functions contains any it needs to be wrapped in quotes (e.g. call :wrap "Foo & bar" -> "Foo & bar" // call :wrap Foo "&" bar -> Foo "&" bar). This means that if any variables that may possibly contain any ampersands are included in the call, the line OR variable(s) should be wrapped in quotes, otherwise it will not return any output if any are present. In order to do this without displaying the quotes in the final output, wrap the text in triple quotes (e.g. call :wrap """Foo & bar""" OR call :wrap Foo """&""" bar -> Foo & bar). If the entire line is quoted to allow for ampersands, no text within the line can be quoted (e.g. """Foo & "bar"""" wouldn't work; however, Foo """&""" "bar" would). Caution is needed with parameters containing quotes, such as a quoted path\filename set to a variable, such as would occur if passing a path\filename to another function and setting it to a variable there, then including the variable in a call to these functions, as the quotes will be counted. This means using the standard single or triple quotes would result in double or quadruple quotes, which will result in no output. In these cases, either the quotes must be stripped from the variable or the quotes used in the call to these functions must be adjusted (subtract one to account for set in variable, so " -> none and """ -> ""). Also be aware the output is much slower than simply echo'ing the lines, and therefore will impart a *very* slight delay in displaying each line, making the functions undesirable or even unsuitable for certain tasks, like frequent screen refreshing, e.g. if implementing a timer. Note that a "full/equalwrap" function to try and split text evenly across all lines, to for example create somewhat shorter but more even lines vs longer lines with the last one being shorter than the rest, was considered and attempted, but this is likely not possible. This is because the total length would have to be determined then divided by the number of columns, but that wouldn't account for words that need to be wrapped, and it would change each time the margins are adjusted, and so it would end up shifting and taking more lines than calculated, resulting in a shorter final line. The only way around this would be to always add a hyphen as the last character on a line then continue mid-word on the next line, which wouldn't be desirable. It could work for shorter strings that would only wrap once or maybe even a few times, but anything longer becomes far too unpredictable. The only way it might work would be to adjust the wrap function, or create a separate one, to allow a line to go past the ( STR_LEN / COLUMNS ) cutoff point until the next space, up to the point where it would actually run out of room, to prevent unintended roll-overs, but that seems unlikely to work as well, and it would require constant recalculating of number of lines, number of characters per line, and margins, so see how the change of any one variable affects the others, which would then have to be changed, which would affect the others, and end up being a vicious cycle.
REM
REM  Center text -- EXAMPLE -> call :centerwrap text
:centerwrap
setlocal EnableDelayedExpansion
SET CENTER=TRUE
goto wrap
REM  Center text and create a margin x spaces wide on the left side and y spaces on the right -- EXAMPLES -> call :centerjustify 5 20 text  OR  call :centerjustify 5 5 text  OR  call :centerjustify 0 10 text (can also use :centerindent, or make a label with whatever name is preferred)
:centerjustify
:centerindent
:centerindentwrap
:centerindentjustify
setlocal EnableDelayedExpansion
REM  Set the text to be wrapped (REMAINDER) and set the function name and first two parameters (x & y; as number and string) as variables for use in the paramater check & trim function (number variables are for checking if they're numbers and string variable is for displaying them if they're not, to help find the incorrectly worded call) and remove triple-quotes, if present, from first parameter (only if the variable is defined, since using SET to remove quotes from an empty variable causes issues), then call function and exit if check fails (first two parameters passed not valid numbers), otherwise call function to clean text to be wrapped (remove triple-quotes and swap out problematic characters with placeholders) and set center flag
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
REM  Set variables for parameter 2, which requires an additional line as not more than one expansion & substitution can be performed per line (no more variables can be set after it, so it must the last one done on each line)
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET CENTER=TRUE
REM  Use variable full of spaces set in param_check_and_trim function to create indent variable combining only the first x characters (spaces) as defined in the call
SET "INDENT=!SPACES:~0,%1!"
REM  Decrease columns by indent amount for justify functionality, so lines will be wrapped x characters sooner, creating a margin that size on the right
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all but the first line x spaces -- EXAMPLE -> call :hangindent 15 text
:hangindent
:hangindentwrap
:hangwrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "HANGINDENT=!SPACES:~0,%1!"
goto wrap
REM  Indent all but the first line x spaces and create a margin y spaces wide on right side -- EXAMPLE -> call :hangjustify 15 5 text
:hangjustify
:hangjustifywrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "HANGINDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all lines x spaces and create a margin x spaces wide on right side (note this always performs indentation as well, since it's unlikely it would be used on its own, though that can be done with indentjustify function below) -- EXAMPLE -> call :justify 5 text
:justify
:justifywrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %1 )"
goto wrap
REM  Indent all lines x spaces and create a margin y spaces wide on right side -- EXAMPLE -> call :indentjustify 5 15 text
:indentjustify
:indentjustifywrap
:doublewrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all lines x spaces -- EXAMPLE -> call :indent 5 text
:indent
:indentwrap
:wrapindent
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
REM  Base word-wrap functionality; call directly if none of the above functions are desired (consists of wrap, outloop, and line_wrap functions; param_check_and_trim and char_count used for above functions) -- EXAMPLE -> call :wrap text
:wrap
setlocal EnableDelayedExpansion
REM  Exit function if no text was entered. If desired, this could be set to notify or perform an echo. (blank line) as well.
If [%1] == [] endlocal & exit /b
REM  Set input and call input clean function if wrap function is called directly, as these wouldn't be done above, and shouldn't be done again if already done above. Placed on the same line to avoid the parentheses required for a multi-line statement, which would break the function if any non-escaped closing parentheses are in the text passed to the function
If NOT "!INDENTED!" == "TRUE" SET REMAINDER=%*& call :wrap_input_clean
REM  Check if first parameter (first character) is a dot, in which case remove it
SET "DOTCHECK=!REMAINDER:~0,1!"
If "!DOTCHECK!" == "." SET "REMAINDER=!REMAINDER:~1!"
SET REMAINDER=!INDENT!!REMAINDER!
:outloop
SET /A LASTSP=%COLUMNS% - 1
CALL :line_wrap
REM  Remove any carets from output (unclear why, but whenever a caret is used in the input, it's doubled in the output)
SET "LINE=!LINE:^=!" 
REM  Send line to center function if center flag is set to true, otherwie echo it normally. This is processed each time the line_wrap function determines an EOL (end-of-line) and sends the currently processed line, which cuts off at the last space before a word that would be split, to the outloop function for display.
If "!CENTER!" == "TRUE" (
  REM  Insert ASCII character at beginning of line to preserve leading spaces (indent), which would otherwise not be counted as part of argument in center function
  SET LINE=!LINE!
  call :center !LINE!
) Else (
  REM  Change ASCII placeholders assigned earlier back to " and & before output is displayed
  SET "LINE=!LINE:="!"
  SET "LINE=!LINE:=&!"
  echo !LINE!
)
IF DEFINED REMAINDER goto outloop
endlocal
exit /b
:line_wrap
SET /A LASTSP-=1
CALL SET LINE=%%REMAINDER:~%LASTSP%,1%%
IF NOT DEFINED LINE endlocal & SET "LINE=%REMAINDER%" & SET "REMAINDER=" & exit /b
IF NOT "%LINE%"==" " goto line_wrap
CALL SET LINE=%%REMAINDER:~0,%LASTSP%%%
SET /A LASTSP+=1
REM  !INDENT! adds indentation, if present, in front of each line
CALL SET REMAINDER=!INDENT!!HANGINDENT!%%REMAINDER:~%LASTSP%%%
endlocal
exit /b
REM  Checks first (x = indent) and, if applicable, second (y = justify/margin) parameter(s) to ensure they're valid (positive numbers). If not, displays error message to alert programmer of the error, otherwise removes them from input string and sets INDENTED=TRUE. FOR loop to cycle through parameters and keep only 3+ (i.e. FOR /F "tokens=3*" %%a IN ("!REMAINDER!") DO SET REMAINDER=%%a %%b) can NOT be used as it will ignore multiple spaces (e.g. "text   to   be   displayed" would become "text to be displayed"). The count loop could be replaced by a call to the length function, but since it's only two additional lines there's no need and this keeps it all together. Because this removes the x and y parameters and leaves the rest of the string intact, functions that call it do not need to use a dot (.) to keep leading spaces; however, doing so will not affect anything.
:param_check_and_trim
setlocal EnableDelayedExpansion
SET "ASTERISKS=********************************************************************************************************************************************************************************************************"
SET "ASTERISKS=!ASTERISKS:~0,%COLUMNS%!"
SET "ASTERISKS=!ASTERISKS:~10!"
If %1 equ 1 (
  If !PARAM1_NUMERICAL! lss 1 (
    call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number as the first parameter (e.g. "call !FUNCTION_NAME! 5 text"). This is a problem with the script code, NOT with user input. The following parameter was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
  ) Else (
    FOR /F "tokens=1" %%a IN ("!REMAINDER!") DO SET CHARS=%%a& SET /A i=1
  )
)
If %1 equ 2 (
  If !PARAM1_NUMERICAL! lss 1 (
    If !PARAM2_NUMERICAL! lss 1 (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but both are invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& echo. & call :centerwrap """PARAMETER 2: '!PARAM2_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    ) Else (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but the first parameter is invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    )
  ) Else (
    If !PARAM2_NUMERICAL! lss 1 (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but the second parameter is invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 2: '!PARAM2_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    ) Else (
      FOR /F "tokens=1,2" %%a IN ("!REMAINDER!") DO SET CHARS=%%a%%b& SET /A i=2
    )
  )
)
:char_count_loop
FOR %%a IN (!CHARS!) DO SET "CHARS=!CHARS:~1!" & SET /A i+=1
If !CHARS! neq 0 goto char_count_loop
endlocal & SET "REMAINDER=!REMAINDER:~%i%!" & SET "INDENTED=TRUE" & SET "SPACES=                                                                                                                                                                                                                                 "
exit /b
:wrap_input_clean
setlocal EnableDelayedExpansion
REM  Remove triple-quotes since they are not wanted in final output. Triple-quotes could be changed to (almost) anything desired, such as "- or ". (double-quotes ("") won't work, however). Then change ampersands (&) and remaining quotes in input to ASCII characters (Alt+004 and Alt+005, respectively) since ampersands are problematic and quotes sometimes break "IF NOT "%LINE%"==" " goto line_wrap" line in Line_wrap function, since it reads as "IF NOT """==" " goto line_wrap" -- Note that this should be possible for other characters as well, such as carets (^).
SET "REMAINDER=!REMAINDER:"""=!"
SET "REMAINDER=%REMAINDER:"=%"
SET "REMAINDER=!REMAINDER:&=!"
endlocal & SET "REMAINDER=%REMAINDER%"
exit /b
vertigo
  • 3
  • 2