cursor-free-vip/uBlock0.chromium/js/arglist-parser.js
2025-01-14 14:47:41 +08:00

117 lines
4.7 KiB
JavaScript

/*******************************************************************************
uBlock Origin - a comprehensive, efficient content blocker
Copyright (C) 2020-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
/******************************************************************************/
export class ArglistParser {
constructor(separatorChar = ',', mustQuote = false) {
this.separatorChar = this.actualSeparatorChar = separatorChar;
this.separatorCode = this.actualSeparatorCode = separatorChar.charCodeAt(0);
this.mustQuote = mustQuote;
this.quoteBeg = 0; this.quoteEnd = 0;
this.argBeg = 0; this.argEnd = 0;
this.separatorBeg = 0; this.separatorEnd = 0;
this.transform = false;
this.failed = false;
this.reWhitespaceStart = /^\s+/;
this.reWhitespaceEnd = /\s+$/;
this.reOddTrailingEscape = /(?:^|[^\\])(?:\\\\)*\\$/;
this.reTrailingEscapeChars = /\\+$/;
}
nextArg(pattern, beg = 0) {
const len = pattern.length;
this.quoteBeg = beg + this.leftWhitespaceCount(pattern.slice(beg));
this.failed = false;
const qc = pattern.charCodeAt(this.quoteBeg);
if ( qc === 0x22 /* " */ || qc === 0x27 /* ' */ || qc === 0x60 /* ` */ ) {
this.indexOfNextArgSeparator(pattern, qc);
if ( this.argEnd !== len ) {
this.quoteEnd = this.argEnd + 1;
this.separatorBeg = this.separatorEnd = this.quoteEnd;
this.separatorEnd += this.leftWhitespaceCount(pattern.slice(this.quoteEnd));
if ( this.separatorEnd === len ) { return this; }
if ( pattern.charCodeAt(this.separatorEnd) === this.separatorCode ) {
this.separatorEnd += 1;
return this;
}
}
}
this.indexOfNextArgSeparator(pattern, this.separatorCode);
this.separatorBeg = this.separatorEnd = this.argEnd;
if ( this.separatorBeg < len ) {
this.separatorEnd += 1;
}
this.argEnd -= this.rightWhitespaceCount(pattern.slice(0, this.separatorBeg));
this.quoteEnd = this.argEnd;
if ( this.mustQuote ) {
this.failed = true;
}
return this;
}
normalizeArg(s, char = '') {
if ( char === '' ) { char = this.actualSeparatorChar; }
let out = '';
let pos = 0;
while ( (pos = s.lastIndexOf(char)) !== -1 ) {
out = s.slice(pos) + out;
s = s.slice(0, pos);
const match = this.reTrailingEscapeChars.exec(s);
if ( match === null ) { continue; }
const tail = (match[0].length & 1) !== 0
? match[0].slice(0, -1)
: match[0];
out = tail + out;
s = s.slice(0, -match[0].length);
}
if ( out === '' ) { return s; }
return s + out;
}
leftWhitespaceCount(s) {
const match = this.reWhitespaceStart.exec(s);
return match === null ? 0 : match[0].length;
}
rightWhitespaceCount(s) {
const match = this.reWhitespaceEnd.exec(s);
return match === null ? 0 : match[0].length;
}
indexOfNextArgSeparator(pattern, separatorCode) {
this.argBeg = this.argEnd = separatorCode !== this.separatorCode
? this.quoteBeg + 1
: this.quoteBeg;
this.transform = false;
if ( separatorCode !== this.actualSeparatorCode ) {
this.actualSeparatorCode = separatorCode;
this.actualSeparatorChar = String.fromCharCode(separatorCode);
}
while ( this.argEnd < pattern.length ) {
const pos = pattern.indexOf(this.actualSeparatorChar, this.argEnd);
if ( pos === -1 ) {
return (this.argEnd = pattern.length);
}
if ( this.reOddTrailingEscape.test(pattern.slice(0, pos)) === false ) {
return (this.argEnd = pos);
}
this.transform = true;
this.argEnd = pos + 1;
}
}
}