Skip to content

Commit

Permalink
improve handling of quoted values
Browse files Browse the repository at this point in the history
- enclose output in single quotes instead of double quotes to avoid
unwanted side effects of parameter substitution or command exection by
the shell
- replace single quotes accordingly, so that the variable assignment
still results in the correct value (containing a single quote)
- remove backslashes that escape double quotes to retain previous
behavior
  • Loading branch information
mrbaseman committed Feb 18, 2024
1 parent e306187 commit eed90b2
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 6 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ The following yaml features are currently supported:
* lists or sequences (`- entry`) with indentation to denote the level
* short notation of lists (`list: [ value, ... ]`)
* unordered lists or sometimes called sets (`? entry`)
* values may be single words (i.e. containing only alphanumeric characters)
* keys may be single words (i.e. containing only alphanumeric characters)
* values (strings) can be enclosed in single or double quotes
* multiline values (`multiline: | ...`) where the following lines are indented one level deeper than the key
* wrapped content (`wrapped: > ...`) where line breaks are converted to spaces and empty lines to newlines
Expand All @@ -107,7 +107,7 @@ The following yaml features are currently supported:
* keys in mappings are assumed to be words (consisting of alphanumerical characters), dots are replaced by the separator character, but other special characters are not supported.
* unordered lists are converted to ordered lists for simplicity
* strings enclosed in quotes should work, but when double- and single quotes are nested in a too complex manner, the regex used for parsing might not correctly capture the value
* multiple quotes inside a string are not correctly "unfolded". Two subsequent single quotes in a string enclosed by single quotes should become one single quote. There might also be problems with quotes masked by backslash in a quoted string.
* multiple quotes inside a string are not correctly "unfolded". Single quotes in a string should be preserved such that they are properly escaped in the variable assignment. There might be problems with quotes masked by backslash in a quoted string.
* plain and quoted multi-line flow scalars produce output for each line to be appended
* anchors are not fully dereferenced twice, i.e. when an anchor is defined and it contains references to other anchors, those are dereferenced when the anchor is processed. If those anchors are re-defined later on, and the main anchor that contains the references on the re-defined anchors, is later dereferenced, it still contains the outdated values.
* if a quoted string starts with a `'*'` character and an anchor exists which is denoted by the following characters in the string, this is currently treated as a dereference, even if the string is enclosed in single quotes
Expand Down
10 changes: 6 additions & 4 deletions src/parse_yaml.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,14 @@ function parse_yaml {
if(vn==\"_\")vn=\"__\";
}
gsub(/\./,\"$separator\",full_vn);
gsub(/\\\\\"/,\"\\\"\",value);
gsub(/'/,\"'\\\"'\\\"'\",value);
assignment[full_vn]=value;
if(!match(assignment[vn], full_vn))assignment[vn]=assignment[vn] \" \" full_vn;
if(match(value,/^\*/)){
ref=anchor[substr(value,2)];
if(length(ref)==0){
printf(\"%s=\\\"%s\\\"\n\", full_vn, value);
printf(\"%s='%s'\n\", full_vn, value);
} else {
for(val in assignment){
if((length(ref)>0)&&index(val, ref)==1){
Expand All @@ -146,19 +148,19 @@ function parse_yaml {
if(match(val,\"$separator\$\")){
gsub(ref,full_vn,tmpval);
} else if (length(tmpval) > 0) {
printf(\"%s=\\\"%s\\\"\n\", val, tmpval);
printf(\"%s='%s'\n\", val, tmpval);
}
assignment[val]=tmpval;
}
}
}
} else if (length(value) > 0) {
printf(\"%s=\\\"%s\\\"\n\", full_vn, value);
printf(\"%s='%s'\n\", full_vn, value);
}
}END{
for(val in assignment){
if(match(val,\"$separator\$\"))
printf(\"%s=\\\"%s\\\"\n\", val, assignment[val]);
printf(\"%s='%s'\n\", val, assignment[val]);
}
}"
}
9 changes: 9 additions & 0 deletions tests/fixtures/quoted_values.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Test fixture: quoted values

---

double_quotes: "this is a quoted string"
single_quotes: 'this is in single quotes'
nested_quotes: 'there may be "double quotes" inside of single quotes'
single_quotes_in_double: "also here it's possible to have single quotes"
double_quotes_in_double: "masked \"double quotes\" inside of double quotes"
12 changes: 12 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,18 @@ test_variable key_withdots "blue"
test_variable another_key "yellow"
test_variable key "red"

# ---------------------------
# quoted values
# ---------------------------
eval $(parse_yaml fixtures/quoted_values.yml)
test_variable __ " double_quotes single_quotes nested_quotes single_quotes_in_double double_quotes_in_double"

test_variable double_quotes 'this is a quoted string'
test_variable single_quotes 'this is in single quotes'
test_variable nested_quotes 'there may be "double quotes" inside of single quotes'
test_variable single_quotes_in_double "also here it's possible to have single quotes"
test_variable double_quotes_in_double 'masked "double quotes" inside of double quotes'


# ---------------------------
# Test everything everywhere all at once
Expand Down

0 comments on commit eed90b2

Please sign in to comment.