Bug#605615: [PATCH] Fix gettext quotation in util/grub.d

Colin Watson cjwatson at ubuntu.com
Tue Dec 21 12:31:23 UTC 2010


http://bugs.debian.org/605615

This happens when the system shell is bash rather than dash.  The behaviour
of printf when the format string contains the character sequence \' is
unspecified.

Adding an extra layer of quotation and making sure that everything that uses
it goes through printf (so that that extra layer is consistently removed) is
easy.  I added a gettext_printf function to help with this, which is briefer
and involves fewer nested layers of open-coded quotation.

The tricky bit is making sure that xgettext understands what's going on!
Adding --keyword=gettext_printf is obvious, but I noticed along the way
that we weren't setting c-format flags so that translations were checked
for the right number of %s entries and the like.  I tried adding
--flag=gettext_quoted:1:c-format --flag=gettext_printf:1:c-format, but
it turns out that xgettext refuses to include c-format flags for strings
it extracted from a shell file.  Whoops.  Since we already had a
modified version of po/Makefile.in.in, I changed it a bit further to fix
things up with sed.

Finally, xgettext refuses to extract strings from here-documents (which
I think is probably a bug, and if I can manage to write a reduced test
case for it I'll report it to the gettext maintainers).  Thus, I
extracted translatable strings from here-documents and used a temporary
variable for them instead.

2010-12-21  Colin Watson  <cjwatson at ubuntu.com>

	* util/grub-mkconfig_lib.in (gettext_quoted): Add clarifying
	comment.  Add an extra layer of quotation, requiring the output of
	this function to be used in a printf format string.
	(gettext_printf): New function.
	* util/grub.d/10_hurd.in: Use gettext_printf where appropriate.
	Extract translatable strings from here-documents and use a temporary
	variable instead, so that xgettext can find them.
	* util/grub.d/10_kfreebsd.in: Likewise.
	* util/grub.d/10_linux.in: Likewise.
	* util/grub.d/20_linux_xen.in: Likewise.

	* po/grub.d.sed: New file.
	* po/Makefile.in.in ($(DOMAIN).pot-update): Extract gettext_printf
	arguments.  Set c-format flags on all strings extracted from
	util/grub.d/ (xgettext refuses to include these itself for strings
	it extracted from a shell file, but these really are c-format).

=== modified file 'po/Makefile.in.in'
--- po/Makefile.in.in	2010-09-20 23:09:23 +0000
+++ po/Makefile.in.in	2010-12-21 12:05:05 +0000
@@ -173,7 +173,8 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcd
 	      --files-from=$(srcdir)/POTFILES-shell.in \
 	      --copyright-holder='$(COPYRIGHT_HOLDER)' \
 	      --msgid-bugs-address="$$msgid_bugs_address" \
-	      --join-existing --language=Shell --keyword=gettext_quoted \
+	      --join-existing --language=Shell \
+	      --keyword=gettext_quoted --keyword=gettext_printf \
 	    ;; \
 	  *) \
 	    $(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
@@ -183,10 +184,13 @@ $(DOMAIN).pot-update: $(POTFILES) $(srcd
 	      --package-name="$${package_gnu}@PACKAGE@" \
 	      --package-version='@VERSION@' \
 	      --msgid-bugs-address="$$msgid_bugs_address" \
-	      --join-existing --language=Shell --keyword=gettext_quoted \
+	      --join-existing --language=Shell \
+	      --keyword=gettext_quoted --keyword=gettext_printf \
 	    ;; \
 	esac
 	test ! -f $(DOMAIN).po || { \
+	  sed -f grub.d.sed < $(DOMAIN).po > $(DOMAIN).1po && \
+	  mv $(DOMAIN).1po $(DOMAIN).po; \
 	  if test -f $(srcdir)/$(DOMAIN).pot; then \
 	    sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \
 	    sed -f remove-potcdate.sed < $(DOMAIN).po > $(DOMAIN).2po && \

=== added file 'po/grub.d.sed'
--- po/grub.d.sed	1970-01-01 00:00:00 +0000
+++ po/grub.d.sed	2010-12-21 12:02:27 +0000
@@ -0,0 +1,2 @@
+/^#: util\/grub\.d\//a\
+#, c-format

=== modified file 'util/grub-mkconfig_lib.in'
--- util/grub-mkconfig_lib.in	2010-09-15 12:46:53 +0000
+++ util/grub-mkconfig_lib.in	2010-12-21 12:13:33 +0000
@@ -187,8 +187,20 @@ version_find_latest ()
   echo "$a"
 }
 
+# One layer of quotation is eaten by "", the second by sed, and the third by
+# printf; so this turns ' into \'.  Note that you must use the output of
+# this function in a printf format string.
 gettext_quoted () {
-  $gettext "$@" | sed "s/'/'\\\\''/g"
+  $gettext "$@" | sed "s/'/'\\\\\\\\''/g"
+}
+
+# Run the first argument through gettext_quoted, and then pass that and all
+# remaining arguments to printf.  This is a useful abbreviation and tends to
+# be easier to type.
+gettext_printf () {
+  local format="$1"
+  shift
+  printf "$(gettext_quoted "$format")" "$@"
 }
 
 uses_abstraction () {

=== modified file 'util/grub.d/10_hurd.in'
--- util/grub.d/10_hurd.in	2010-11-01 11:49:40 +0000
+++ util/grub.d/10_hurd.in	2010-12-21 11:45:56 +0000
@@ -81,14 +81,16 @@ do
 menuentry "${OS} ${KERNEL}" ${CLASS} {
 EOF
   prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
+  message="$(gettext_printf "Loading GNU Mach ...")"
   cat << EOF
-	echo		'$(gettext_quoted "Loading GNU Mach ...")'
+	echo		'$message'
 	multiboot	${kernel} root=device:${GRUB_DEVICE#/dev/}
 EOF
   save_default_entry | sed -e "s/^/\t/"
   prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/"
+  message="$(gettext_printf "Loading the Hurd ...")"
   cat << EOF
-	echo		'$(gettext_quoted "Loading the Hurd ...")'
+	echo		'$message'
 	module		/hurd/${hurd_fs}.static ${hurd_fs} --readonly \\
 			--multiboot-command-line='\${kernel-command-line}' \\
 			--host-priv-port='\${host-port}' \\
@@ -103,13 +105,15 @@ EOF
 menuentry "${OS} ${KERNEL} (recovery mode)" ${CLASS} {
 EOF
   prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
+  message="$(gettext_printf "Loading GNU Mach ...")"
   cat << EOF
-	echo		'$(gettext_quoted "Loading GNU Mach ...")'
+	echo		'$message'
 	multiboot	${kernel} root=device:${GRUB_DEVICE#/dev/} -s
 EOF
   prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/"
+  message="$(gettext_printf "Loading the Hurd ...")"
   cat << EOF
-	echo		'$(gettext_quoted "Loading the Hurd ...")'
+	echo		'$message'
 	module		/hurd/${hurd_fs}.static ${hurd_fs} \\
 			--multiboot-command-line='\${kernel-command-line}' \\
 			--host-priv-port='\${host-port}' \\

=== modified file 'util/grub.d/10_kfreebsd.in'
--- util/grub.d/10_kfreebsd.in	2010-11-01 11:49:40 +0000
+++ util/grub.d/10_kfreebsd.in	2010-12-21 11:46:13 +0000
@@ -84,8 +84,9 @@ kfreebsd_entry ()
   fi
 
   printf '%s\n' "${prepare_boot_cache}"
+  message="$(gettext_printf "Loading kernel of FreeBSD %s ..." ${version})"
   cat << EOF
-	echo			'$(printf "$(gettext_quoted "Loading kernel of FreeBSD %s ...")" ${version})'
+	echo			'$message'
 	kfreebsd		${rel_dirname}/${basename} ${args}
 EOF
 

=== modified file 'util/grub.d/10_linux.in'
--- util/grub.d/10_linux.in	2010-11-01 11:49:40 +0000
+++ util/grub.d/10_linux.in	2010-12-21 11:43:50 +0000
@@ -94,13 +94,15 @@ EOF
     prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
   fi
   printf '%s\n' "${prepare_boot_cache}"
+  message="$(gettext_printf "Loading Linux %s ..." ${version})"
   cat << EOF
-	echo	'$(printf "$(gettext_quoted "Loading Linux %s ...")" ${version})'
+	echo	'$message'
 	linux	${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
 EOF
   if test -n "${initrd}" ; then
+    message="$(gettext_printf "Loading initial ramdisk ...")"
     cat << EOF
-	echo	'$(gettext_quoted "Loading initial ramdisk ...")'
+	echo	'$message'
 	initrd	${rel_dirname}/${initrd}
 EOF
   fi

=== modified file 'util/grub.d/20_linux_xen.in'
--- util/grub.d/20_linux_xen.in	2010-11-01 11:49:40 +0000
+++ util/grub.d/20_linux_xen.in	2010-12-21 11:46:36 +0000
@@ -73,14 +73,16 @@ linux_entry ()
     prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
   fi
   printf '%s\n' "${prepare_boot_cache}"
+  message="$(gettext_printf "Loading Linux %s ..." ${version})"
   cat << EOF
-	echo	'$(printf "$(gettext_quoted "Loading Linux %s ...")" ${version})'
+	echo	'$message'
 	multiboot	${rel_xen_dirname}/${xen_basename} placeholder ${xen_args}
 	module	${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
 EOF
   if test -n "${initrd}" ; then
+    message="$(gettext_printf "Loading initial ramdisk ...")"
     cat << EOF
-	echo	'$(gettext_quoted "Loading initial ramdisk ...")'
+	echo	'$message'
 	module	${rel_dirname}/${initrd}
 EOF
   fi

-- 
Colin Watson                                       [cjwatson at ubuntu.com]





More information about the Pkg-grub-devel mailing list