FIX: cleaninput() for sed-replacement needs more escaping and unique separator.

Commit 8e4364f5e1 removed the deletion of the "|" character from cleaninput. That was okay for the cleaninput() use in _addto(), but not in those cases that used $input for replacement via sed.

Added corresponding tests for replace, append and prepend actions similar to what was added for the add action in the above commit.

To really fix the problem (and not just remove all "|" characters from the text), a separator character must be found that is not part of $input, and this must be used in the sed expression. As cleaninput() already modifies the global $input variable, another $inputSep global variable is used to pass back this information.

In addition, backslashes must be escaped in $input, or replacements like \1 wreak havoc.
This commit is contained in:
Ingo Karkat
2011-05-11 16:12:03 +02:00
parent 41dba2d636
commit a97144d0e8
4 changed files with 85 additions and 12 deletions

View File

@@ -45,6 +45,12 @@ grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'replace error' << EOF
>>> todo.sh replace 10 "hej!"
=== 1
TODO: No task 10.
EOF
test_todo_session 'replace in multi-item file' <<EOF
>>> todo.sh replace 1 smell the cheese
1 smell the cows
@@ -89,10 +95,24 @@ grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'replace error' << EOF
>>> todo.sh replace 10 "hej!"
=== 1
TODO: No task 10.
test_todo_session 'replace with symbols' <<EOF
>>> todo.sh replace 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 smell the cows
TODO: Replaced task with:
1 ~@#$%^&*()-_=+[{]}|;:',<.>/?
>>> todo.sh replace 2 '\`!\\"'
2 grow some corn
TODO: Replaced task with:
2 \`!\\"
>>> todo.sh list
4 chase the chickens
3 thrash some hay
2 \`!\\"
1 ~@#$%^&*()-_=+[{]}|;:',<.>/?
--
TODO: 4 of 4 tasks shown
EOF
cat /dev/null > todo.txt

View File

@@ -57,6 +57,28 @@ test_todo_session 'prepend with &' <<EOF
3 no running & jumping now stop
EOF
cat > todo.txt <<EOF
smell the cows
grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'prepend with symbols' <<EOF
>>> todo.sh prepend 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 ~@#$%^&*()-_=+[{]}|;:',<.>/? smell the cows
>>> todo.sh prepend 2 '\`!\\"'
2 \`!\\" grow some corn
>>> todo.sh list
4 chase the chickens
3 thrash some hay
2 \`!\\" grow some corn
1 ~@#$%^&*()-_=+[{]}|;:',<.>/? smell the cows
--
TODO: 4 of 4 tasks shown
EOF
cat /dev/null > todo.txt
test_todo_session 'prepend handling prepended date on add' <<EOF
>>> todo.sh -t add "new task"

View File

@@ -17,6 +17,12 @@ test_todo_session 'append usage' <<EOF
usage: todo.sh append ITEM# "TEXT TO APPEND"
EOF
test_todo_session 'append error' << EOF
>>> todo.sh append 10 "hej!"
=== 1
TODO: No task 10.
EOF
test_todo_session 'basic append' <<EOF
>>> todo.sh append 1 "smell the roses"
1 notice the daisies smell the roses
@@ -37,11 +43,26 @@ test_todo_session 'basic append with &' <<EOF
TODO: 1 of 1 tasks shown
EOF
cat > todo.txt <<EOF
smell the cows
grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'append with symbols' <<EOF
>>> todo.sh append 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 smell the cows ~@#$%^&*()-_=+[{]}|;:',<.>/?
test_todo_session 'append error' << EOF
>>> todo.sh append 10 "hej!"
=== 1
TODO: No task 10.
>>> todo.sh append 2 '\`!\\"'
2 grow some corn \`!\\"
>>> todo.sh list
4 chase the chickens
2 grow some corn \`!\\"
1 smell the cows ~@#$%^&*()-_=+[{]}|;:',<.>/?
3 thrash some hay
--
TODO: 4 of 4 tasks shown
EOF
cat > todo.txt <<EOF

18
todo.sh
View File

@@ -272,8 +272,16 @@ cleaninput()
input=`echo $input | tr -d '\r\n'`
if [ "$1" = "for sed" ]; then
# This action uses sed and & as the matched string so escape it
input=`echo $input | sed 's/\&/\\\&/g'`
# This action uses sed and & as the matched string so escape it.
# Backslashes must be escaped, too.
input=`echo $input | sed -e 's+\\\+\\\\\\\\+g' -e 's/\&/\\\&/g'`
# Find a separator that doesn't occur in $input, sed cannot handle it, and escaping doesn't help.
# In the worst case (no separator found), the replacement text after the "|" is lost.
for inputSep in '%' '#' '@' ':' '!' '|'
do
[[ "$input" = *${inputSep}* ]] || break
done
fi
}
@@ -319,6 +327,7 @@ replaceOrPrepend()
input=$*
fi
cleaninput "for sed"
sep=${inputSep:-|}
# Retrieve existing priority and prepended date
priority=$(sed -e "$item!d" -e $item's/^\(([A-Z]) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\1/' "$TODO_FILE")
@@ -333,7 +342,7 @@ replaceOrPrepend()
# Temporarily remove any existing priority and prepended date, perform the
# change (replace/prepend) and re-insert the existing priority and prepended
# date again.
sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s|^.*|${priority}${prepdate}${input}${backref}|" "$TODO_FILE"
sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s${sep}^.*${sep}${priority}${prepdate}${input}${backref}${sep}" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
newtodo=$(sed "$item!d" "$TODO_FILE")
case "$action" in
@@ -840,8 +849,9 @@ case $action in
*) appendspace=" ";;
esac
cleaninput "for sed"
sep=${inputSep:-|}
if sed -i.bak $item" s|^.*|&${appendspace}${input}|" "$TODO_FILE"; then
if sed -i.bak $item" s${sep}^.*${sep}&${appendspace}${input}${sep}" "$TODO_FILE"; then
if [ $TODOTXT_VERBOSE -gt 0 ]; then
newtodo=$(sed "$item!d" "$TODO_FILE")
echo "$item $newtodo"