2627 lines
119 KiB
Batchfile
Executable File
2627 lines
119 KiB
Batchfile
Executable File
@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment
|
|
@goto :Batch
|
|
|
|
::JREPL.BAT by Dave Benham
|
|
::/History
|
|
::
|
|
:: 2020-07-30 v8.6: Added options to /K, /R, and /MATCH to count the number
|
|
:: of matches or rejects instead of printing them.
|
|
:: Added the counter /JScript variable.
|
|
:: Fixed /T Pig Latin example - $0 corrected to read $&
|
|
:: 2020-02-29 v8.5: Added /EOL option to set the end of line terminator.
|
|
:: Added the eol global jscript variable.
|
|
:: Doc fix - No EOL if /RTN option specifies a :LineNumber.
|
|
:: 2019-09-13 v8.4: Bug fix - /K,/R did not work with /EXC,/INC as of v8.0
|
|
:: 2019-07-16 v8.3: Documentation correction - Binary data with null bytes may
|
|
:: be read via ADO.
|
|
:: 2019-06-05 v8.2: /RTN bug fix - preserve Unicode by using CHCP 65001/utf-8
|
|
:: to transfer value to variable unless /XFILE used.
|
|
:: 2019-05-19 v8.1: Add /VT to enable Virtual Terminal ANSI escape sequences.
|
|
:: Code courtesy of DosTips user aGerman (Steffen).
|
|
:: 2019-05-15 v8.0: Add /Hxxx options for highlighting matched/replaced text.
|
|
:: Bug fix - /OFF was wrong when used with /P.
|
|
:: Change - /OFF is now incompatible with /PREPL.
|
|
:: Change - /PREPL may now be used with /K and /R.
|
|
:: Doc fix - corrected syntax for /F [|NB] option.
|
|
:: Doc fix - /OFF is for first match if used with /K.
|
|
:: 2018-10-20 v7.15: Add a string literal syntax to the /INC and /EXC options.
|
|
:: 2018-10-15 v7.14: Bug fix - User defined variables declared in /JBEG named
|
|
:: str and/or obj were getting clobbered.
|
|
:: Bug fix - Internal variable xbytes was visibile to user
|
|
:: supplied JScript.
|
|
:: 2018-07-19 v7.13: Bug fix - /INC and /EXC regex failed to match any
|
|
:: line that immediately followed a prior block.
|
|
:: Added ADO code to create XBYTES.DAT in case CERTUTIL is
|
|
:: missing. Code courtesy of DosTips user aGerman (Steffen).
|
|
:: 2018-07-18 v7.12: Fixed XBYTES.DAT creation cleanup bugs, and improved docs
|
|
:: 2018-03-26 v7.11: Add support for /O "-|UTF-?|NB" (overwrite without BOM)
|
|
:: 2018-03-14 v7.10: Now can block BOM in ADO output files by appending |NB
|
|
:: to |CharSet in the /O option and OpenOutput() function.
|
|
:: 2017-11-23 v7.9: Allow escape sequences with /T "" coupled with /XSEQ
|
|
:: Added /PREPL option to augment /P behavior
|
|
:: Bug fix - Force /L when /T "" used, as per documentation
|
|
:: Bug fix - Allow /?charset/search to include non alpha
|
|
:: 2017-11-13 v7.8: Added \x{nn-mm} and \x{nn-mm,CharSet} escape sequences
|
|
:: Split /X into /XFILE and /XSEQ - /X implies both
|
|
:: Add :FILE syntax for /K and /R to load searches from file
|
|
:: Fixed /XSEQ escaped backslash bug with /INC, /EXC, AND /P
|
|
:: 2017-10-24 v7.7: Fixed broken Microsoft documentation links
|
|
:: Allow /O "-|CharSet"
|
|
:: Fixed decode(Str[,CharSet]) bug when CharSet is undefined
|
|
:: 2017-10-08 v7.6: Fixed /?Intro syntax help for /?Charset/[Query]
|
|
:: 2017-10-08 v7.5: Added /?CHARSET and /?XREGEXP web page help options
|
|
:: Added /?CHARSET/[query] List character sets help option
|
|
:: Fixed ADO output.WriteLine() to use \r\n instead of \n
|
|
:: Improved documentation: /EXC, /OFF, /U, /?HELP, decode()
|
|
:: 2017-09-25 v7.4: Modified /X \xnn extended ASCII escape sequence to support
|
|
:: any single byte character set.
|
|
:: Added /X \x{nn,Charset} escape sequence.
|
|
:: Added /XBYTES and /XBYTESOFF options.
|
|
:: Modified decode() to support the new /X \xnn behavior.
|
|
:: 2017-09-23 v7.3: Fixed /O - support for ADO input.
|
|
:: 2017-09-23 v7.2: Improved documentation of new 7.0 features.
|
|
:: Bug fix - /T FILE ADO support was broken
|
|
:: 2017-09-08 v7.1: Bug fix - v7.0 failed if Find or Replace contained )
|
|
:: 2017-09-08 v7.0: Added /XREG and /TFLAG for XRegExp regex support.
|
|
:: Added /UTF for UTF-16LE support.
|
|
:: Added /X support for the \u{N} unicode escape sequence.
|
|
:: Added |CharSet syntax for file names to allow reading
|
|
:: and writing via ADO with a specified character set.
|
|
:: Exposed the fso FileSystemObject to user JScript.
|
|
:: Augmented openOutput for Unicode and ADO support.
|
|
:: 2017-08-25 v6.8: Added /X support for the \c caret escape sequence.
|
|
:: Added /APP - append to the output file.
|
|
:: Added the openOutput(file[,appendBoolean]) function.
|
|
:: 2017-04-09 v6.7: Corrected /OFF /EXC & /INC documentation + spelling fixes.
|
|
:: 2016-12-23 v6.6: Help correction: Fixed return codes in /?RETURN section.
|
|
:: 2016-11-13 v6.5: Modify /X to consistently preserve extended ASCII.
|
|
:: New option /RTN writes result to a variable.
|
|
:: 2016-11-01 v6.4: Bug fix - v6.3 had inverted /EXC result.
|
|
:: 2016-10-13 v6.3: Improved performance by dynamically generating main loop
|
|
:: code based on chosen options.
|
|
:: 2016-10-13 v6.2: Bug fix - /J, /JQ, /JMATCH, /JMATCHQ did not work with /P.
|
|
:: 2016-10-08 v6.1: Bug fix - v6.0 broke /JBEG and /JLIB, all fixed.
|
|
:: 2016-10-08 v6.0: Added /K - search and write matching lines.
|
|
:: Added /R - search and write non-matching lines.
|
|
:: Added /MATCH - search and write each match on a new line.
|
|
:: Added /P - Pre-filter regex before normal search/replace.
|
|
:: Added /PFLAG - set search flags for /P regex
|
|
:: Added /JQ and /JMATCHQ as Quick forms of /J and /JMATCH.
|
|
:: Augmented /INC and /EXC so can now specify lines by regex.
|
|
:: Changed behavior - /V now applies to /INC and /EXC.
|
|
:: Improved performance of /INC, /EXC, /T, /JBEGLN, /JENDLN.
|
|
:: Added HISTORY and UPDATE topics to the help system.
|
|
:: 2016-09-27 v5.2: Bug fix - Search & Replace now ignore /V if /T FILE used.
|
|
:: Added a /T FILE example to the documentation.
|
|
:: 2016-09-20 v5.1: Added the FILE alternative for the /T option.
|
|
:: 2016-09-18 v5.0: Added the /U option for Unix line terminators of /n.
|
|
:: 2016-08-04 v4.6: Fixed the /N documentation (repaired missing line)
|
|
:: 2016-08-03 v4.5: Added /D option to specify delimiter for /N and /OFF.
|
|
:: 2016-08-02 v4.4: Bug fix - /C count was wrong when last line did not end
|
|
:: with new line. This also affected /INC and /EXC.
|
|
:: 2016-07-30 v4.3: Added rpad() function and improved lpad()
|
|
:: 2016-06-24 v4.2: Improved the /?Options help.
|
|
:: 2016-06-23 v4.1: Added /T option examples to the help.
|
|
:: Added ability to request help on a single option or topic.
|
|
:: 2016-06-19 v4.0: Added the /INC and /EXC options.
|
|
:: 2016-03-27 v3.8: Bug fix - Hide leaked global variables i, lib, libs, rtn2.
|
|
:: Bug fix - Work around %~f0 bug when command is quoted.
|
|
:: Bug fix - Use /OPTIONS instead of OPTIONS as a variable
|
|
:: name within the option parser so that it is unlikely to
|
|
:: collide with a user defined variable name.
|
|
:: 2016-01-14 v3.7: Reworked error handling a bit.
|
|
:: Bug fix - \xnn and \unnnn could fail in a regex search
|
|
:: if result was a meta-character and /X option was used.
|
|
:: 2015-07-15 v3.6: Added /?? option for paged help.
|
|
:: 2015-06-12 v3.5: Bug fix for $n or $nn in replace string when /T is
|
|
:: used without /J or /JMATCH or /L
|
|
:: 2015-01-22 v3.4: Bug fix - Use /TEST instead of TEST as a variable name
|
|
:: within the option parser so that it is unlikely to
|
|
:: collide with a user defined variable name.
|
|
:: 2014-12-24 v3.3: Bug fix for when /JMATCH is combined with /M or /S
|
|
:: 2014-12-09 v3.2: Bug fix for /T without /JMATCH - fixed dynamic repl func
|
|
:: Added GOTO at top for improved startup performance
|
|
:: 2014-11-25 v3.1: Added /JLIB option
|
|
:: Exception handler reports when regex is bad
|
|
:: Fix /X bug with extended ASCII
|
|
:: 2014-11-23 v3.0: Added /JBEGLN and /JENDLN options
|
|
:: Added skip, quit, and lpad() global variables/functions
|
|
:: Exception handler reports when error in user code
|
|
:: 2014-11-21 v2.2: Bug fix for /T with /L option.
|
|
:: 2014-11-20 v2.1: Bug fix for /T option when match is an empty string
|
|
:: 2014-11-17 v2.0: Added /T (translate) and /C (count input lines) options
|
|
:: 2014-11-14 v1.0: Initial release derived from REPL.BAT v6.2
|
|
::/
|
|
::============ Documentation ===========
|
|
::/INTRO
|
|
:::
|
|
:::JREPL Search Replace [/Option [Value]]...
|
|
:::JREPL /?[?][Topic|/Option|CHARSET/[Query]|HELP]
|
|
:::
|
|
::: Perform a global regular expression search and replace operation on
|
|
::: each line of ASCII input from stdin and prints the result to stdout.
|
|
:::
|
|
::: Each parameter may be optionally enclosed by double quotes. The double
|
|
::: quotes are not considered part of the argument. The quotes are required
|
|
::: if the parameter contains a batch token delimiter like space, tab, comma,
|
|
::: semicolon. The quotes should also be used if the argument contains a
|
|
::: batch special character like &, |, etc. so that the special character
|
|
::: does not need to be escaped with ^.
|
|
:::
|
|
::: Search - By default, this is a case sensitive JScript (ECMA) regular
|
|
::: expression expressed as a string.
|
|
:::
|
|
::: JScript regex syntax documentation is available at
|
|
::: https://msdn.microsoft.com/en-us/library/ae5bf541.aspx
|
|
:::
|
|
::: Replace - By default, this is the string to be used as a replacement for
|
|
::: each found search expression. Full support is provided for
|
|
::: substitution patterns available to the JScript replace method.
|
|
:::
|
|
::: For example, $& represents the portion of the source that matched
|
|
::: the entire search pattern, $1 represents the first captured
|
|
::: submatch, $2 the second captured submatch, etc. A $ literal
|
|
::: can be escaped as $$.
|
|
:::
|
|
::: An empty replacement string must be represented as "".
|
|
:::
|
|
::: Replace substitution pattern syntax is fully documented at
|
|
::: https://msdn.microsoft.com/en-US/library/efy6s3e6.aspx
|
|
:::
|
|
::: Binary input with NULL bytes requires either the /M option, or the file
|
|
::: must be read using ADO by appending the character set name to the file name.
|
|
::: For example, if your input is ASCII containing null bytes, then you must
|
|
::: use: /F "input.txt" /M or /F "input.txt|ascii".
|
|
:::
|
|
::: The meaning of extended ASCII byte codes >= 128 (0x80) is dependent on the
|
|
::: active code page. Extended ASCII within arguments and variables may require
|
|
::: the /XFILE option.
|
|
::/OPTIONS
|
|
:::
|
|
::: Options: Behavior may be altered by appending one or more options.
|
|
::: The option names are case insensitive, and may appear in any order
|
|
::: after the Replace argument.
|
|
:::
|
|
:: /A - write Altered lines only
|
|
:: /APP - Append results to the output file
|
|
:: /B - match Beginning of line
|
|
:: /C - Count number of source lines
|
|
:: /D - Delimiter for /N and /OFF
|
|
:: /E - match End of line
|
|
:: /EOL EndOfLineString - set the End Of Line terminator
|
|
:: /EXC BlockList - EXClude lines from selected blocks
|
|
:: /F InFile[|CharSet[|NB]]- read input from a File
|
|
:: /H - Highlight replaced or matched text
|
|
:: /HON HilightStart - defines the string to start highlighting
|
|
:: /HOFF HilightEnd - defines the string to stop highlighting
|
|
:: /HU - Underline replaced or matched text
|
|
:: /I - Ignore case
|
|
:: /INC BlockList - INClude lines from selected blocks
|
|
:: /J - JScript replace expressions
|
|
:: /JBEG InitCode - initialization JScript code
|
|
:: /JBEGLN NewLineCode - line initialization JScript code
|
|
:: /JEND FinalCode - finalization JScript code
|
|
:: /JENDLN EndLineCode - line finalization JScript code
|
|
:: /JLIB FileList - load file(s) of initialization code
|
|
:: /JMATCH - write matching JScript replacements only
|
|
:: /JMATCHQ - new Quick form of /JMATCH
|
|
:: /JQ - new Quick form of /J
|
|
:: /K Context or Pre:Post - search and Keep lines that match
|
|
:: /L - Literal search
|
|
:: /M - Multi-line mode
|
|
:: /MATCH - Search and print each match, one per line
|
|
:: /N MinWidth - prefix output with liNe numbers
|
|
:: /O OutFile[|CharSet[|NB]]- write Output to a file
|
|
:: /OFF MinWidth - add OFFsets to /K, /JMATCHQ, /MATCH output
|
|
:: /P Regex - only search/replace strings that match a Regex
|
|
:: /PFLAG Flags - set the /P regex Flags to "g", "gi", "" or "i"
|
|
:: /PREPL FilterReplCode - selectively Search/Replace captured /P groups
|
|
:: /R Context or Pre:Post - search and Reject lines that match
|
|
:: /RTN ReturnVar[:Line#] - Return result in a variable
|
|
:: /S VarName - Source is read from a variable
|
|
:: /T DelimChar or FILE - Translate multiple search/replace pairs
|
|
:: /TFLAG Flags - specify XRegExp flags for use with /T
|
|
:: /U - Unix line terminators (\n instead of \r\n)
|
|
:: /UTF - all input and output as UTF-16LE (BOM optional)
|
|
:: /V - use Variables for Search/Replace and code
|
|
:: /VT - enable Virtual Terminal ANSI escape sequences
|
|
:: /X - shorthand for combined /XFILE and /XSEQ
|
|
:: /XBYTES - force creation of new XBYTES.DAT
|
|
:: /XBYTESOFF - force /XSEQ \xnn to be treated as Windows-1252
|
|
:: /XFILE - preserve extended ASCII in args via temp files
|
|
:: /XREG FileList - adds XRegExp support to JREPL
|
|
:: /XSEQ - enable extended escape sequences
|
|
::/
|
|
::: /A - Only write altered lines. Unaltered lines are discarded.
|
|
::: If the /S option is used, then write the result only if
|
|
::: there was a change anywhere in the string. The /A option
|
|
::: is incompatible with the /M option unless the /S option
|
|
::: is also present.
|
|
:::
|
|
::: /APP - Modify /O behavior to Append results to the output file.
|
|
:::
|
|
::: /B - The Search must match the Beginning of a line.
|
|
::: Mostly used with literal searches.
|
|
:::
|
|
::: /C - Count the number of input lines and store the result in global
|
|
::: variable cnt. This value can be useful in JScript code associated
|
|
::: with any of the /Jxxx options.
|
|
:::
|
|
::: This option is implicitly enabled if /INC or /EXC contains a
|
|
::: negative value.
|
|
:::
|
|
::: This option is incompatible with the /M and /S options.
|
|
:::
|
|
::: If the input data is piped or redirected, then the data is first
|
|
::: written to a temporary file, so processing does not start until
|
|
::: the end-of-file is reached.
|
|
:::
|
|
::: /D Delimiter
|
|
:::
|
|
::: Specifies the Delimiter string to use after line numbers and/or
|
|
::: byte offsets that are output due to the /N or /OFF options.
|
|
::: The default value is a colon. The delimiter may be set to an
|
|
::: empty string by using /D "".
|
|
:::
|
|
::: /E - The Search must match the End of a line.
|
|
::: Mostly used with literal searches.
|
|
:::
|
|
::: /EOL EndOfLineString
|
|
:::
|
|
::: Write lines using EndOfLineString as the line terminator.
|
|
::: Standard JScript escape sequences may be used.
|
|
::: The default is "\r\n" (CarriageReturn LineFeed).
|
|
::: The value may be set to an empty string to eliminate linefeeds
|
|
::: from the output.
|
|
:::
|
|
::: /EOL has no effect if the /M option is used unless /MATCH,
|
|
::: /JMATCH, or /JMATCHQ is also used.
|
|
:::
|
|
::: Note that /EOL does not affect input.ReadLine or output.WriteLine
|
|
::: methods in user supplied JScript. ReadLine always accepts both
|
|
::: \r\n and \n as line terminators. And WriteLine always terminates
|
|
::: lines with \r\n.
|
|
:::
|
|
::: /EXC BlockList
|
|
:::
|
|
::: Exclude (do not search/replace) lines that appear within at least
|
|
::: one block within BlockList. A block may be a single line, or a
|
|
::: contiguous range of lines between a start and end line. The /EXC
|
|
::: option is incompatible with /M and /S.
|
|
:::
|
|
::: The syntax for specifying a BlockList is complex. Whitespace
|
|
::: should not appear anywhere except for possibly within a Regex or
|
|
::: String.
|
|
:::
|
|
::: BlockList = {Block}[,{Block}]...
|
|
::: {Block} = {SingleLine}|{LineRange}
|
|
::: {SingleLine} = {LineSpec}[{Offset}]
|
|
::: {LineRange} = {LineSpec}[{Offset}]:{EndLineSpec}[{Offset}]
|
|
::: {LineSpec} = [-]LineNumber|{Regex}[/]|{String}[/]
|
|
::: {EndLineSpec} = [-]LineNumber|+Number|{Regex}|{String}
|
|
::: {Regex} = /Regex/[i|b|e]...
|
|
::: {String} = 'String'[i|b|e]...
|
|
::: {Offset} = +Number|-Number
|
|
:::
|
|
::: A line may be identified by its LineNumber, or by a Regex that
|
|
::: matches the line, or a String literal that is found in the line.
|
|
::: Once identified, a line position may be adjusted forward or
|
|
::: backward via the optional Offset.
|
|
:::
|
|
::: A negative LineNumber is counted from the end of the file.
|
|
::: So 1 is the first line of input, and -1 is the last line. The /C
|
|
::: option is automatically activated if any block identifies a line
|
|
::: via a negative line number.
|
|
:::
|
|
::: A Block Regex uses mostly standard JScript syntax. Both a Regex
|
|
::: and a String may use any of the escape sequences defined by the
|
|
::: /XSEQ option, even if the /XSEQ option has not been set. Any /
|
|
::: literal within a Regex must be escaped as \/. Any ' literal
|
|
::: within a String must be escaped as ''.
|
|
:::
|
|
::: A Regex or String may be followed by any combination of the
|
|
::: following flags:
|
|
::: i - Ignore case
|
|
::: b - The search must match the beginning of a line
|
|
::: e - The search must match the end of a line
|
|
::: /EXC and /INC ignore the /I option.
|
|
:::
|
|
::: A line or range start that is identified by a Regex or String may
|
|
::: match multiple lines within the input. Only the first matching
|
|
::: line is used if the Regex or String is terminated by an extra /.
|
|
:::
|
|
::: A Line block or Range start that is identified by a Regex or
|
|
::: String cannot have a negative Offset.
|
|
:::
|
|
::: If the end of a Range is specified as + followed by a Number,
|
|
::: then the Number is treated as an offset from the start of the
|
|
::: Range (after any start Offset has been applied).
|
|
:::
|
|
::: If the end of a Range is specified as a Regex or String, then the
|
|
::: block end is the first line that matches after the beginning of
|
|
::: the block. The extra / cannot be used with an end of Range Regex
|
|
::: or String. The Offset must be greater than or equal to -1 if a
|
|
::: Regex or String is used. If the end of Range Regex or String is
|
|
::: not found, then the block continues to the end of file.
|
|
:::
|
|
::: Examples:
|
|
:::
|
|
::: /EXC "1:5,10,-5:-1"
|
|
::: Exclude the first 5, 10th, and last 5 lines.
|
|
:::
|
|
::: /EXC "/^:/"
|
|
::: Exclude all lines that begin with a colon
|
|
:::
|
|
::: /EXC "/^Begin$/+1:/^End$/-1"
|
|
::: Exclude all lines that are after a "Begin" line, and before
|
|
::: the next "End" line. Multiple blocks may be excluded.
|
|
:::
|
|
::: /EXC "/^DATA/i/:+10"
|
|
::: Exclude the first line that begins with DATA, ignoring case,
|
|
::: and exclude the next 10 lines as well.
|
|
:::
|
|
::: /EXC "'[START]':'[STOP]'"
|
|
::: Exclude lines beginning with a line that contains the literal
|
|
::: [START] and ending with the next line that contains [STOP].
|
|
:::
|
|
::: /EXC "'[START]'be:'[STOP]'be"
|
|
::: Exclude lines beginning with a [START] line (exact match)
|
|
::: and ending with the next [STOP] line (exact match).
|
|
:::
|
|
::: /F InFile[|CharSet[|NB]]
|
|
:::
|
|
::: Input is read from file InFile instead of stdin.
|
|
:::
|
|
::: If |CharSet (internet character set name) is appended to InFile,
|
|
::: then the file is opened via ADO using the specified CharSet value.
|
|
::: JREPL still recognizes both \n and \r\n as input line terminators
|
|
::: when using ADO. Both ADO and the CharSet must be available on the
|
|
::: local system. Appending |NB to the |CharSet normally has no impact.
|
|
::: The |NB No BOM flag is only useful when combined with /O -.
|
|
:::
|
|
::: Note: Input containing null bytes cannot be read unless ADO is
|
|
::: used, or else the /M option must be used.
|
|
:::
|
|
::: /H - Highlight all replaced or matched text in the output using the
|
|
::: strings defined by /HON and /HOFF.
|
|
:::
|
|
::: /HON and /HOFF default to ANSI escape sequences that swap the
|
|
::: foreground and background colors.
|
|
:::
|
|
::: /HU may be a better option if the current COLOR does not match
|
|
::: the console default.
|
|
:::
|
|
::: Native support for ANSI escape sequences requires Windows 10 or
|
|
::: higher. ANSI escape sequences only work on the Windows 10 console
|
|
::: if the "Use legacy console" option is off in console properties.
|
|
:::
|
|
::: In addition, one of the following must be used:
|
|
:::
|
|
::: - The /VT option can be used to enable the escape sequences for
|
|
::: a single JREPL run.
|
|
:::
|
|
::: or
|
|
:::
|
|
::: - The registry can have the following DWORD defined, which will
|
|
::: enable escape sequences for all console applications.
|
|
::: [HKEY_CURRENT_USER\Console]
|
|
::: "VirtualTerminalLevel"=dword:00000001
|
|
:::
|
|
::: /HON HighlightStart
|
|
:::
|
|
::: Defines the string to start highlighting text, normally an ANSI
|
|
::: escape sequence.
|
|
:::
|
|
::: Default is \x1B[7m - Swap foreground and background colors.
|
|
:::
|
|
::: /HOFF HighlightEnd
|
|
:::
|
|
::: Defines the string to end highlighting text, normally an ANSI
|
|
::: escape sequence.
|
|
:::
|
|
::: Default is \x1B[0m - Return to the console default format.
|
|
:::
|
|
::: /HU - Underline all replaced or matched text in the output using ANSI
|
|
::: escape sequences.
|
|
:::
|
|
::: This is the same as using /H with /HON=\x1B[4m and /HOFF=\x1B[24m
|
|
:::
|
|
::: /I - Ignore case when searching.
|
|
:::
|
|
::: /INC BlockList
|
|
:::
|
|
::: Only Include (search/replace) lines that appear within at least
|
|
::: one block within BlockList. A block may be a single line, or a
|
|
::: contiguous range of lines between a start and end line. The /INC
|
|
::: option is incompatible with /M and /S.
|
|
:::
|
|
::: A line within an /INC block is not included if it also appears
|
|
::: within an /EXC block.
|
|
:::
|
|
::: See the /EXC help for the syntax of a BlockList.
|
|
:::
|
|
::: Examples:
|
|
:::
|
|
::: /INC "1:5,10,-5:-1"
|
|
::: Include the first 5, 10th, and last 5 lines.
|
|
:::
|
|
::: /INC "/^:/"
|
|
::: Include all lines that begin with a colon
|
|
:::
|
|
::: /INC "/^Begin$/+1:/^End$/-1"
|
|
::: Include all lines that are after a "Begin" line, and before
|
|
::: the next "End" line. Multiple blocks may be included.
|
|
:::
|
|
::: /INC "/^DATA/i/:+10"
|
|
::: Include the first line that begins with DATA, ignoring case,
|
|
::: and include the next 10 lines as well.
|
|
:::
|
|
::: /INC "'[START]':'[STOP]'"
|
|
::: Include lines starting with a line that contains the literal
|
|
::: "[START]" and ending with the next line that contains "[STOP]".
|
|
:::
|
|
::: /INC "'[START]'be:'[STOP]'be"
|
|
::: Include lines beginning with a "[START]" line (exact match)
|
|
::: and ending with the next "[STOP]" line (exact match).
|
|
:::
|
|
::: /J - A deprecated form of /JQ that is slow because the JScript code
|
|
::: is executed via the eval() function each and every match. This
|
|
::: form does not use $txt - The replace value is taken as the value
|
|
::: of the last JScript expression within Replace.
|
|
:::
|
|
::: This option is only preserved so as not to break existing scripts.
|
|
:::
|
|
::: /JBEG InitCode
|
|
:::
|
|
::: JScript inititialization code to run prior to loading any input.
|
|
::: This is useful for initializing user defined variables for
|
|
::: accumulating information across matches. The default code is an
|
|
::: empty string.
|
|
:::
|
|
::: /JBEGLN NewLineCode
|
|
:::
|
|
::: JScript code to run at the beginning of each line, prior to
|
|
::: performing any search on the line. The line content may be
|
|
::: manipulated via the $txt variable. The default code is an empty
|
|
::: string. This option is incompatible with the /M and /S options.
|
|
:::
|
|
::: /JEND FinalCode
|
|
:::
|
|
::: JScript termination code to run when there is no more input to
|
|
::: read. This is useful for writing summarization results.
|
|
::: The default code is an empty string.
|
|
:::
|
|
::: /JENDLN EndLineCode
|
|
:::
|
|
::: JScript code to run at the end of each line, after all matches
|
|
::: on the line have been found, but before the result is printed.
|
|
::: The final result can be modified via the $txt variable. Setting
|
|
::: $txt to false discards the line without printing. The $txt value
|
|
::: is ignored if the /JMATCH option has been used. The default
|
|
::: code is an empty string. This option is incompatible with the
|
|
::: /M and /S options.
|
|
:::
|
|
::: /JLIB FileList
|
|
:::
|
|
::: Specifies one or more files that contain libraries of JScript
|
|
::: code to load before /JBEG is run. Multiple files are delimited
|
|
::: by forward slashes (/). Useful for declaring global variables
|
|
::: and functions in a way that is reusable.
|
|
:::
|
|
::: /JMATCH - A deprecated form of /JMATCHQ that is slow because the JScript
|
|
::: code is executed via the eval() function each and every match.
|
|
::: This form does not use $txt - The replace value is taken as the
|
|
::: value of the last JScript expression within Replace.
|
|
:::
|
|
::: This option is only preserved so as not to break existing scripts.
|
|
:::
|
|
::: /JMATCHQ - Write each Replace value on a new line, discarding all text
|
|
::: that does not match the Search. The Replace argument is one or
|
|
::: more JScript statements with access to the same $ variables
|
|
::: available to the /JQ option. The code must store the final replace
|
|
::: value in variable $txt. A $txt value of false indicates the match
|
|
::: is to be ignored.
|
|
:::
|
|
::: Note the trailing Q stands for Quick :-)
|
|
:::
|
|
::: /JQ - The Replace argument is one or more JScript statements that
|
|
::: define the replacement value, and possibly do more. The code
|
|
::: must store the final replace value in variable $txt.
|
|
:::
|
|
::: The following variables contain details about each match:
|
|
:::
|
|
::: $0 is the substring that matched the Search
|
|
::: $1 through $n are the captured submatch strings
|
|
::: $off is the offset where the match occurred
|
|
::: $src is the original source string
|
|
:::
|
|
::: Note the trailing Q stands for Quick :-)
|
|
:::
|
|
::: /K PreContext:PostContext[:FILE]
|
|
::: /K Context[:FILE]
|
|
::: /K COUNT[:FILE]
|
|
:::
|
|
::: Keep matches - Search and write out lines that contain at least
|
|
::: one match, without doing any replacement. The Replace argument is
|
|
::: still required, but is ignored.
|
|
:::
|
|
::: The integers PreContext and PostContext specify how many non-
|
|
::: matching lines to write before the match, and after the match,
|
|
::: respectively. If a single Context integer is given, then the same
|
|
::: number of non-matching lines are written before and after.
|
|
::: A Context of 0 writes only matching lines.
|
|
:::
|
|
::: If the value of Context is COUNT, then matching lines are counted
|
|
::: but not written, and the final match count is written at the end.
|
|
:::
|
|
::: If :FILE is appended to the context, then the Search parameter
|
|
::: specifies a file containing one or more search terms, one term
|
|
::: per line. A line matches if any of the search terms are found
|
|
::: witin the line. The file can be opened via ADO if |CharSet
|
|
::: (internet character set name) is appended to the file name.
|
|
::: Note: the /V option does not apply to Search if /K :FILE is used.
|
|
:::
|
|
::: See /OFF and /N for how to prefix each kept line with the match
|
|
::: byte offset and/or the line number.
|
|
:::
|
|
::: /K is incompatible with /A, /J, /JQ, /JMATCH, /JMATCHQ, /M,
|
|
::: /MATCH, /R, /S, and /T.
|
|
:::
|
|
::: /L - The Search is treated as a string literal instead of a
|
|
::: regular expression. Also, all $ found in the Replace string
|
|
::: are treated as $ literals.
|
|
:::
|
|
::: /M - Multi-line mode. The entire input is read and processed in one
|
|
::: pass instead of line by line, thus enabling search for \n. This
|
|
::: also enables preservation of the original line terminators.
|
|
::: The /M option is incompatible with the /A option unless the /S
|
|
::: option is also present.
|
|
:::
|
|
::: Note: The /M option is one method to read binary data with null
|
|
::: bytes. The other option is to use ADO to read the file.
|
|
::: See the /F option for more info.
|
|
:::
|
|
::: /MATCH - Search and write out each matching string on a new line,
|
|
::: discarding any non-matching text. The Replace argument is
|
|
::: usually ignored, but is still required. However, if the Replace
|
|
::: value is "COUNT", then the matches are counted but not written,
|
|
::: and the final match count is written at the end.
|
|
:::
|
|
::: See /OFF and /N for how to prefix each match with the byte offset
|
|
::: and/or the line number.
|
|
:::
|
|
::: /MATCH is incompatible with /A, /J, /JQ, /JMATCH, /JMATCHQ,
|
|
::: /K, /R and /T.
|
|
:::
|
|
::: /N MinWidth
|
|
:::
|
|
::: Precede each output line with the line number of the source line,
|
|
::: followed by a delimiter (colon by default). The default delimiter
|
|
::: can be overridden with the /D option.
|
|
:::
|
|
::: Line 1 is the first line of the source.
|
|
:::
|
|
::: The MinWidth value specifies the minimum number of digits to
|
|
::: display. The default value is 0, meaning do not display the
|
|
::: line number. A value of 1 displays the line numbers without any
|
|
::: zero padding.
|
|
:::
|
|
::: The /N option is ignored if the /M or /S option is used.
|
|
:::
|
|
::: /O OutFile[|CharSet[|NB]]
|
|
:::
|
|
::: Output is written to file OutFile instead of stdout. Any existing
|
|
::: OutFile is overwritten unless the /APP option is also used.
|
|
:::
|
|
::: If |CharSet (internet character set name) is appended to OutFile,
|
|
::: then the file is opened via ADO using the specified CharSet value.
|
|
::: The output line terminator still defaults to \r\n when using ADO,
|
|
::: and may be changed to \n with the \U option. Both ADO and the
|
|
::: CharSet must be available on the local system. Unicode files
|
|
::: written by ADO have a BOM by default. Appending |NB (or |anyvalue)
|
|
::: to the CharSet blocks the BOM from being written.
|
|
:::
|
|
::: If /F InFile is also used, then an OutFile value of "-" overwrites
|
|
::: the original InFile with the output. A value of "-" preserves the
|
|
::: original input character set (and also any |NB No BOM indicator).
|
|
::: A value of "-|" explicitly transforms the file into the machine
|
|
::: default character set. A "-|CharSet[|NB]" value explicitly
|
|
::: transforms the file into the specified character set. The output
|
|
::: is first written to a temporary file with the same path and name,
|
|
::: with .new appended. Upon completion, the temp file is moved to
|
|
::: replace the InFile.
|
|
:::
|
|
::: It is rarely useful, but /APP may be combined with /O -. But /APP
|
|
::: cannot be combined with /O "-|CharSet".
|
|
:::
|
|
::: /OFF MinWidth
|
|
:::
|
|
::: Ignored unless /JMATCHQ, /JMATCH, /MATCH, or /K is used.
|
|
::: Precede each line of output with the offset of the match within
|
|
::: the original source string, followed by a delimiter (colon by
|
|
::: default). The default delimiter can be overridden with the /D
|
|
::: option. The offset follows the line number if the /N option is
|
|
::: also used.
|
|
:::
|
|
::: Offset 0 is the first character of the source string. The source
|
|
::: string is normally the current line. But if the /M option is used
|
|
::: then the source string is the entire file.
|
|
:::
|
|
::: If used with /K, then the offset represents the first occurrence
|
|
::: of the search string within the line.
|
|
:::
|
|
::: The MinWidth value specifies the minimum number of digits to
|
|
::: display. The default value is 0, meaning do not display the
|
|
::: offset. A value of 1 displays the offsets without any zero
|
|
::: padding.
|
|
:::
|
|
::: /P FilterRegex
|
|
:::
|
|
::: Only Search/Replace strings that match the Pre-filter regular
|
|
::: expression FilterRegex. All escape sequences defined by /XSEQ are
|
|
::: available to FilterRegex, even if /XSEQ has not been set.
|
|
:::
|
|
::: FilterRegex is a global, case sensitive search by default.
|
|
::: The behavior may be changed via the /PFLAG option.
|
|
:::
|
|
::: By default, /P passes the entire matched filter string to the
|
|
::: main Search/Replace routine. If your FilterRegex includes captured
|
|
::: groups, then you can add the /PREPL option to selectively pass one
|
|
::: or more captured groups instead.
|
|
:::
|
|
::: The /P option ignores /I, but honors /M.
|
|
:::
|
|
::: The /P option may be combined with /INC and/or /EXC, in which case
|
|
::: /P is applied after lines have been included and/or excluded.
|
|
:::
|
|
::: Within the main Search argument, ^ matches the beginning of the
|
|
::: matched filter, and $ matches the end of the matched filter.
|
|
:::
|
|
::: Example - Substitute X for each character within curly braces,
|
|
::: including the braces.
|
|
:::
|
|
::: echo abc{xyz}def|jrepl . X /p "{.*?}"
|
|
:::
|
|
::: result:
|
|
:::
|
|
::: abcXXXXXdef
|
|
:::
|
|
::: See /PREPL for an example showing how to preserve the enclosing
|
|
::: braces.
|
|
:::
|
|
::: /PFLAG Flags
|
|
:::
|
|
::: Set the search flags to be used when defining the /P FilterRegex.
|
|
::: Possible values are:
|
|
::: "g" - global, case sensitive (default)
|
|
::: "gi" - global, ignore case
|
|
::: "" - first match only, case sensitive
|
|
::: "i" - first match only, ignore case
|
|
:::
|
|
::: If the search is not global, then the first match of each line
|
|
::: is used. If the /M option is used, then a non-global search uses
|
|
::: only the first match of the entire input.
|
|
:::
|
|
::: Note that the /P FilterRegex multiline mode is contolled by the
|
|
::: /M option. The "m" flag cannot be used with /PFLAG.
|
|
:::
|
|
::: /PREPL FilterReplaceCode
|
|
:::
|
|
::: Specify a JScript expression FilterReplaceCode that controls
|
|
::: what portion of the /P Pre-filter match is passed on to the main
|
|
::: Search/Replace routine, and what portion is preserved as-is.
|
|
:::
|
|
::: The expression is mostly standard JScript, and should evaluate to
|
|
::: a string value. $0 is the entire Pre-filter match, and $1 through
|
|
::: $N are the captured groups. The only non-standard syntax is the
|
|
::: use of curly braces to indicate what string expression gets passed
|
|
::: on to the main Search/Replace. Prior to executing the /P filter,
|
|
::: each brace expression within /PREPL is transformed as follows:
|
|
:::
|
|
::: {Expression} --> (Expression).replace(Search,Replace)
|
|
:::
|
|
::: Any JScript is allowed within /PREPL, except string literals
|
|
::: should not contain $, {, or }.
|
|
:::
|
|
::: Using /P without /PREPL is the same as using /P with /PREPL "{$0}"
|
|
:::
|
|
::: /PREPL cannot be used with /OFF.
|
|
:::
|
|
::: Note that neither /V nor /XFILE apply to /PREPL.
|
|
:::
|
|
::: Example - Substitute X for each character within curly braces,
|
|
::: excluding the braces.
|
|
:::
|
|
::: echo abc{xyz}def|jrepl . X /p "({)(.*?)(})" /prepl "$1+{$2}+$3"
|
|
:::
|
|
::: result:
|
|
:::
|
|
::: abc{XXX}def
|
|
:::
|
|
::: /R PreContext:PostContext[:FILE]
|
|
::: /R Context[:FILE]
|
|
::: /R COUNT[:FILE]
|
|
:::
|
|
::: Reject matches - Search and write out lines that do not contain
|
|
::: any matches, without doing any replacement. The Replace argument
|
|
::: is still required, but is ignored.
|
|
:::
|
|
::: The integers PreContext and PostContext specify how many matching
|
|
::: lines to write before the non-match, and after the non-match,
|
|
::: respectively. If a single Context integer is given, then the same
|
|
::: number of matching lines are written before and after.
|
|
::: A Context of 0 writes only non-matching lines.
|
|
:::
|
|
::: If the value of Context is COUNT, then rejected lines are counted
|
|
::: but not written, and the final reject count is written at the end.
|
|
:::
|
|
::: If :FILE is appended to the context, then the Search parameter
|
|
::: specifies a file containing one or more search terms, one term
|
|
::: per line. A line is rejected if any of the search terms are found
|
|
::: witin the line. The file can be opened via ADO if |CharSet
|
|
::: (internet character set name) is appended to the file name.
|
|
::: Note: the /V option does not apply to Search if /K :FILE is used.
|
|
:::
|
|
::: See /N for how to prefix each rejected line with the line number.
|
|
:::
|
|
::: /R is incomptaible with /A, /J, /JQ, /JMATCH, /JMATCHQ, /K, /M,
|
|
::: /MATCH, /S, and /T.
|
|
:::
|
|
::: /RTN ReturnVar[:[-]LineNumber]
|
|
:::
|
|
::: Write the result to variable ReturnVar.
|
|
:::
|
|
::: If the optional LineNumber is present, then only that specified
|
|
::: line within the result set is returned. A LineNumber of 1 is the
|
|
::: first line. A negative LineNumber is measured from the end of the
|
|
::: result set, so -1 is the last line. /RTN always breaks lines at
|
|
::: \r\n and \n - the /EOL value is ignored.
|
|
:::
|
|
::: All byte codes except NULL (0x00) are preserved, regardless
|
|
::: whether delayed expansion is enabled or not. An error is thrown
|
|
::: and no value stored if the result contains NULL.
|
|
:::
|
|
::: An error is thrown and no value stored if the value does not fit
|
|
::: within a variable. The maximum returned length varies depending
|
|
::: on the variable name and result content. The longest possible
|
|
::: returned length is 8179 bytes.
|
|
:::
|
|
::: The line terminator of the last match is suppressed if /MATCH,
|
|
::: /JMATCH, or /JMATCHQ is used. There is also no line terminator
|
|
::: if LineNumber is specified.
|
|
:::
|
|
::: /RTN uses a temporary output file to transfer the result to the
|
|
::: environment variable. By default the temporary file is written
|
|
::: as UTF-8. But the file is written using the CSCRIPT default code
|
|
::: page if the /XFILE option is used - the action may fail if the
|
|
::: result contains a character that cannot be mapped to the CSCRIPT
|
|
::: default code page.
|
|
:::
|
|
::: /S VarName
|
|
:::
|
|
::: The source is read from environment variable VarName instead
|
|
::: of from stdin. Without the /M option, ^ anchors the beginning
|
|
::: of the string, and $ the end of the string. With the /M option,
|
|
::: ^ anchors the beginning of a line, and $ the end of a line.
|
|
:::
|
|
::: The variable name must not begin with /.
|
|
:::
|
|
::: /T DelimiterChar
|
|
::: /T FILE
|
|
:::
|
|
::: The /T option is very similar to the Oracle Translate() function,
|
|
::: or the unix tr command, or the sed y command.
|
|
:::
|
|
::: The Search represents a set of search expressions, and Replace
|
|
::: is a like sized set of replacement expressions. Expressions are
|
|
::: delimited by DelimiterChar (a single character). If DelimiterChar
|
|
::: is an empty string, then each character is treated as its own
|
|
::: expression. The /L option is implicitly set if DelimiterChar is
|
|
::: empty. Normally escape sequences are interpreted after the search
|
|
::: and replace strings are split into expressions. But if the
|
|
::: DelimiterChar is empty and /XSEQ is used, then escape sequences
|
|
::: are interpreted prior to the split at every character.
|
|
:::
|
|
::: An alternate syntax is to specify the word FILE instead of a
|
|
::: DelimiterChar, in which case the Search and Replace parameters
|
|
::: specify files that contain the search and replace expressions,
|
|
::: one expression per line. Each file can be opened via ADO if
|
|
::: |CharSet (internet character set name) is appended to the file
|
|
::: name. Note that the /V option does not apply to Search and Replace
|
|
::: if /T FILE is used.
|
|
:::
|
|
::: Each substring from the input that matches a particular search
|
|
::: expression is translated into the corresponding replacement
|
|
::: expression.
|
|
:::
|
|
::: The search expressions may be regular expressions, possibly with
|
|
::: captured groups. Note that each expression is itself converted into
|
|
::: a captured group behind the scene, and the operation is performed
|
|
::: as a single search/replace upon execution. So backreferences within
|
|
::: each regex, and $n references within each replacement expression,
|
|
::: must be adjusted accordingly. The total number of expressions plus
|
|
::: captured groups must not exceed 99.
|
|
:::
|
|
::: If an expression must include a delimiter, then an escape
|
|
::: sequence must be used (not an issue if the FILE syntax is used).
|
|
:::
|
|
::: Search expressions are tested from left to right. The left most
|
|
::: matching expression takes precedence when there are multiple
|
|
::: matching expressions.
|
|
:::
|
|
::: Examples using /T:
|
|
:::
|
|
::: ROT13 - Simple character substitution is achieved by setting the
|
|
::: /T delimiter to an empty string. The search and replace strings
|
|
::: must have identical length. The use of line continuation aligns
|
|
::: the replace string directly below the search string, thus making
|
|
::: it very easy to see exactly how each character will be translated.
|
|
::: The "a" in the search string will be replaced by the "n" in the
|
|
::: replace string. And you can see the symmetry in that the "n" will
|
|
::: be replaced by "a".
|
|
:::
|
|
::: echo The quick brown fox jumps over a lazy dog | jrepl^
|
|
::: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"^
|
|
::: "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM"^
|
|
::: /t ""
|
|
:::
|
|
::: -- OUTPUT --
|
|
:::
|
|
::: Gur dhvpx oebja sbk whzcf bire n ynml qbt
|
|
:::
|
|
::: Simple string substitution - The /T option specifies that string
|
|
::: expressions are delimited by a space. The /L option prevents "."
|
|
::: from being interpreted as a regex wildcard character.
|
|
:::
|
|
::: echo The blackbird flew through the blue sky. | jrepl^
|
|
::: "black blue sky ." "blue black night !" /l /t " "
|
|
:::
|
|
::: -- OUTPUT--
|
|
:::
|
|
::: The bluebird flew through the black night!
|
|
:::
|
|
::: Simple string substitution using FILE - This is the same as the
|
|
::: prior example, except now the Search and Replace strings are in
|
|
::: the following files:
|
|
:::
|
|
::: find.txt repl.txt
|
|
::: -------- --------
|
|
::: black blue
|
|
::: blue black
|
|
::: sky night
|
|
::: . !
|
|
:::
|
|
::: The following command yields the same output as before:
|
|
:::
|
|
::: echo The blackbird flew through the blue sky. | jrepl^
|
|
::: find.txt repl.txt /l /t file
|
|
:::
|
|
::: Pig Latin - This example shows how /T can be used with regular
|
|
::: expressions, and it demonstrates how the numbering of captured
|
|
::: groups must be adjusted. The /T delimiter is set to a space.
|
|
:::
|
|
::: The first regex is captured as $1, and it matches words that begin
|
|
::: with a consonant. The first captured group ($2) contains the initial
|
|
::: sequence of consonants, and the second captured group ($3) contains
|
|
::: the balance of the word. The corresponding replacement string moves
|
|
::: $2 after $3, with a "-" in between, and appends "ay".
|
|
:::
|
|
::: The second regex matches any word, and it is captured as $4 because
|
|
::: the prior regex ended with group $3. Because the first regex matched
|
|
::: all words that begin with consonants, the only thing the second
|
|
::: regex can match is a word that begins with a vowel. The replacement
|
|
::: string simply adds "-yay" to the end of $4. Note that $& could have
|
|
::: been used instead of $4, and it would yield the same result.
|
|
:::
|
|
::: echo Can you speak Pig Latin? | jrepl^
|
|
::: "\b((?:qu(?=[aeiou])|[bcdfghj-np-twxz])+)([a-z']+)\b \b[a-z']+\b"^
|
|
::: "$3-$2ay $4-yay" /t " " /i
|
|
:::
|
|
::: -- OUTPUT --
|
|
:::
|
|
::: an-Cay you-yay eak-spay ig-Pay atin-Lay?
|
|
:::
|
|
::: Pig-Latin with proper capitalization - This is simply an extension
|
|
::: of the prior example. The /JBEG option defines a fixCaps() function
|
|
::: that checks if the translated word is all lower case, except for one
|
|
::: capital letter after the "-". If so, then the initial letter is
|
|
::: capitalized, and the remainder is converted to lower caae. The /JQ
|
|
::: option treats the replacement strings as JScript expressions. The
|
|
::: first replacement expression uses fixCaps() to properly restore case.
|
|
:::
|
|
::: echo Can you speak Pig Latin? | jrepl^
|
|
::: "\b((?:qu(?=[aeiou])|[bcdfghj-np-twxz])+)([a-z']+)\b \b[a-z']+\b"^
|
|
::: "$txt=fixCaps($3+'-'+$2+'ay') $txt=$4+'-yay'"^
|
|
::: /t " " /i /j /jbeg ^"^
|
|
::: function fixCaps(str){^
|
|
::: return str.search(/[a-z']+-[A-Z][a-z]*$/)==0 ?^
|
|
::: str.substr(0,1).toUpperCase()+str.substr(1).toLowerCase() : str^
|
|
::: }^"
|
|
:::
|
|
::: -- OUTPUT --
|
|
:::
|
|
::: An-cay you-yay eak-spay Ig-pay Atin-lay?
|
|
:::
|
|
::: /TFLAG Flags
|
|
:::
|
|
::: Used to specify XRegExp non-standard mode flags for use with /T.
|
|
::: /TFLAG is ignored unless both /T and /XREG are used.
|
|
:::
|
|
::: /U - Write lines using a Unix line terminator \n instead of Windows
|
|
::: terminator of \r\n. This is the same as using /EOL "\n".
|
|
::: See /EOL help for more info.
|
|
:::
|
|
::: /UTF - All input and output encodings are Unicode UTF-16 Little
|
|
::: Endian (UTF-16LE). This includes stdin and stdout. The only
|
|
::: exceptions are /JLIB and /XREG files, which are still read
|
|
::: as ASCII.
|
|
:::
|
|
::: The \xFF\xFE BOM is optional for input.
|
|
:::
|
|
::: Output files will automatically have the \xFF\xFE BOM inserted.
|
|
::: But stdout will not have the BOM.
|
|
:::
|
|
::: Regular expression support of Unicode can be improved by using
|
|
::: the /XREG option.
|
|
:::
|
|
::: Variables are never written to temporary files (/XFILE is ignored)
|
|
::: if /UTF is used.
|
|
:::
|
|
::: Unfortunately, /UTF is incompatible with /RTN.
|
|
:::
|
|
::: /V - Search, Replace, /INC BlockList, /EXC BlockList, /P FilterRegex,
|
|
::: /JBEG InitCode, /JBEGLN NewLineCode, /JEND FinalCode, and
|
|
::: /JENDLN EndLineCode all represent the names of environment
|
|
::: variables that contain the respective values. An undefined
|
|
::: variable is treated as an empty string.
|
|
:::
|
|
::: Variable names beginning with / are reserved for option storage
|
|
::: and other internal uses. So user defined variables used with /V
|
|
::: must not have a name that begins with /.
|
|
:::
|
|
::: /VT - Enables Virtual Terminal processing of ANSI escape sequences for
|
|
::: the current JREPL.bat process within the Windows 10 console. This
|
|
::: option is not needed if the registry has HKEY_CURRENT_USER\Console
|
|
::: "VirtualTerminalLevel" DWORD set to 1 in the registry.
|
|
:::
|
|
::: /X - Shorthand for combined /XFILE and /XSEQ.
|
|
:::
|
|
::: /XBYTES - Force creation of a new XBYTES.DAT file for use by the /XSEQ
|
|
::: option when decoding \xnn sequences.
|
|
:::
|
|
::: /XBYTESOFF - Force JREPL to use pre v7.4 behavior where /XSEQ \xnn is
|
|
::: always interpreted as Windows-1252.
|
|
:::
|
|
::: /XFILE - Preserves extended ASCII characters that may appear within
|
|
::: command line arguments and/or variables by first writing the
|
|
::: values to temporary files within the %TEMP% directory. Extended
|
|
::: ASCII values are byte codes >= 128 (0x80).
|
|
:::
|
|
::: Temporary files may be needed when the cmd.exe active code page
|
|
::: does not match the default code page used by the CSCRIPT engine.
|
|
::: The default CSCRIPT code page is defined in the registry under
|
|
::: \HKLM\SYSTEM\CurrentControlSet\Control\Nls\CodePage\ACP.
|
|
:::
|
|
::: The temporary files are written using the cmd.exe active code page.
|
|
::: The files are read using the CSCRIPT default code page. Extended
|
|
::: ASCII output to the console may appear wrong, but output written
|
|
::: to a file will be correct based on the cmd.exe active code page.
|
|
:::
|
|
::: /XFILE is ignored (no temporary files written) if /UTF is used.
|
|
:::
|
|
::: /XREG FileList
|
|
:::
|
|
::: Adds support for XRegExp by loading the xregexp files specified
|
|
::: in FileList before any /JLIB code is loaded. Multiple files are
|
|
::: delimited by forward slashes (/). If FileList is simply a dot,
|
|
::: then substitute the value of environment variable XREGEXP for
|
|
::: the FileList.
|
|
:::
|
|
::: The simplest option is to load "xregexp-all.js", but this
|
|
::: includes all available XRegExp options and addons, some of which
|
|
::: are unlikely to be useful to JREPL. Alternatively you can load
|
|
::: only the specific modules you need, but they must be loaded in the
|
|
::: correct order.
|
|
:::
|
|
::: Once the XRegExp module(s) are loaded, all user supplied regular
|
|
::: expressions are created using the XRegExp constructor rather than
|
|
::: the standard RegExp constructor. Also, XRegExp.install('natives')
|
|
::: is executed so that many standard regular expression methods are
|
|
::: overridden by XRegExp methods.
|
|
:::
|
|
::: /XREG requires XRegExp version 2.0.0 or 3.x.x. JREPL will not
|
|
::: support version 4.x.x (when it is released) because v4.x.x
|
|
::: is scheduled to drop support for XRegExp.install('natives').
|
|
:::
|
|
::: One of the key features of XRegExp is that it extends the JScript
|
|
::: regular expression syntax to support named capture groups, as in
|
|
::: (?<name>anyCapturedExpression). Named backreference syntax in
|
|
::: regular expressions is \k<name>. Named group syntax in Replace
|
|
::: strings is ${name}, and in Replace JScript code the syntax is
|
|
::: $0.name
|
|
:::
|
|
::: The /T option is no longer limited to 99 capture groups when
|
|
::: /XREG is used. However, /T replace expressions must reference a
|
|
::: captured group by name if the capture index is 100 or above.
|
|
:::
|
|
::: Every /T search expression is automatically given a capture group
|
|
::: name of Tn, where n is the 0 based index of the /T expression.
|
|
:::
|
|
::: XRegExp also adds support for non-standard mode flags:
|
|
::: n - Explicit capture
|
|
::: s - Dot matches all
|
|
::: x - Free spacing and line comments
|
|
::: A - Astral
|
|
::: These flags can generally be applied by using (?flags) syntax
|
|
::: at the begining of any regex. This is true for /P, /INC, /EXC,
|
|
::: and most Find regular expressions. The one exception is /T doesn't
|
|
::: support (?flags) at the beginning of the Find string. The /TFLAG
|
|
::: option should be used to specify XRegExp flags for use with /T.
|
|
:::
|
|
::: XRegExp also improves regular expression support for Unicode via
|
|
::: \p{Category}, \p{Script}, \p{InBlock}, \p{Property} escape
|
|
::: sequences, as well as the negated forms \P{...} and \p{^...}.
|
|
::: Note that example usage on xregexp.com shows use of doubled back
|
|
::: slashes like \\p{...}. But JREPL automatically does the doubling
|
|
::: for you, so you should use \p{...} instead.
|
|
:::
|
|
::: See xregexp.com for more information about the capabilities of
|
|
::: XRegExp, and for links to download XRegExp.
|
|
:::
|
|
::: /XSEQ - Enables extended escape sequences for both Search strings and
|
|
::: Replacement strings, with support for the following sequences:
|
|
:::
|
|
::: \\ - Backslash
|
|
::: \b - Backspace
|
|
::: \c - Caret (^)
|
|
::: \f - Formfeed
|
|
::: \n - Newline
|
|
::: \q - Quote (")
|
|
::: \r - Carriage Return
|
|
::: \t - Horizontal Tab
|
|
::: \v - Vertical Tab
|
|
::: \xnn - Extended ASCII byte code expressed as 2 hex digits nn.
|
|
::: The code is mapped to the correct Unicode code point,
|
|
::: depending on the chosen character set. If used within
|
|
::: a Find string, then the input character set is used. If
|
|
::: within a Replacement string, then the output character
|
|
::: set is used. If the selected character set is invalid or
|
|
::: not a single byte character set, then \xnn is treated as
|
|
::: a Unicode code point. Note that extended ASCII character
|
|
::: class ranges like [\xnn-\xnn] should not be used because
|
|
::: the intended range likely does not map to a contiguous
|
|
::: set of Unicode code points - use [\x{nn-mm}] instead.
|
|
::: \x{nn-mm} - A range of extended ASCII byte codes for use within
|
|
::: a regular expression character class expression. The
|
|
::: The min value nn and max value mm are expressed as hex
|
|
::: digits. The range is automatically expanded into the
|
|
::: full set of mapped Unicode code points. The character
|
|
::: set mapping rules are the same as for \xnn.
|
|
::: \x{nn,CharSet} - Same as \xnn, except explicitly uses CharSet
|
|
::: character set mapping.
|
|
::: \x{nn-mm,CharSet} - Same as \x{nn-mm}, except explicitly uses
|
|
::: CharSet character set mapping.
|
|
::: \unnnn - Unicode code point expressed as 4 hex digits nnnn.
|
|
::: \u{N} - Any Unicode code point where N is 1 to 6 hex digits
|
|
:::
|
|
::: JREPL automatically creates an XBYTES.DAT file containing all 256
|
|
::: possible byte codes. The XBYTES.DAT file is preferentially created
|
|
::: in "%ALLUSERSPROFILE%\JREPL\" if at all possible. Otherwise the
|
|
::: file is created in "%TEMP%\JREPL\" instead. JREPL uses the file
|
|
::: to establish the correct \xnn byte code mapping for each character
|
|
::: set. Once created, successive runs reuse the same XBYTES.DAT file.
|
|
::: If the file gets corrupted, then use the /XBYTES option to force
|
|
::: creation of a new XBYTES.DAT file. If JREPL cannot create the file
|
|
::: for any reason, then JREPL silently defaults to using pre v7.4
|
|
::: behavior where /XSEQ \xnn is interpreted as Windows-1252. Creation
|
|
::: of XBYTES.DAT requires either CERTUTIL.EXE or ADO. It is possible
|
|
::: that both may be missing from an XP machine.
|
|
:::
|
|
::: Without the /XSEQ option, only standard JSCRIPT escape sequences
|
|
::: \\, \b, \f, \n, \r, \t, \v, \xnn, \unnnn are available for the
|
|
::: search strings. And the \xnn sequence represents a unicode
|
|
::: code point, not extended ASCII.
|
|
:::
|
|
::: Extended escape sequences are supported even when the /L option
|
|
::: is used. Both Search and Replace support all of the extended
|
|
::: escape sequences if both the /XSEQ and /L options are combined.
|
|
:::
|
|
::: Extended escape sequences are not applied to JScript code when
|
|
::: using any of the /Jxxx options. Use the decode() function if
|
|
::: extended escape sequences are needed within the code.
|
|
:::
|
|
::/JSCRIPT
|
|
:::
|
|
::: The following global JScript variables/objects/functions are available for
|
|
::: use in JScript code associated with the /Jxxx options. User code may safely
|
|
::: declare additional variables/objects/functions because all other internal
|
|
::: objects used by JREPL are hidden behind an opaque _g object.
|
|
:::
|
|
::: ln - Within /JBEGLN, /JENDLN, and Replace code = current line number
|
|
::: Within /JBEG code = 0
|
|
::: Within /JEND code = total number of lines read.
|
|
::: This value is always 0 if the /M or /S option is used.
|
|
:::
|
|
::: cnt - The total number of lines in the input. The value is undefined
|
|
::: unless the /C option is used.
|
|
:::
|
|
::: counter - A general purpose counter that is initialized to 0. This
|
|
::: variable is used by /K COUNT and /R COUNT to track the number
|
|
::: of kept/rejected lines, and by /MATCH with a "COUNT" replace
|
|
::: value to track the number of matches.
|
|
:::
|
|
::: skip - If true, do not search/replace any more lines until the value
|
|
::: becomes false. /JBEGLN and /JENDLN code are still executed for
|
|
::: each line, regardless. If set to true while in the midst of
|
|
::: searching a line, then that search will continue to the end of
|
|
::: the current line.
|
|
:::
|
|
::: The default value is false.
|
|
:::
|
|
::: This variable has no impact if the /M or /S options is used.
|
|
:::
|
|
::: Note that this variable operates independently of the /INC
|
|
::: and /EXC options.
|
|
:::
|
|
::: quit - If true, then do not read any more lines of input. The current
|
|
::: line is still processed to completion, and /JEND code is still
|
|
::: executed afterward.
|
|
:::
|
|
::: The default value is false.
|
|
:::
|
|
::: This variable has no impact if the /M or /S options is used.
|
|
:::
|
|
::: env('varName')
|
|
:::
|
|
::: Access to environment variable named varName.
|
|
:::
|
|
::: decode( String [,CharSet] )
|
|
:::
|
|
::: Decodes extended escape sequences within String as defined by
|
|
::: the /XSEQ option, and returns the result. CharSet specifies the
|
|
::: single byte character set to use for \xnn escape sequences.
|
|
::: If CharSet is 'input', then the character set of the input is
|
|
::: used. If CharSet is 'output', then the character set of the
|
|
::: output is used. If CharSet is 'default' or undefined, then the
|
|
::: default character set for the machine is used. Otherwise,
|
|
::: CharSet should be a valid internet character set name understood
|
|
::: by the machine. If the selected character set is invalid or not
|
|
::: a single byte character set, then \xnn is treated as a Unicode
|
|
::: code point.
|
|
:::
|
|
::: All backslashes within String must be escaped an extra time to
|
|
::: use this function in your code.
|
|
:::
|
|
::: Examples:
|
|
::: quote literal: decode('\\q','output')
|
|
::: extended ASCII(128): decode('\\x80','output')
|
|
::: backslash literal: decode('\\\\','output')
|
|
:::
|
|
::: This function is only needed if you use any \q, \c, or \u{N}
|
|
::: escape sequences, or \xnn escape sequence for extended ASCII.
|
|
:::
|
|
::: lpad( value, padString )
|
|
::: lpad( value, length [,padString] )
|
|
:::
|
|
::: Used to left pad a value to a minimum width string. If the
|
|
::: value already has string width >= the desired length, then no
|
|
::: change is made. Otherwise it left pads the value with the
|
|
::: characters of the pad string to the desired length. If only
|
|
::: padString is specified, then the value is padded to the length
|
|
::: of padString. If length is specified with a padString, then
|
|
::: padString is replicated as needed to get the desired length.
|
|
::: If length is specified without padString, then spaces are used
|
|
::: for the padString.
|
|
:::
|
|
::: Examples:
|
|
::: lpad(15,' ') returns ' 15'
|
|
::: lpad(15,4) returns ' 15'
|
|
::: lpad(15,'0000') returns '0015'
|
|
::: lpad(15,4,'0') returns '0015'
|
|
::: lpad(19011,4,'0') returns '19011'
|
|
::: lpad('A','. . . . .') returns '. . . . .A'
|
|
::: lpad('A',9,'. ') returns '. . . . .A'
|
|
::: lpad('AB','. . . . .') returns '. . . . AB'
|
|
::: lpad('AB',9,'. ') returns '. . . . AB'
|
|
:::
|
|
::: rpad( value, padString )
|
|
::: rpad( value, length [,padString] )
|
|
:::
|
|
::: Used to right pad a value to a minimum width string. If the
|
|
::: value already has string width >= the desired length, then no
|
|
::: change is made. Otherwise it right pads the value with the
|
|
::: characters of the pad string to the desired length. If only
|
|
::: padString is specified, then the value is padded to the length
|
|
::: of padString. If length is specified with a padString, then
|
|
::: padString is replicated as needed to get the desired length.
|
|
::: If length is specified without padString, then spaces are used
|
|
::: for the padString.
|
|
:::
|
|
::: Examples:
|
|
::: rpad('hello',' ') returns 'hello '
|
|
::: rpad('hello',10) returns 'hello '
|
|
::: rpad('hello',' . . . . .') returns 'hello. . .'
|
|
::: rpad('hello',10,' .') returns 'hello. . .'
|
|
::: rpad('hell',' . . . . .') returns 'hell . . .'
|
|
::: rpad('hell',10,' .') returns 'hell . . .'
|
|
::: rpad('hello',2) returns 'hello'
|
|
:::
|
|
::: inc( [blockNum] )
|
|
:::
|
|
::: A boolean function that returns true or false.
|
|
:::
|
|
::: Returns true if the current line appears within the specified
|
|
::: /INC blockNum. A blockNum of 0 specifies the first /INC block.
|
|
:::
|
|
::: If blockNum is not specified, then returns true if the current
|
|
::: line appears within any /INC block.
|
|
:::
|
|
::: exc( [blockNum] )
|
|
:::
|
|
::: A boolean function that returns true or false.
|
|
:::
|
|
::: Returns true if the current line appears within the specified
|
|
::: /EXC blockNum. A blockNum of 0 specifies the first /EXC block.
|
|
:::
|
|
::: If blockNum is not specified, then returns true if the current
|
|
::: line appears within any /EXC block.
|
|
:::
|
|
::: fso - An instantiation of the FileSystemObject object.
|
|
:::
|
|
::: input - The TextStream object from which input is read.
|
|
::: This may be stdin or a file.
|
|
:::
|
|
::: If the file was opened by ADO with |CharSet, then input is
|
|
::: an object that partially emulates a TextStream object, with
|
|
::: a private ADO Stream doing the actual work. The following
|
|
::: public members are available to the ADO object:
|
|
:::
|
|
::: Property Method
|
|
::: ------------- ----------
|
|
::: AtEndOfStream Read
|
|
::: ReadLine (line terminator \n or \r\n)
|
|
::: SkipLine (line terminator \n or \r\n)
|
|
::: Write
|
|
::: WriteLine (line terminator always \r\n)
|
|
::: Close
|
|
:::
|
|
::: output - The TextStream object to which the output is written.
|
|
::: This may be stdout or a file. If /RTN is used, then the output
|
|
::: is first written to a temporary file before it is read and
|
|
::: stored in the return variable.
|
|
:::
|
|
::: If the file was opened by ADO with |CharSet, then output is
|
|
::: an object that partially emulates a TextStream object (see the
|
|
::: input object).
|
|
:::
|
|
::: stdin - Equivalent to WScript.StdIn
|
|
:::
|
|
::: stdout - Equivalent to WScript.StdOut
|
|
:::
|
|
::: stderr - Equivalent to WScript.StdErr
|
|
:::
|
|
::: openOutput( fileName[|CharSet[|NB]] [,appendBoolean [,utfBoolean]] )
|
|
:::
|
|
::: Open a new TextStream object for writing and assign it to the
|
|
::: output variable. If appendBoolean is truthy, then open the file
|
|
::: for appending.
|
|
:::
|
|
::: If |CharSet is appended to the fileName, then open the file
|
|
::: using ADO and the specified internet character set name. The
|
|
::: output variable will be set to an object that partially
|
|
::: emulates a TextStream object (see the input object). Unicode
|
|
::: written by ADO will have a BOM by default. The BOM is blocked
|
|
::: by appending |NB (or |anyValue) to the CharSet.
|
|
:::
|
|
::: If utfBoolean is truthy, then output is encoded as unicode
|
|
::: (UTF-16LE). The unicode file will automatically have the BOM
|
|
::: unless opened for appending. The utfBoolean argument is ignored
|
|
::: if |CharSet is also specified.
|
|
:::
|
|
::: If fileName is falsey, then output is written to stdout.
|
|
:::
|
|
::: All subsequent output will be written to the new destination.
|
|
:::
|
|
::: Any prior output file is automatically closed.
|
|
:::
|
|
::: eol - The line terminator used when writing output lines. This is the
|
|
::: same value set by the /EOL option.
|
|
:::
|
|
::: See the /JQ option help for info about local $ variables that may be used
|
|
::: within replacement code when using /JQ or /JMATCHQ.
|
|
::/HELP
|
|
:::
|
|
::: Help is available by supplying a single argument beginning with /? or /??:
|
|
:::
|
|
::: /? - Writes all available help to stdout.
|
|
::: /?? - Same as /? except uses MORE for pagination.
|
|
:::
|
|
::: /?Topic - Writes help about the specified topic to stdout.
|
|
::: Valid topics are:
|
|
:::
|
|
::: INTRO - Basic syntax and default behavior
|
|
::: OPTIONS - Brief summary of all options
|
|
::: JSCRIPT - JREPL objects available to user JScript
|
|
::: RETURN - All possible return codes
|
|
::: VERSION - Display the version of JREPL.BAT
|
|
::: HISTORY - A summary of all releases
|
|
::: HELP - Lists all methods of getting help
|
|
:::
|
|
::: Example: List a summary of all available options
|
|
:::
|
|
::: jrepl /?options
|
|
:::
|
|
::: /?WebTopic - Opens up a web page within your browser about a topic.
|
|
::: Valid web topics are:
|
|
:::
|
|
::: REGEX - Microsoft regular expression documentation
|
|
::: REPLACE - Microsoft Replace method documentation
|
|
::: UPDATE - DosTips release page for JREPL.BAT
|
|
::: CHARSET - List of possible character set names for ADO I/O
|
|
::: Some character sets may not be installed
|
|
::: XREGEXP - xRegExp.com home page (extended regex docs)
|
|
:::
|
|
::: /?/Option - Writes detailed help about the specified /Option to stdout.
|
|
:::
|
|
::: Example: Display paged help about the /T option
|
|
:::
|
|
::: jrepl /??/t
|
|
:::
|
|
::: /?CHARSET/[Query] - List all character set names for use with ADO I/O
|
|
::: that are installed on this computer. Optionally restrict
|
|
::: the list to names that contain Query. Wildcards * and ? may
|
|
::: be used within Query. The default Query is an empty string,
|
|
::: meaning list all available character sets. The list is
|
|
::: generated via reg.exe.
|
|
:::
|
|
::: Examples:
|
|
:::
|
|
::: jrepl /??charset/ - Paged list of all available names
|
|
::: jrepl /?charset/utf - List of names containing "utf"
|
|
::/RETURN
|
|
:::
|
|
::: Possible ERRORLEVEL Return Codes:
|
|
:::
|
|
::: If /? was used, and no other argument
|
|
::: 0 = Only possible return
|
|
:::
|
|
::: If /MATCH, /JMATCH, /JMATCHQ, /K, and /R were not used
|
|
::: 0 = At least one change was made
|
|
::: 1 = No change was made
|
|
::: 2 = Invalid call syntax or incompatible options
|
|
::: 3 = JScript runtime error
|
|
:::
|
|
::: If /MATCH, /JMATCH, /JMATCHQ, /K, or /R was used
|
|
::: 0 = At least one line was written
|
|
::: 1 = No line was written
|
|
::: 2 = Invalid call syntax or incompatible options
|
|
::: 3 = JScript runtime error
|
|
::/VERSION
|
|
:::
|
|
::: JREPL.BAT version 8.6 was written by Dave Benham, and originally posted at
|
|
::: http://www.dostips.com/forum/viewtopic.php?f=3&t=6044
|
|
::/
|
|
|
|
============= :Batch portion ===========
|
|
@echo off
|
|
setlocal disableDelayedExpansion
|
|
|
|
:: Process Help
|
|
if .%2 equ . call :help "%~1" && exit /b 0 || call :exitErr "Insufficient arguments"
|
|
|
|
:: Define options
|
|
set ^"/options= /A: /APP: /B: /C: /D:":" /DBUG: /E: /EOL:"\r\n" /EXC:"" /F:"" /H: /HON:"\x1B[7m" /HOFF:"\x1B[0m"^
|
|
/HU: /I: /INC:"" /J: /JBEG:"" /JBEGLN:"" /JEND:"" /JENDLN:"" /JLIB:"" /JMATCH: /JMATCHQ: /JQ:^
|
|
/K:"" /L: /M: /MATCH: /N:0 /O:"" /OFF:0 /P:"" /PFLAG:"g" /PREPL:"" /R:"" /RTN:"" /S:""^
|
|
/T:"none" /TFLAG:"" /U: /UTF: /V: /VT: /X: /XBYTES: /XBYTESOFF: /XFILE: /XSEQ: /XREG:"" ^"
|
|
:: Set default option values
|
|
for %%O in (%/options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
|
|
|
|
:: Get options
|
|
:loop
|
|
if not "%~3"=="" (
|
|
set "/test=%~3"
|
|
setlocal enableDelayedExpansion
|
|
if "!/test:~0,1!" neq "/" call :exitErr "Too many arguments"
|
|
set "/test=!/options:*%~3:=! "
|
|
if "!/test!"=="!/options! " (
|
|
endlocal
|
|
call :exitErr "Invalid option %~3"
|
|
) else if "!/test:~0,1!"==" " (
|
|
endlocal
|
|
set "%~3=1"
|
|
) else (
|
|
endlocal
|
|
set "%~3=%~4"
|
|
shift /3
|
|
)
|
|
shift /3
|
|
goto :loop
|
|
)
|
|
|
|
:: Validate options
|
|
if defined /M if defined /A if not defined /S call :exitErr "/M cannot be used with /A without /S"
|
|
if "%/O%" equ "-" if not defined /F call :exitErr "Output = - but Input file not specified"
|
|
if defined /F if defined /S call :exiterr "/S cannot be used with /F"
|
|
if defined /F for %%A in ("%/F%") do for %%B in ("%/O%") do if "%%~fA" equ "%%~fB" call :exitErr "Output file cannot match Input file"
|
|
if defined /RTN if defined /O call :exitErr "/O and /RTN are mutually exclusive"
|
|
if defined /RTN if defined /UTF call :exitErr "/UTF and /RTN are mutually exclusive"
|
|
if "%/EXC%%/INC%%/C%%/JBEGLN%%/JENDLN%" neq "" if "%/M%%/S%" neq "" call :exitErr "/C, /INC, /EXC, /JBEGLN, and /JENDLN cannot be used with /M or /S"
|
|
for /f "tokens=2" %%A in ("%/J% %/JQ% %/JMATCH% %/JMATCHQ% %/K% %/R% %/MATCH%") do call :exitErr "/J, /JQ, /JMATCH, /JMATCHQ, /MATCH, /K and /R are all mutually exclusive"
|
|
if "%/K%%/R%" neq "" if "%/A%%/M%%/S%%/T%" neq "none" call :exitErr "/K, /R cannot be used with /A, /M, /S or /T"
|
|
if defined /MATCH if "%/A%%/T%" neq "none" call :exitErr "/MATCH cannot be used with /A or /T"
|
|
for /f delims^=giGI^ eol^= %%A in ("%/PFLAG%") do call :exitErr "Invalid /PFLAG value"
|
|
if "%/OFF%" neq "0" if defined /PREPL call :exitErr "/PREPL cannot be used with /OFF"
|
|
for /f "delims=| eol=| tokens=2*" %%A in ("%/APP%|%/O%x") do if %%A==- if .%%B neq . call :exitErr "/APP cannot be combined with /O - with CharSet"
|
|
|
|
:: Transform options
|
|
if "%/XREG%"=="." (set /XREG=%XREGEXP%)
|
|
if defined /X set "/XFILE=1" & set "/XSEQ=1"
|
|
if defined /MATCH set "/JMATCHQ=1"
|
|
if defined /JMATCHQ set "/JMATCH=1"
|
|
if defined /JMATCH set "/J=1"
|
|
if defined /JQ set "/J=1"
|
|
if "%/JMATCH%%/K%" equ "" set "/OFF=0"
|
|
if defined /UTF set "/UTF=//u" & set "/XFILE="
|
|
if not defined /T set "/L=1"
|
|
if "%/M%%/S%" neq "" set "/N=0"
|
|
if defined /U set "/EOL=\n"
|
|
if defined /HU (
|
|
set "/H=1"
|
|
set "/HON=\x1B[4m"
|
|
set "/HOFF=\x1B[24m"
|
|
)
|
|
if defined /R set "/H="
|
|
if defined /RTN (
|
|
setlocal enableDelayedExpansion
|
|
for /f "eol=: delims=: tokens=1,2" %%A in ("!/RTN!") do (
|
|
endlocal
|
|
set "/RTN=%%A"
|
|
set "/RTN_LINE=%%B"
|
|
)
|
|
)
|
|
|
|
if defined /XBYTESOFF set "/XBYTES=" & goto :endXBytes
|
|
if defined /XBYTES set "/XBYTES=" & goto :createXBytes
|
|
for %%F in (
|
|
"%ALLUSERSPROFILE%\JREPL\XBYTES.DAT"
|
|
"%TEMP%\JREPL\XBYTES.DAT"
|
|
"%TMP%\JREPL\XBYTES.DAT"
|
|
) do if "%%~zF" equ "256" set "/XBYTES=%%~fF" & goto :endXBytes
|
|
|
|
:createXBytes
|
|
:: Attempt to create XBYTES.DAT via CERTUTIL. If able to write to the JREPL
|
|
:: subdirectory, but unable to create correct file, then pass task to JScript.
|
|
for %%F in (
|
|
"%ALLUSERSPROFILE%"
|
|
"%TEMP%"
|
|
"%TMP%"
|
|
) do if %%F neq "" for %%F in ("%%~F\JREPL\XBYTES.DAT") do (
|
|
del %%F
|
|
md "%%~dpF"
|
|
( >"%%~dpnF.HEX" (
|
|
for %%A in (0 1 2 3 4 5 6 7 8 9 A B C D E F) do for %%B in (0 1 2 3 4 5 6 7 8 9 A B C D E F) do echo %%A%%B
|
|
)) && (
|
|
set "/XBYTES=%%~fF"
|
|
certutil.exe -f -decodehex "%%~dpnF.HEX" "%%~fF"
|
|
for %%G in (%%F) do if "%%~zG" neq "256" del %%F
|
|
del "%%~dpnF.HEX"
|
|
goto :endXBytes
|
|
)
|
|
) >nul 2>nul
|
|
:endXBytes
|
|
|
|
set ^"/FIND=%1"
|
|
set ^"/REPL=%2"
|
|
call :GetScript /SCRIPT
|
|
set "/LOCK="
|
|
|
|
set "/FindReplVar="
|
|
if defined /UTF (
|
|
set "/FindReplVar=1"
|
|
set "/FIND2=%/FIND:"=%"
|
|
set "/REPL2=%/REPL:"=%"
|
|
set "/FIND=/FIND2"
|
|
set "/REPL=/REPL2"
|
|
goto :noLock
|
|
)
|
|
if defined /V if /i "%/T%" neq "FILE" set "/FindReplVar=1"
|
|
if defined /XFILE if /i "%/T%" neq "FILE" set "/FindReplVar=1"
|
|
if defined /RTN goto :lock
|
|
if not defined /XFILE goto :noLock
|
|
if defined /FindReplVar goto :lock
|
|
if not defined /JBEG if not defined /JBEGLN if not defined /JEND if not defined /JENDLN if not defined /INC if not defined /EXC if not defined /P if not defined /S goto :noLock
|
|
|
|
:lock
|
|
setlocal enableDelayedExpansion
|
|
set "/LOCK=jrepl.bat.!date:\=-!_!time::=.!_!random!.temp"
|
|
set "/LOCK=!/LOCK:/=-!"
|
|
for /f "delims=" %%F in ("!temp!\!/LOCK::=-!") do (
|
|
endlocal
|
|
set "/LOCK=%%~fF"
|
|
)
|
|
if defined /RTN (
|
|
set "/CHCP="
|
|
if not defined /XFILE for /f "tokens=2 delims=:." %%P in ('chcp') do (
|
|
chcp 65001 >nul 2>nul && (
|
|
set "/CHCP=%%P"
|
|
chcp %%P >nul 2>nul
|
|
)
|
|
)
|
|
if defined /CHCP (set "/O=%/LOCK%.RTN|utf-8|nb") else set "/O=%/LOCK%.RTN"
|
|
)
|
|
9>&2 2>nul (
|
|
8>"%/LOCK%" (
|
|
2>&9 (
|
|
if defined /XFILE (
|
|
setlocal enableDelayedExpansion
|
|
if defined /S call :writeVar S
|
|
if defined /V (
|
|
if defined /FindReplVar (
|
|
call :writeVar FIND
|
|
call :writeVar REPL
|
|
)
|
|
if defined /JBEG call :writeVar JBEG
|
|
if defined /JBEGLN call :writeVar JBEGLN
|
|
if defined /JEND call :writeVar JEND
|
|
if defined /JENDLN call :writeVar JENDLN
|
|
if defined /INC call :writeVar INC
|
|
if defined /EXC call :writeVar EXC
|
|
if defined /P call :writeVar P
|
|
) else (
|
|
if defined /FindReplVar (
|
|
(echo(!/FIND:^"=!) >"!/LOCK!.FIND"
|
|
(echo(!/REPL:^"=!) >"!/LOCK!.REPL"
|
|
)
|
|
if defined /JBEG (echo(!/JBEG!) >"!/LOCK!.JBEG"
|
|
if defined /JBEGLN (echo(!/JBEGLN!) >"!/LOCK!.JBEGLN"
|
|
if defined /JEND (echo(!/JEND!) >"!/LOCK!.JEND"
|
|
if defined /JENDLN (echo(!/JENDLN!) >"!/LOCK!.JENDLN"
|
|
if defined /INC (echo(!/INC!) >"!/LOCK!.INC"
|
|
if defined /EXC (echo(!/EXC!) >"!/LOCK!.EXC"
|
|
if defined /P (echo(!/P!) >"!/LOCK!.P"
|
|
)
|
|
endlocal
|
|
)
|
|
call :execute
|
|
)
|
|
)
|
|
if errorlevel 3 (del "%/LOCK%*"&exit /b 3)
|
|
if errorlevel 1 (del "%/LOCK%*"&(call)) else del "%/LOCK%*"
|
|
if "%/RTN%" equ "" exit /b
|
|
) || goto :lock
|
|
|
|
:writeVar
|
|
for /f delims^=^ eol^= %%A in ("!/%1!") do (echo(!%%A!) >"!/LOCK!.%1"
|
|
exit /b
|
|
|
|
:noLock
|
|
call :execute
|
|
exit /b %errorlevel%
|
|
|
|
:execute
|
|
cscript.exe //E:JScript //nologo %/UTF% "%/SCRIPT%" %/FIND% %/REPL%
|
|
if not defined /RTN exit /b %errorlevel%
|
|
|
|
::returnVar
|
|
if errorlevel 3 exit /b %errorlevel%
|
|
if defined /CHCP chcp 65001 >nul 2>nul
|
|
set "/ERR=%errorlevel%"
|
|
set "/NORMAL="
|
|
for /f "usebackq delims=" %%A in ("%/LOCK%.RTN") do (
|
|
if not defined /NORMAL (
|
|
set "/NORMAL=%%A"
|
|
) else set "/DELAYED=%%A"
|
|
)
|
|
chcp %/CHCP% >nul 2>nul
|
|
for /f %%2 in (
|
|
'copy /z "%/SCRIPT%" nul' %= This generates CR =%
|
|
) do for %%1 in (^"^
|
|
%= This generates quoted LF =%
|
|
^") do for /f "tokens=1,2" %%3 in (^"%% "") do (
|
|
(goto) 2>nul
|
|
(goto) 2>nul
|
|
if "^!^" equ "^!" (
|
|
set "%/RTN%=%/DELAYED:~1%"!
|
|
) else (
|
|
set "%/RTN%=%/NORMAL:~1%"
|
|
)
|
|
if %/ERR% equ 0 (call ) else (call)
|
|
)
|
|
|
|
:GetScript
|
|
set "%1=%~f0"
|
|
exit /b
|
|
|
|
:help
|
|
setlocal
|
|
set "help=%~1"
|
|
setlocal enableDelayedExpansion
|
|
if "!help:~0,2!" neq "/?" exit /b 1
|
|
set "noMore=1"
|
|
set "help=!help:~2!"
|
|
if defined help if "!help:~0,1!" equ "?" (
|
|
set "noMore="
|
|
set "help=!help:~1!"
|
|
)
|
|
for /f "delims=" %%A in ("/!help!") do if /i "%%~pA" equ "\CharSet\" ( %= /?CHARSET/ =%
|
|
echo(
|
|
if defined noMore (
|
|
for /f "delims=" %%F in ('reg query HKCR\MIME\Database\Charset /k /f "%%~nxA"') do echo %%~nF
|
|
) else (
|
|
(cmd /c "for /f "delims=" %%F in ('reg query HKCR\MIME\Database\Charset /k /f "%%~nxA"') do @echo %%~nF") | more /e
|
|
)
|
|
exit /b 0
|
|
)
|
|
if defined help if "!help:~0,2!" equ "/?" set "help=help"
|
|
for /f "delims=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/ eol=a" %%A in ("!help!") do (
|
|
echo(
|
|
echo Invalid /? option
|
|
exit /b 0
|
|
)
|
|
if /i "!help!" equ "regex" (
|
|
explorer "https://msdn.microsoft.com/en-us/library/ae5bf541.aspx"
|
|
exit /b 0
|
|
) else if /i "!help!" equ "replace" (
|
|
explorer "https://msdn.microsoft.com/en-US/library/efy6s3e6.aspx"
|
|
exit /b 0
|
|
) else if /i "!help!" equ "update" (
|
|
explorer "http://www.dostips.com/forum/viewtopic.php?f=3&t=6044"
|
|
exit /b 0
|
|
) else if /i "!help!" equ "charset" (
|
|
explorer "https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756.aspx"
|
|
exit /b 0
|
|
) else if /i "!help!" equ "xregexp" (
|
|
explorer "http:xregexp.com"
|
|
exit /b 0
|
|
) else if "!help!" equ "" ( %= /? =%
|
|
set "find=^:::(.*)"
|
|
set "repl=$1"
|
|
set ^"cmd="%~f0" find repl /v /a /f "%~f0"^"
|
|
) else if "!help:~0,1!" equ "/" ( %= /?/Option =%
|
|
set "find=^:::(.*)"
|
|
set "repl=$txt=$1"
|
|
set "help=!help:/=\/!"
|
|
set "inc=/^^::: {6}!help!(?= |$)/i/:/^^::: {6}\/(?^!!help:~2!(?= |$))|^^::\//i-1"
|
|
set "help=!help:\/=/!"
|
|
set ^"cmd=echo(^&call "%~f0" find repl /v /jmatchq /inc inc /f "%~f0"^|^|echo Help not found for option %help%^"
|
|
) else ( %= /?Topic =%
|
|
set "find=^:::?(.*)"
|
|
set "repl=$txt=$1"
|
|
set "inc=/^^::\/!help:/=\/!$/i/+1:/^^::\//-1"
|
|
set ^"cmd="%~f0" find repl /v /jmatchq /inc inc /f "%~f0"^|^|(echo(^&echo Help not found for topic %help%^)^"
|
|
)
|
|
if defined noMore (
|
|
setlocal
|
|
set "pathext=."
|
|
call %cmd%
|
|
) else (%cmd%) | more /e
|
|
exit /b 0
|
|
|
|
:exitErr
|
|
>&2 (
|
|
echo ERROR: %~1.
|
|
echo Use JREPL /? or JREPL /?? to get help.
|
|
(goto) 2>nul
|
|
exit /b 2
|
|
)
|
|
|
|
|
|
************* JScript portion **********/
|
|
var _g=new Object();
|
|
_g.loc='';
|
|
_g.objSh=WScript.CreateObject("WScript.Shell");
|
|
try {
|
|
var env=_g.objSh.Environment("Process"),
|
|
cnt,
|
|
counter=0,
|
|
ln=0,
|
|
skip=false,
|
|
quit=false,
|
|
fso,
|
|
stdin=WScript.StdIn,
|
|
stdout=WScript.Stdout,
|
|
stderr=WScript.Stderr,
|
|
output,
|
|
input;
|
|
if (env('/VT')!='') _g.objExec=_g.objSh.Exec("powershell.exe -nop -ep Bypass -c \"exit\"");
|
|
_g.ForReading=1;
|
|
_g.ForWriting=2;
|
|
_g.ForAppending=8;
|
|
_g.FileFormat = env('/UTF') ? -1 : 0;
|
|
_g.TemporaryFolder=2;
|
|
fso = new ActiveXObject("Scripting.FileSystemObject");
|
|
_g.inFile=env('/F');
|
|
_g.inFileA=_g.inFile.split('|');
|
|
_g.outFile=env('/O');
|
|
_g.outFileA=_g.outFile.split('|');
|
|
if (_g.outFileA[0]=='-') {
|
|
if (_g.outFileA[1]===undefined) {_g.outFileA[1]=_g.inFileA[1]; _g.outFileA[2]=_g.inFileA[2];}
|
|
_g.outFile = _g.inFileA[0]+'.new'+(_g.outFileA[1]?'|'+_g.outFileA[1]:'')+(_g.outFileA[2]?'|'+_g.outFileA[2]:'');
|
|
if (env('/APP')) fso.CopyFile( _g.inFileA[0], _g.inFileA[0]+'.new', true );
|
|
}
|
|
_g.tempFile='';
|
|
_g.delim=env('/D');
|
|
_g.loc=" defining EOL"
|
|
eol=eval('"'+env('/EOL')+'"');
|
|
_g.loc="";
|
|
|
|
_g.ADOStream = function( name, mode, format, noBom) {
|
|
var that = this;
|
|
var bomSize = 0;
|
|
try {
|
|
var stream = WScript.CreateObject("ADODB.Stream");
|
|
} catch(ex) {
|
|
throw new Error(215,'ADO unavailable');
|
|
}
|
|
try {
|
|
stream.CharSet = format;
|
|
} catch(ex) {
|
|
throw new Error(215,'ADO character set "'+format+'" is invalid or unavailable');
|
|
}
|
|
stream.LineSeparator = (mode==_g.ForReading) ? 10 : -1;
|
|
stream.Open();
|
|
if (mode !== _g.ForReading && noBom) {
|
|
stream.WriteText("");
|
|
stream.Position = bomSize = stream.Size;
|
|
}
|
|
switch (mode) {
|
|
case _g.ForReading:
|
|
stream.LoadFromFile(name);
|
|
break;
|
|
case _g.ForAppending:
|
|
stream.LoadFromFile(name);
|
|
stream.Position = stream.Size;
|
|
case _g.ForWriting:
|
|
break;
|
|
default:
|
|
throw new Error(215, 'Invalid file mode');
|
|
}
|
|
this.AtEndOfStream = stream.EOS;
|
|
|
|
this.ReadLine = function() {
|
|
if (mode!=_g.ForReading) throw new Error(215, 'Bad file mode');
|
|
var str = stream.ReadText(-2);
|
|
that.AtEndOfStream = stream.EOS;
|
|
return str.slice(-1)=='\r' ? str.slice(0,-1) : str;
|
|
}
|
|
|
|
this.Read = function(size) {
|
|
if (mode!=_g.ForReading) throw new Error(215, 'Bad file mode');
|
|
var str = stream.ReadText(size)
|
|
that.AtEndOfStream = stream.EOS;
|
|
return str;
|
|
}
|
|
|
|
this.SkipLine = function() {
|
|
if (mode!=_g.ForReading) throw new Error(215, 'Bad file mode');
|
|
stream.SkipLine();
|
|
that.AtEndOfStream = stream.EOS;
|
|
}
|
|
|
|
this.Write = function(str) {
|
|
if (mode==_g.ForReading) throw new Error(215, 'Bad file mode');
|
|
stream.WriteText(str);
|
|
}
|
|
|
|
this.WriteLine = function(str) {
|
|
if (mode==_g.ForReading) throw new Error(215, 'Bad file mode');
|
|
stream.WriteText(str,1);
|
|
}
|
|
|
|
this.Close = function() {
|
|
if (mode!==_g.ForReading){
|
|
if (bomSize) {
|
|
var noBomStream = WScript.CreateObject("ADODB.Stream");
|
|
noBomStream.Type = 1;
|
|
noBomStream.Mode = 3;
|
|
noBomStream.Open();
|
|
stream.Position = bomSize;
|
|
stream.CopyTo(noBomStream);
|
|
noBomStream.SaveToFile( name, 2 );
|
|
noBomStream.Flush();
|
|
noBomStream.Close();
|
|
noBomStream = null;
|
|
} else stream.SaveToFile( name, 2 );
|
|
}
|
|
stream.Close();
|
|
stream=null;
|
|
}
|
|
}
|
|
|
|
_g.openInput = function( fileName ) {
|
|
var file;
|
|
if (fileName) {
|
|
file = fileName.split('|');
|
|
if (file[1]) {
|
|
file = new _g.ADOStream( file[0], _g.ForReading, file[1], file[2] );
|
|
return file;
|
|
}
|
|
else return fso.OpenTextFile( fileName, _g.ForReading, false, _g.FileFormat );
|
|
}
|
|
else return stdin;
|
|
}
|
|
|
|
_g.charMap = new Object();
|
|
_g.readVar = function( val, ref, ext ) {
|
|
var input, buf=1024;
|
|
if (!env('/XFILE') || !val) return (ref && val) ? env(val) : val;
|
|
_g.loc=' reading '+env('/LOCK')+ext;
|
|
input=fso.OpenTextFile( env('/LOCK')+ext, _g.ForReading );
|
|
val='';
|
|
while (!input.AtEndOfStream) {
|
|
val+=input.Read(buf);
|
|
buf*=2;
|
|
}
|
|
input.Close();
|
|
_g.loc=''
|
|
return val.slice(0,-2);
|
|
}
|
|
|
|
_g.xbytes = env('/XBYTES');
|
|
if (_g.xbytes && !(fso.FileExists(_g.xbytes))) try {
|
|
// Unable to create file with CERTUTIL, so now try with ADO
|
|
var Stream=WScript.CreateObject('ADODB.Stream'),
|
|
Node=WScript.CreateObject('Microsoft.XMLDOM').createElement('e');
|
|
Node.dataType='bin.base64';
|
|
Node.text='AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v'
|
|
+ 'MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f'
|
|
+ 'YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P'
|
|
+ 'kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/'
|
|
+ 'wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v'
|
|
+ '8PHy8/T19vf4+fr7/P3+/w==';
|
|
Stream.Type=1;
|
|
Stream.Open();
|
|
Stream.Write(Node.nodeTypedValue);
|
|
Stream.SaveToFile(_g.xbytes);
|
|
} catch(e) {
|
|
_g.xbytes = '';
|
|
}
|
|
var decode = _g.xbytes ?
|
|
// Default dynamic character set decode() for v7.4 and beyond
|
|
function(str, charSet, searchSwitch) {
|
|
function u(codeUnit) {return '\\u'+lpad(codeUnit.toString(16),4,'0');}
|
|
function xToUTF16(byte,charSet) {
|
|
if (typeof _g.charMap[charSet]==='undefined') {
|
|
if (charSet=='default' && _g.utf) {
|
|
_g.charMap[charSet]=false
|
|
} else {
|
|
var stream = _g.openInput( _g.xbytes+(charSet=='default'?'':'|'+charSet) );
|
|
try {
|
|
_g.charMap[charSet] = stream.Read(256);
|
|
stream.Close();
|
|
if (_g.charMap[charSet].length!=256) _g.charMap[charSet]=false;
|
|
} catch(e) {
|
|
_g.charMap[charSet]=false;
|
|
}
|
|
}
|
|
}
|
|
return u( _g.charMap[charSet] ? _g.charMap[charSet].charCodeAt(byte) : byte );
|
|
}
|
|
function xRange(min,max,charSet) {
|
|
var str='', i;
|
|
for (i=min; i<=max; i++ ) str+=xToUTF16(i,charSet);
|
|
return str;
|
|
}
|
|
function uToUTF16(codePoint) {
|
|
if (codePoint <= 0xFFFF) return u(codePoint);
|
|
codePoint -= 0x10000;
|
|
return u(0xD800|(codePoint>>10)) + u(0xDC00|(codePoint&1023));
|
|
}
|
|
if (charSet===undefined) charSet='default';
|
|
if (charSet=='input') charSet = _g.inFileA[1] ? _g.inFileA[1] : 'default';
|
|
if (charSet=='output') charSet = _g.outFileA[1] ? _g.outFileA[1] : 'default';
|
|
return str.replace(
|
|
/\\(?:\\|b|c|f|n|q|r|t|v|x([0-9a-fA-F]{2})|x\{([0-9a-fA-F]{2}),([^}]+)}|u[0-9a-fA-F]{4}|u\{([0-9a-fA-F]+)\}|x\{([0-9a-fA-F]{2})-([0-9a-fA-F]{2})(?:,([^}]+))?})/g,
|
|
function($0,$1,$2,$3,$4,$5,$6,$7) {
|
|
if ($0=='\\q') return '"';
|
|
if ($0=='\\c') return '^';
|
|
if ($1) $0=xToUTF16(parseInt($1,16),charSet);
|
|
if ($2) $0=xToUTF16(parseInt($2,16),$3);
|
|
if ($4) $0=uToUTF16(parseInt($4,16));
|
|
if ($5) $0=xRange(parseInt($5,16),parseInt($6,16),($7?$7:charSet));
|
|
return searchSwitch===false ? $0 : eval('"'+$0+'"');
|
|
}
|
|
);
|
|
}
|
|
: // Pre-v7.4 decode() that assumes Windows-1252, only used if XBYTES.DAT not available or disabled.
|
|
function(str, ignore, searchSwitch) {
|
|
function toUTF16(codePoint) {
|
|
function u(codeUnit) {return '\\u'+lpad(codeUnit.toString(16),4,'0');}
|
|
if (codePoint <= 0xFFFF) return u(codePoint);
|
|
codePoint -= 0x10000;
|
|
return u(0xD800|(codePoint>>10)) + u(0xDC00|(codePoint&1023));
|
|
}
|
|
str=str.replace(
|
|
/\\(\\|b|c|f|n|q|r|t|v|x80|x82|x83|x84|x85|x86|x87|x88|x89|x8[aA]|x8[bB]|x8[cC]|x8[eE]|x91|x92|x93|x94|x95|x96|x97|x98|x99|x9[aA]|x9[bB]|x9[cC]|x9[dD]|x9[eE]|x9[fF]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|u\{([0-9a-fA-F]+)\}|x\{([0-9a-fA-F]{2}),[^}]+\})/g,
|
|
function($0,$1,$2,$3) {
|
|
if ($3) {
|
|
$1='x'+$3;
|
|
$0='\\'+$1;
|
|
}
|
|
switch ($1.toLowerCase()) {
|
|
case 'q': return '"';
|
|
case 'c': return '^';
|
|
case 'x80': return '\u20AC';
|
|
case 'x82': return '\u201A';
|
|
case 'x83': return '\u0192';
|
|
case 'x84': return '\u201E';
|
|
case 'x85': return '\u2026';
|
|
case 'x86': return '\u2020';
|
|
case 'x87': return '\u2021';
|
|
case 'x88': return '\u02C6';
|
|
case 'x89': return '\u2030';
|
|
case 'x8a': return '\u0160';
|
|
case 'x8b': return '\u2039';
|
|
case 'x8c': return '\u0152';
|
|
case 'x8e': return '\u017D';
|
|
case 'x91': return '\u2018';
|
|
case 'x92': return '\u2019';
|
|
case 'x93': return '\u201C';
|
|
case 'x94': return '\u201D';
|
|
case 'x95': return '\u2022';
|
|
case 'x96': return '\u2013';
|
|
case 'x97': return '\u2014';
|
|
case 'x98': return '\u02DC';
|
|
case 'x99': return '\u2122';
|
|
case 'x9a': return '\u0161';
|
|
case 'x9b': return '\u203A';
|
|
case 'x9c': return '\u0153';
|
|
case 'x9d': return '\u009D';
|
|
case 'x9e': return '\u017E';
|
|
case 'x9f': return '\u0178';
|
|
default: if ($2) $0=toUTF16(parseInt($2,16));
|
|
return searchSwitch===false ? $0 : eval('"'+$0+'"');
|
|
}
|
|
}
|
|
);
|
|
return str;
|
|
}
|
|
;
|
|
|
|
_g.getCount = function() {
|
|
if (cnt>=0) return;
|
|
cnt=0;
|
|
if (_g.inFile=='') {
|
|
_g.tempFile=fso.GetSpecialFolder(_g.TemporaryFolder).path+'\\'+fso.GetTempName();
|
|
_g.inFile=_g.tempFile;
|
|
var output=fso.OpenTextFile(_g.tempFile,_g.ForWriting,true,_g.FileFormat);
|
|
while (!input.AtEndOfStream) {
|
|
output.WriteLine(input.ReadLine());
|
|
cnt++
|
|
}
|
|
output.Close();
|
|
} else {
|
|
while (!input.AtEndOfStream) {
|
|
input.SkipLine();
|
|
cnt++;
|
|
}
|
|
input.Close();
|
|
}
|
|
input = _g.openInput(_g.inFile);
|
|
}
|
|
|
|
_g.loc=' opening input file';
|
|
input = _g.openInput(_g.inFile);
|
|
_g.loc='';
|
|
|
|
if (env('/C')) _g.getCount();
|
|
|
|
openOutput( _g.outFile, env('/APP'), _g.FileFormat );
|
|
|
|
if (env('/XREG')) {
|
|
_g.loc=' while loading /XREG library';
|
|
_g.libs=env('/XREG').split('/');
|
|
for (_g.i=0; _g.i<_g.libs.length; _g.i++) {
|
|
_g.lib=fso.OpenTextFile(_g.libs[_g.i],_g.ForReading);
|
|
if (!_g.lib.AtEndOfStream) eval(_g.lib.ReadAll());
|
|
_g.lib.Close();
|
|
}
|
|
_g.loc=' while initializing /XREG library';
|
|
_g.newRegExp = function(pattern,flags){ return new XRegExp(pattern,flags); }
|
|
XRegExp.install('natives');
|
|
_g.loc='';
|
|
_g.XRegExp = true;
|
|
} else {
|
|
_g.newRegExp = function(pattern,flags){ return new RegExp(pattern,flags); }
|
|
_g.XRegExp = false;
|
|
}
|
|
|
|
if (env('/JLIB')) {
|
|
_g.loc=' while loading /JLIB code';
|
|
_g.libs=env('/JLIB').split('/');
|
|
for (_g.i=0; _g.i<_g.libs.length; _g.i++) {
|
|
_g.lib=fso.OpenTextFile(_g.libs[_g.i],_g.ForReading);
|
|
if (!_g.lib.AtEndOfStream) eval(_g.lib.ReadAll());
|
|
_g.lib.Close();
|
|
}
|
|
_g.loc='';
|
|
}
|
|
|
|
_g.loc=' in /JBEG code';
|
|
eval( _g.readVar( env('/JBEG'), env('/V'), '.JBEG' ) );
|
|
_g.loc='';
|
|
|
|
_g.defineObjectInternal=function(){
|
|
_g.loc=' while defining '+_g.defineObjectObj;
|
|
eval(_g.defineObjectStr);
|
|
_g.loc='';
|
|
}
|
|
_g.defineObject=function(str,obj) {
|
|
_g.defineObjectStr=str;
|
|
_g.defineObjectObj=obj;
|
|
_g.defineObjectInternal();
|
|
}
|
|
|
|
_g.main=function() {
|
|
_g.rtn=1;
|
|
var args=WScript.Arguments;
|
|
var search = env('/FindReplVar') ? _g.readVar( args.Item(0), env('/V')||env('/UTF'), '.FIND' ) : args.Item(0);
|
|
var replace = env('/FindReplVar') ? _g.readVar( args.Item(1), env('/V')||env('/UTF'), '.REPL' ) : args.Item(1);
|
|
var hiLite=env('/H')!='';
|
|
var hiLiteOn=eval('"'+env('/HON')+'"');
|
|
var hiLiteOff=eval('"'+env('/HOFF')+'"');
|
|
var multi=env('/M')!='';
|
|
var literal=env('/L')!='';
|
|
var alterations=env('/A')!='';
|
|
var srcVar=env('/S');
|
|
var jexpr=env('/J')!='';
|
|
var jmatch=env('/JMATCH')!='';
|
|
var jmatchq=env('/JMATCHQ')!='';
|
|
var jquick=env('/JQ')!='';
|
|
var translate=env('/T');
|
|
var filter = _g.readVar( env('/P'), env('/V'), '.P' );
|
|
var keep, reject, context, krfile=false, krcount=false;
|
|
var rtnVar=env('/RTN');
|
|
if (reject=env('/R')) {
|
|
if (!/^(\d+(:\d+)?|COUNT)(:FILE)?$/i.test(reject)) throw new Error(209, 'Invalid /R Context');
|
|
context = reject.toUpperCase().split(':')
|
|
krfile=(context[context.length-1]=='FILE');
|
|
if (context[0]=='COUNT') {
|
|
context[0]=context[1]=0;
|
|
krcount=true;
|
|
} else {
|
|
context[0]=Number(context[0]);
|
|
context[1]=(context.length==1 || context[1]=='FILE')?context[0]:Number(context[1]);
|
|
}
|
|
}
|
|
if (keep=env('/K')) {
|
|
//if (!/^\d+(:\d+)?(:FILE)?$/i.test(keep)) throw new Error(208, 'Invalid /K Context');
|
|
if (!/^(\d+(:\d+)?|COUNT)(:FILE)?$/i.test(keep)) throw new Error(208, 'Invalid /K Context');
|
|
context = keep.toUpperCase().split(':')
|
|
krfile=(context[context.length-1]=='FILE');
|
|
if (context[0]=='COUNT'){
|
|
context[0]=context[1]=0;
|
|
krcount=true;
|
|
} else {
|
|
context[0]=Number(context[0]);
|
|
context[1]=(context.length==1 || context[1]=='FILE')?context[0]:Number(context[1]);
|
|
}
|
|
}
|
|
var options = (keep||reject)?"":"g";
|
|
_g.begLn = _g.readVar( env('/JBEGLN'), env('/V'), '.JBEGLN' );
|
|
_g.endLn = _g.readVar( env('/JENDLN'), env('/V'), '.JENDLN' );
|
|
|
|
_g.incBlock = new Array();
|
|
_g.excBlock = new Array();
|
|
_g.incBlock.dynamic = false;
|
|
_g.excBlock.dynamic = false;
|
|
var blockMatch,
|
|
blockSearch = /(?:(-?\d+)|(?:\/((?:\\\/|[^/])+)\/|'((?:''|[^'])+)')([ibe]*)(\/)?)([+-]\d+)?(:(?:(-?\d+)|(\+\d+)|(?:\/((?:\\\/|[^/])+)\/|'((?:''|[^'])+)')([ibe]*))([+-]\d+)?)?(?:,(?=.)|$)?|(.+)/g;
|
|
/* 1 2 3 4 5 6 7 8 9 1 1 1 1 1
|
|
0 1 2 3 4
|
|
line or range begin
|
|
spec
|
|
1 = line number
|
|
2 = regex
|
|
4 = i|b|e flags
|
|
5 = singleton
|
|
3 = string
|
|
4 = i|b|e flags
|
|
5 = singleton
|
|
6 = offset
|
|
7 = range end
|
|
spec
|
|
8 = line number
|
|
9 = offset from range begin
|
|
10 = regex
|
|
12 = i|b|e flags
|
|
11 = string
|
|
12 = i|b|e flags
|
|
13 = offset
|
|
14 = error
|
|
*/
|
|
_g.Block = function(match) {
|
|
if (match[14]) throw new Error(210, 'Invalid block syntax');
|
|
this.offset=match[6]?Number(match[6]):0;
|
|
if (match[1]) {
|
|
this.type='lineNum';
|
|
if ((this.spec=Number(match[1])) < 0) _g.getCount();
|
|
this.lineNum=this.spec+this.offset+(this.spec<0?cnt+1:0);
|
|
} else {
|
|
this.type='regex';
|
|
this.spec=_g.newRegExp( (match[4].search('b')+1?'^':'') + (
|
|
match[2] ? decode(match[2],'input',false) :
|
|
decode(match[3].replace(/''/g,"'"),'input',true).replace(/([.^$*+?()[{\\|])/g,"\\$1")
|
|
) + (match[4].search('e')+1?'$':''),
|
|
match[4].search('i')+1?'i':''
|
|
);
|
|
this.spec.singleton=match[5]?true:false;
|
|
this.lineNum=void 0;
|
|
if (this.offset<0) throw new Error(211, 'Regex/String offset cannot be negative');
|
|
}
|
|
if (match[7]) {
|
|
this.endOffset=Number(match[13]);
|
|
if (match[8]) {
|
|
this.endType='lineNum';
|
|
if ((this.endSpec=Number(match[8])) < 0) _g.getCount();
|
|
this.endLineNum=this.endSpec+this.endOffset+(this.endSpec<0?cnt+1:0);
|
|
} else if (match[9]) {
|
|
this.endType='offset';
|
|
this.endSpec=Number(match[9]);
|
|
this.endLineNum=this.lineNum+this.endSpec+this.endOffset;
|
|
} else {
|
|
this.endType='regex';
|
|
this.endSpec=_g.newRegExp( (match[12].search('b')+1?'^':'') + (
|
|
match[10] ? decode(match[10],'input',false) :
|
|
decode(match[11].replace(/''/g,"'"),'input',true).replace(/([.^$*+?()[{\\|])/g,"\\$1")
|
|
) + (match[12].search('e')+1?'$':''),
|
|
match[12].search('i')+1?'i':''
|
|
);
|
|
this.endLineNum=void 0;
|
|
if (this.endOffset<-1) throw new Error(212, 'End-range Regex/String offset cannot be less than -1');
|
|
}
|
|
} else {
|
|
this.endType=void 0;
|
|
this.endSpec=void 0;
|
|
this.endLineNum=this.lineNum;
|
|
}
|
|
}
|
|
_g.setBlocks = function(blocks,str) {
|
|
if (blocks.dynamic==true) {
|
|
for (var i=0; i<blocks.length; i++) {
|
|
var block = blocks[i];
|
|
if (ln>block.endLineNum && block.type=='regex' && !block.spec.singleton)
|
|
block.lineNum=block.endLineNum=void 0;
|
|
if (!block.lineNum && block.spec.test(str)) {
|
|
block.lineNum = ln+block.offset;
|
|
if (!block.endLineNum) {
|
|
if (!block.endType)
|
|
block.endLineNum=block.lineNum;
|
|
else if (block.endType=='offset')
|
|
block.endLineNum=block.lineNum+block.endSpec+block.endOffset;
|
|
}
|
|
}
|
|
if (!block.endLineNum && ln>block.lineNum && block.endSpec.test(str))
|
|
block.endLineNum = ln+block.endOffset;
|
|
}
|
|
}
|
|
}
|
|
var str = _g.readVar( env('/INC'), env('/V'), '.INC' );
|
|
while ( (blockMatch=blockSearch.exec(str)) !== null ) {
|
|
_g.loc=' while parsing /INC block['+_g.incBlock.length+']';
|
|
var block = new _g.Block(blockMatch);
|
|
_g.incBlock.dynamic=(_g.incBlock.dynamic || block.type=='regex' || block.endType=='regex');
|
|
_g.incBlock.push(block);
|
|
}
|
|
str = _g.readVar( env('/EXC'), env('/V'), '.EXC' );
|
|
while ( (blockMatch=blockSearch.exec(str)) !== null ) {
|
|
_g.loc=' while parsing /EXC block['+_g.excBlock.length+']';
|
|
var block = new _g.Block(blockMatch);
|
|
_g.excBlock.dynamic=(_g.excBlock.dynamic || block.type=='regex' || block.endType=='regex');
|
|
_g.excBlock.push(new _g.Block(blockMatch));
|
|
}
|
|
_g.loc='';
|
|
|
|
if (multi) options+='m';
|
|
if (env('/MATCH')) {
|
|
if (replace.toUpperCase()=='COUNT') {
|
|
replace='$txt=false;counter++;';
|
|
krcount=true;
|
|
} else replace='$txt=$0';
|
|
}
|
|
_g.krcount=krcount;
|
|
if (_g.begLn) _g.defineObject("_g.begLn=function($txt){_g.loc=' in /JBEGLN code';"+_g.begLn+";_g.loc='';return $txt;}",'/JBEGLN code');
|
|
if (_g.endLn) _g.defineObject("_g.endLn=function($txt){_g.loc=' in /JENDLN code';"+_g.endLn+";_g.loc='';return $txt;}",'/JENDLN code');
|
|
if (env('/I')) options+='i';
|
|
|
|
var lnWidth=parseInt(env('/N'),10),
|
|
offWidth=parseInt(env('/OFF'),10);
|
|
if (lnWidth<0) lnWidth = 0;
|
|
if (offWidth<0) offWidth = 0;
|
|
_g.lnPrefix=lnWidth>0;
|
|
_g.offPrefix=offWidth>0;
|
|
var lnPad=lnWidth>0?'"'+(Array(lnWidth+1).join('0'))+'"':'',
|
|
offPad=offWidth>0?'"'+(Array(offWidth+1).join('0'))+'"':'',
|
|
xcnt=0, test,
|
|
filterMatchOffset = offWidth>0&&filter!='' ? '+_g.filterMatchOffset' : '';
|
|
|
|
function writeMatch(str,ln,lnPad,off,offPad) {
|
|
return 'if('+str+'!==false){_g.rtn=0;output.Write('
|
|
+ (lnWidth==0 ? '' : 'lpad('+ln+','+lnPad+')+_g.delim+')
|
|
+ (offWidth==0 ? '' : 'lpad('+off+','+offPad+')+_g.delim+')
|
|
+ str+'+eol);}';
|
|
}
|
|
|
|
if (env('/VT')!='') while (_g.objExec.Status == 0) WScript.Sleep(50);
|
|
|
|
if (translate=='none') { // Normal
|
|
if (hiLite && !krcount && (keep||reject)) options+='g';
|
|
if (krfile) { // Load KEEP or REJECT File
|
|
_g.loc=' loading '+(keep?'/K':'/R')+' Search file';
|
|
var f = _g.openInput(search);
|
|
search='';
|
|
while (!f.AtEndOfStream) {
|
|
str=f.ReadLine();
|
|
if (env('/XSEQ')) str=decode(str,'input',literal);
|
|
if (literal) str=str.replace(/([.^$*+?()[{\\|])/g,"\\$1");
|
|
if (env('/B')) str="^"+str;
|
|
if (env('/E')) str=str+"$";
|
|
search+=(search?'|':'')+str;
|
|
}
|
|
f.Close();
|
|
} else { // Load Normal Search
|
|
if (env('/XSEQ')) {
|
|
if (!jexpr) replace=decode(replace,'output');
|
|
search=decode(search,'input',literal);
|
|
}
|
|
if (literal) {
|
|
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
|
|
if (!jexpr) replace=replace.replace(/\$/g,"$$$$");
|
|
}
|
|
if (env('/B')) search="^"+search;
|
|
if (env('/E')) search=search+"$";
|
|
_g.loc=' in Search regular expression';
|
|
}
|
|
search=_g.newRegExp(search,options);
|
|
_g.loc='';
|
|
if (keep||reject){
|
|
jquick=jexpr=(krcount || hiLite || filter!='');
|
|
replace = krcount ? '$txt=false;counter++;' : jquick ? '$txt=$0;if(_g.matchOffset==null)_g.matchOffset=$off'+filterMatchOffset+';' : '$&';
|
|
}
|
|
if (jexpr) {
|
|
_g.loc=' in Search regular expression';
|
|
test=_g.newRegExp('.|'+search,options);
|
|
_g.loc='';
|
|
'x'.replace(test,function(){xcnt=arguments.length-2; return '';});
|
|
_g.replFunc='_g.replFunc=function($0';
|
|
for (var i=1; i<xcnt; i++) _g.replFunc+=',$'+i;
|
|
_g.replFunc+=',$off,$src){_g.loc=" in Replace code";';
|
|
if (jquick||jmatchq) {
|
|
_g.replFunc+='var $txt;'+replace+';';
|
|
if (hiLite) _g.replFunc+='$txt="'+hiLiteOn+'"+$txt+"'+hiLiteOff+'";';
|
|
_g.replFunc+=
|
|
jmatch ? writeMatch('$txt','ln',lnPad,'$off'+filterMatchOffset,offPad)+'_g.loc="";return $0;}'
|
|
: '_g.loc="";return $txt;}';
|
|
} else {
|
|
var jstr = 'eval(_g.replace)';
|
|
if (hiLite) jstr = '"'+hiLiteOn+'"+'+jstr+'+"'+hiLiteOff+'"';
|
|
_g.replFunc+=
|
|
jmatch ? writeMatch(jstr,'ln',lnPad,'$off'+filterMatchOffset,offPad)+'_g.loc="";return $0;}'
|
|
: '_g.rtn2='+jstr+';_g.loc="";return _g.rtn2;}';
|
|
}
|
|
_g.defineObject(_g.replFunc,'/J or /JMATCH code');
|
|
_g.replace = replace;
|
|
} else {
|
|
_g.replace = hiLite ? hiLiteOn + replace + hiLiteOff : replace;
|
|
}
|
|
} else { // /T
|
|
if (translate.toLowerCase()=='file') {
|
|
var f
|
|
_g.loc=' loading /T Search file';
|
|
f = _g.openInput(search);
|
|
search=[];
|
|
while (!f.AtEndOfStream) search[search.length]=f.ReadLine();
|
|
f.Close();
|
|
_g.loc=' loading /T Replace file';
|
|
f = _g.openInput(replace);
|
|
replace=[];
|
|
while (!f.AtEndOfStream) replace[replace.length]=f.ReadLine();
|
|
f.Close();
|
|
_g.loc='';
|
|
} else {
|
|
if (translate.length>1) throw new Error(203, 'Invalid /T delimiter');
|
|
if (translate.length==0 && env('/XSEQ')) {
|
|
search=decode(search,'input',literal);
|
|
replace=decode(replace,'output');
|
|
}
|
|
search=search.split(translate);
|
|
var replace=replace.split(translate);
|
|
}
|
|
if (search.length>99 && !_g.XRegExp) throw new Error(202, '/T expression count exceeds 99');
|
|
if (search.length!=replace.length) throw new Error(201, 'Mismatched search and replace /T expressions');
|
|
var j=1;
|
|
if (!jexpr) jquick=1;
|
|
if (jquick) _g.replace='';
|
|
else _g.replace=[];
|
|
for (var i=0; i<search.length; i++) {
|
|
if (env('/XSEQ')) search[i]=decode(search[i],'input',literal);
|
|
if (literal) {
|
|
search[i]=search[i].replace(/([.^$*+?()[{\\|])/g,"\\$1");
|
|
} else {
|
|
_g.loc=' in Search regular expression';
|
|
test=_g.newRegExp('.|'+search[i],options+(_g.XRegExp?env('/TFLAG'):''));
|
|
_g.loc='';
|
|
'x'.replace(test,function(){xcnt=arguments.length-3;return '';});
|
|
}
|
|
if (j+xcnt>99 && !_g.XRegExp) throw new Error(202, '/T expressions + captured expressions exceeds 99');
|
|
if (env('/B')) search[i]="^"+search[i];
|
|
if (env('/E')) search[i]=search[i]+"$";
|
|
if (_g.XRegExp) search[i]="?<T"+i+">"+search[i];
|
|
if (jquick|jmatchq) {
|
|
if (!jexpr) {
|
|
replace[i]="'" + (env('/XSEQ')==''?replace[i]:decode(replace[i],'output')).replace(/[\\']/g,"\\$&") + "'";
|
|
replace[i]=replace[i].replace(/\n/g, "\\n");
|
|
replace[i]=replace[i].replace(/\r/g, "\\r");
|
|
if (!literal) {
|
|
if (_g.XRegExp) {
|
|
replace[i]='$txt='+replace[i].replace(
|
|
/\$([$&`0]|\\'|\{0\}|(\d)(\d)?|\{((\d)(\d)?)\}|\{([^}]+)\})/g,
|
|
function($0,$1,$2,$3,$4,$5,$6,$7){
|
|
return ($1=="$") ? "$":
|
|
($1=="&" || $1=="0" || $1=="{0}") ? "'+$0+'":
|
|
($1=="`") ? "'+$src.substr(0,$off)+'":
|
|
($1=="\\'") ? "'+$src.substr($off+$0.length)+'":
|
|
($7) ? "'+$0."+$7+"+'":
|
|
(Number($1)-j<=xcnt && Number($1)>=j) ? "'+"+$0+"+'":
|
|
(Number($2)-j<=xcnt && Number($2)>=j) ? "'+$"+$2+"+'"+$3:
|
|
(Number($4)-j<=xcnt && Number($4)>=j) ? "'+$"+$4+"+'":
|
|
(Number($5)-j<=xcnt && Number($5)>=j) ? "'+$"+$5+"+'"+$6:
|
|
$0;
|
|
}
|
|
);
|
|
} else {
|
|
replace[i]='$txt='+replace[i].replace(
|
|
/\$([$&`0]|\\'|(\d)(\d)?)/g,
|
|
function($0,$1,$2,$3){
|
|
return ($1=="$") ? "$":
|
|
($1=="&") ? "'+$0+'":
|
|
($1=="`") ? "'+$src.substr(0,$off)+'":
|
|
($1=="\\'") ? "'+$src.substr($off+$0.length)+'":
|
|
(Number($1)-j<=xcnt && Number($1)>=j) ? "'+"+$0+"+'":
|
|
(Number($2)-j<=xcnt && Number($2)>=j) ? "'+$"+$2+"+'"+$3:
|
|
$0;
|
|
}
|
|
);
|
|
}
|
|
} else replace[i]='$txt='+replace[i];
|
|
}
|
|
_g.replace+='if(arguments['+j+']!==undefined){'+replace[i]+';}';
|
|
} else {
|
|
_g.replace[j]=replace[i];
|
|
}
|
|
j+=xcnt+1;
|
|
}
|
|
search='('+search.join(')|(')+')';
|
|
_g.loc=' in Search regular expression';
|
|
search=_g.newRegExp( search, options+(_g.XRegExp?env('/TFLAG'):'') );
|
|
_g.loc='';
|
|
_g.replFunc='_g.replFunc=function($0';
|
|
for (var i=1; i<j; i++) _g.replFunc+=',$'+i;
|
|
_g.replFunc+=',$off,$src){_g.loc=" in Replace code";';
|
|
if (jquick||jmatchq) {
|
|
_g.replFunc+='var $txt;'+_g.replace;
|
|
if (hiLite) _g.replFunc+='$txt="'+hiLiteOn+'"+$txt+"'+hiLiteOff+'";';
|
|
_g.replFunc+=(
|
|
jmatch ? writeMatch('$txt','ln',lnPad,'$off'+filterMatchOffset,offPad)+'_g.loc="";return $0;}'
|
|
: '_g.loc="";return $txt;}' );
|
|
} else {
|
|
var jstr = 'eval(_g.replace[_g.i])';
|
|
if (hiLite) jstr = '"'+hiLiteOn+'"+'+jstr+'+"'+hiLiteOff+'"';
|
|
_g.replFunc+='for(_g.i=1;_g.i<arguments.length-2;_g.i++)if(arguments[_g.i]!==undefined)'+ (
|
|
jmatch ? writeMatch(jstr,'ln',lnPad,'$off'+filterMatchOffset,offPad)+'_g.loc="";return $0;}'
|
|
: '{_g.rtn2='+jstr+';_g.loc="";return _g.rtn2;}}' );
|
|
}
|
|
_g.defineObject(_g.replFunc,'/J or /JMATCH code');
|
|
jexpr=true;
|
|
}
|
|
|
|
var str1, str2;
|
|
var repl=jexpr?_g.replFunc:_g.replace;
|
|
|
|
if (filter!='') {
|
|
if (env('/PREPL')) {
|
|
_g.defineObject(
|
|
'_g.filterReplace=function(){ return '
|
|
+ env('/PREPL').replace(/\$(\d+)/g,'arguments[$1]')
|
|
.replace(/{([^}]*)}/g,'($1).replace(_g.search,_g.filterReplace2)')
|
|
+';}'
|
|
,'/PREPL'
|
|
);
|
|
} else if (offWidth>0) {
|
|
_g.filterReplace=function(str) {
|
|
_g.filterMatchOffset = arguments[arguments.length-2];
|
|
return str.replace(_g.search,_g.filterReplace2);
|
|
}
|
|
} else {
|
|
_g.filterReplace=function(str) {
|
|
return str.replace(_g.search,_g.filterReplace2);
|
|
}
|
|
}
|
|
_g.loc=' in /P FilterRegex';
|
|
filter = _g.newRegExp( decode(filter,'input',false), env('/PFLAG').toLowerCase()+(env('/M')?'m':'') );
|
|
_g.loc='';
|
|
_g.search=search;
|
|
search=filter;
|
|
_g.filterReplace2=repl;
|
|
repl=_g.filterReplace;
|
|
}
|
|
|
|
if (srcVar) {
|
|
str1=_g.readVar( srcVar, srcVar, '.S' );
|
|
str2=str1.replace(search,repl);
|
|
if (str1!=str2) _g.rtn=0;
|
|
if (!jmatch && (!alterations || str1!=str2)) output.Write(str2+(multi?'':eol));
|
|
} else if (multi){
|
|
var buf=1024;
|
|
str1="";
|
|
while (!input.AtEndOfStream) {
|
|
str1+=input.Read(buf);
|
|
buf*=2;
|
|
}
|
|
str2=str1.replace(search,repl);
|
|
if (!jmatch) output.Write(str2);
|
|
if (str1!=str2) _g.rtn=0;
|
|
} else if (keep||reject){
|
|
var match, arr, filterResult, post, pre=new Array();
|
|
var cmd='while(!input.AtEndOfStream&&!quit){match=reject;str1=input.ReadLine();';
|
|
if ( _g.incBlock.length || _g.excBlock.length || lnWidth
|
|
|| _g.begLn || _g.endLn || env(env('/V')?env('/JEND'):'/JEND')
|
|
) cmd+='ln++;';
|
|
if (_g.incBlock.dynamic) cmd+='_g.setBlocks(_g.incBlock,str1);';
|
|
if (_g.excBlock.dynamic) cmd+='_g.setBlocks(_g.excBlock,str1);';
|
|
if (_g.begLn) cmd+='str1=_g.begLn(str1);';
|
|
if (jquick) cmd+='_g.matchOffset=null;';
|
|
str1='';str2='if(';
|
|
if (_g.incBlock.length) {str1+=str2+'inc()';str2='&&';}
|
|
if (_g.excBlock.length) {str1+=str2+'!exc()';str2='&&';}
|
|
if (_g.begLn||_g.endLn||jexpr||env(env('/V')?env('/JBEG'):'/JBEG')) {str1+=str2+'!skip';}
|
|
if (str1) cmd+=str1+')';
|
|
if (jquick) {
|
|
cmd+='{str1=str1.replace(search,repl);match=_g.matchOffset!=null?!reject:reject;}';
|
|
} else {
|
|
cmd+='if ((arr=search.exec(str1))!==null){match=!reject;_g.matchOffset=arr.index}';
|
|
}
|
|
if (_g.endLn) cmd += 'str1=_g.endLn(str1);';
|
|
cmd+='if (str1!==false && match) {_g.rtn=0;';
|
|
if (context[0]) cmd+='while(pre.length){str2=pre.pop();'+writeMatch('str2','ln-pre.length-1',lnPad,'""',offWidth)+'}';
|
|
cmd+=writeMatch('str1','ln',lnPad,'_g.matchOffset',offPad);
|
|
if (context[1]) cmd+='post=context[1];}else if(post-->0){'+writeMatch('str1','ln',lnPad,'""',offWidth);
|
|
if (context[0]) cmd+='}else{pre.unshift(str1);if(pre.length>context[0])pre.pop();';
|
|
cmd+='}}';
|
|
if (env('/DBUG')) output.WriteLine(cmd);
|
|
else eval(cmd);
|
|
} else {
|
|
var cmd='while(!input.AtEndOfStream&&!quit){str2=str1=input.ReadLine();';
|
|
if ( _g.incBlock.length || _g.excBlock.length || lnWidth
|
|
|| _g.begLn || _g.endLn|| jexpr || env(env('/V')?env('/JEND'):'/JEND')
|
|
) cmd+='ln++;';
|
|
if (_g.incBlock.dynamic) cmd+='_g.setBlocks(_g.incBlock,str2);';
|
|
if (_g.excBlock.dynamic) cmd+='_g.setBlocks(_g.excBlock,str2);';
|
|
if (_g.begLn) cmd+='str2=_g.begLn(str2);';
|
|
str1='';str2='if(';
|
|
if (_g.incBlock.length) {str1+=str2+'inc()';str2='&&';}
|
|
if (_g.excBlock.length) {str1+=str2+'!exc()';str2='&&';}
|
|
if (_g.begLn||_g.endLn||jexpr||env(env('/V')?env('/JBEG'):'/JBEG')) {str1+=str2+'!skip';}
|
|
if (str1) cmd+=str1+')';
|
|
cmd+='str2=str2.replace(search,repl);';
|
|
if (_g.endLn) cmd+='str2=_g.endLn(str2);';
|
|
if (!jmatch) {
|
|
str1='';str2='if(';
|
|
if (_g.endLn||jexpr) {str1+=str2+'str2!==false';str2='&&';}
|
|
if (alterations) {str1+=str2+'str1!=str2';}
|
|
if (str1) cmd+=str1+')';
|
|
cmd+='output.Write('+(lnWidth>0?'lpad(ln,'+lnPad+')+_g.delim+':'')+'str2+eol);';
|
|
cmd+='if (str1!=str2) _g.rtn=0;';
|
|
}
|
|
cmd+='}'
|
|
if (env('/DBUG')) output.WriteLine(cmd);
|
|
else eval(cmd);
|
|
}
|
|
}
|
|
|
|
_g.main();
|
|
|
|
_g.loc=' in /JEND code';
|
|
eval( _g.readVar( env('/JEND'), env('/V'), '.JEND' ) );
|
|
_g.loc='';
|
|
if (_g.krcount) output.WriteLine(counter);
|
|
if (_g.inFile) input.Close();
|
|
if (_g.outFile) output.Close();
|
|
if (_g.outFileA[0]=='-') {
|
|
fso.GetFile(_g.inFileA[0]).Delete();
|
|
fso.GetFile(_g.inFileA[0]+'.new').Move(_g.inFileA[0]);
|
|
}
|
|
if (_g.tempFile) fso.GetFile(_g.tempFile).Delete();
|
|
|
|
|
|
if (env('/RTN')) {
|
|
_g.rtnVar = function() {
|
|
var val, str1, str2, buf=1024, arr, n;
|
|
input=_g.openInput(_g.outFile)
|
|
val='';
|
|
while (!input.AtEndOfStream) {
|
|
val+=input.Read(buf);
|
|
buf*=2;
|
|
}
|
|
input.Close();
|
|
if (env('/RTN_LINE')&&(n=parseInt(env('/RTN_LINE')))) {
|
|
arr=val.split(/\r?\n/);
|
|
n = n>0 ? n-1 : arr.length+n;
|
|
val = typeof arr[n]==='undefined' ? '' : arr[n];
|
|
} else if ((env('/MATCH')||env('/JMATCH')||env('/JMATCHQ'))&&eol&&val.slice(-eol.length)===eol){
|
|
val=val.slice(0,-eol.length);
|
|
}
|
|
output=null;
|
|
openOutput(_g.outFile, "", 0 );
|
|
str1='x'+val.replace(/%/g,'%3').replace(/\n/mg,'%~1').replace(/\r/mg,'%2').replace(/"/g,'%4');
|
|
str2=str1.replace(/[!^]/g,'^$&');
|
|
if (str2.length + env('/RTN').length > 8181) throw new Error(213, 'Result too long to fit within variable');
|
|
if (str2.indexOf('\x00')>=0) throw new Error(214, 'Null bytes (0x00) cannot be returned in a variable');
|
|
output.WriteLine(str1);
|
|
output.WriteLine(str2);
|
|
output.Close();
|
|
}
|
|
_g.rtnVar();
|
|
}
|
|
|
|
WScript.Quit(_g.rtn);
|
|
} catch(e) {
|
|
WScript.Stderr.WriteLine("JScript runtime error"+_g.loc+": "+e.message);
|
|
WScript.Quit(3);
|
|
}
|
|
|
|
function lpad( val, arg2, arg3 ) {
|
|
var rtn=val.toString(), len, pad, cnt;
|
|
if (typeof arg2 === "string") {
|
|
pad = arg2;
|
|
len = arg2.length;
|
|
} else {
|
|
len = arg2;
|
|
pad = arg3 ? arg3 : ' ';
|
|
while (pad.length < len) pad+=pad;
|
|
}
|
|
return (rtn.length<len) ? pad.slice(0,len-rtn.length)+rtn : rtn;
|
|
}
|
|
|
|
function rpad( val, arg2, arg3 ) {
|
|
var rtn=val.toString(), len, pad, cnt;
|
|
if (typeof arg2 === "string") {
|
|
pad = arg2;
|
|
len = arg2.length;
|
|
} else {
|
|
len = arg2;
|
|
pad = typeof arg3 === "string" ? arg3 : ' ';
|
|
while (pad.length < len) pad+=pad;
|
|
}
|
|
return (rtn.length<pad.length) ? rtn+pad.slice(rtn.length-len) : rtn;
|
|
}
|
|
|
|
function inc(n) {
|
|
for (var i=n?n:0, end=n?n+1:_g.incBlock.length; i<end; i++) {
|
|
var block = _g.incBlock[i];
|
|
if (ln>=block.lineNum && ln<=(block.endLineNum?block.endLineNum:ln)) return true;
|
|
}
|
|
return (_g.incBlock.length==0);
|
|
}
|
|
|
|
function exc(n) {
|
|
for (var i=n?n:0, end=n?n+1:_g.excBlock.length; i<end; i++) {
|
|
var block = _g.excBlock[i];
|
|
if (ln>=block.lineNum && ln<=(block.endLineNum?block.endLineNum:ln)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function openOutput( fileName, append, utf ) {
|
|
_g.loc=' opening output file';
|
|
if (output && output!==stdout) output.Close();
|
|
if (fileName) {
|
|
var file = fileName.split('|');
|
|
if (file[1]) output=new _g.ADOStream( file[0], append?_g.ForAppending:_g.ForWriting, file[1], file[2] );
|
|
else output=fso.OpenTextFile( fileName, append?_g.ForAppending:_g.ForWriting, true, utf?-1:0 );
|
|
}
|
|
else output=stdout;
|
|
_g.loc='';
|
|
}
|