public inbox for pbs-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [RFC PATCH proxmox-backup] ui: implement quoted strings in parsePropertyString
Date: Wed,  9 Mar 2022 15:16:46 +0100	[thread overview]
Message-ID: <20220309141646.1027526-1-d.csapak@proxmox.com> (raw)

like we do in our rust propertystring parser.
code is heavily inspired by the rust code.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
if we want to go the js route and not use wasm + rust code for this

i sent it as rfc for pbs (since there we have that property string
implementation), but we actually want this to live in wt, and use it in
pve and pbs both when pve gains support for these.

@thomas, the code is my attempt to write the parser as close to the
rust code as it was sensible, but i'm sure there are some js specific
improvements to be done here. i'll look over it again tomorrow
with fresh eyes and mind, but if you see some things, don't hold back ;)

 www/Utils.js | 100 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 82 insertions(+), 18 deletions(-)

diff --git a/www/Utils.js b/www/Utils.js
index 36a94211..87809364 100644
--- a/www/Utils.js
+++ b/www/Utils.js
@@ -62,32 +62,96 @@ Ext.define('PBS.Utils', {
 	return path.indexOf(PBS.Utils.dataStorePrefix) === 0;
     },
 
+    parseQuotedString: function(value) {
+	let data = "";
+	let was_backslash = false;
+	if (value[0] !== '"') {
+	    throw "not a quoted string";
+	}
+	value = value.slice(1);
+	for (let i = 0; ; i++) {
+	    if (i === value.length) {
+		throw "invalid quoted string";
+	    }
+	    if (was_backslash) {
+		was_backslash = false;
+		switch (value[i]) {
+		    case '"': data += '"'; break;
+		    case '\\': data += '\\'; break;
+		    case 'n': data += '\n'; break;
+		    default:
+			throw "unsupported escape sequence";
+		}
+	    } else {
+		switch (value[i]) {
+		    case '"': return [data, i+1];
+		    case '\\': was_backslash = true; break;
+		    default:
+			data += value[i];
+		}
+	    }
+	}
+    },
+
     parsePropertyString: function(value, defaultKey) {
-	var res = {},
-	    error;
+	let res = {};
 
 	if (typeof value !== 'string' || value === '') {
 	    return res;
 	}
 
-	Ext.Array.each(value.split(','), function(p) {
-	    var kv = p.split('=', 2);
-	    if (Ext.isDefined(kv[1])) {
-		res[kv[0]] = kv[1];
-	    } else if (Ext.isDefined(defaultKey)) {
-		if (Ext.isDefined(res[defaultKey])) {
-		    error = 'defaultKey may be only defined once in propertyString';
-		    return false; // break
+	try {
+	    while (value.length > 0) {
+		let key, current;
+		if (value[0] !== '"') {
+		    let idx = value.search(/[,=]/);
+		    if (idx !== -1 && value[idx] === '=') {
+			key = value.slice(0, idx);
+			value = value.slice(idx + 1);
+			if (Ext.isDefined(res[key])) {
+			    throw `duplicate key ${key} found`;
+			}
+		    }
+
+		    if (value[0] !== '"') {
+			let next_idx = value.search(/,/);
+			if (next_idx === -1) {
+			    current = value;
+			    value = "";
+			} else {
+			    current = value.slice(0, next_idx);
+			    value = value.slice(next_idx + 1);
+			}
+		    }
 		}
-		res[defaultKey] = kv[0];
-	    } else {
-		error = 'invalid propertyString, not a key=value pair and no defaultKey defined';
-		return false; // break
-	    }
-	    return true;
-	});
 
-	if (error !== undefined) {
+		if (key === undefined) {
+		    if (Ext.isDefined(defaultKey)) {
+			if (Ext.isDefined(res[defaultKey])) {
+			    throw 'defaultKey may be only defined once in propertyString';
+			}
+			key = defaultKey;
+		    } else {
+			throw "value without key and no defaultKey";
+		    }
+		}
+		if (current === undefined) {
+		    let [val, idx] = PVE.Parser.parseQuotedString(value);
+		    current = val;
+		    value = value.slice(idx + 1);
+		}
+
+		res[key] = current;
+
+		if (value.length > 0) {
+		    if (value[0] === ',') {
+			value = value.slice(1);
+		    } else {
+			throw "garbage after value";
+		    }
+		}
+	    }
+	} catch (error) {
 	    console.error(error);
 	    return null;
 	}
-- 
2.30.2





                 reply	other threads:[~2022-03-09 14:16 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220309141646.1027526-1-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal