lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

It's been noted on this list[1] that many implementations of the
printf() family support positional parameters, to help i18n/l10n
efforts.  The example in the archive message was

printf("%2$s %1$s\n", "world!", "Hello");  /* prints "Hello world!\n" */

I haven't been able to find any discussion in the archives proposing
similar behavior for Lua.  Has this been kicked around before?

Attached is a patch implementing the same behavior described in the
POSIX extension[2]:  instead of plain '%' starting a conversion
sequence, you can use '%n$', where n is the integer index of format
arguments.  Some annotated examples after applying the patch against

> =string.format("%2$s %1$s\n", "world!", "Hello")
Hello world!

Straightforward enough.

> =string.format("%3$d %1$d %d\n", 11, 22, 33, 44)
33 11 22

Mixing numbered (%n$) and unnumbered (%) specifications is undefined
behavior in POSIX.  But string.format doesn't do one big call to
sprintf, so mixing doesn't need to cause errors; instead you just need
to choose what behavior is least surprising.  The patch as posted
causes the index to be "permanently" updated, that is, after
specifying n, the next unnumbered index is n+1, n+2, and so on rather
than picking back up where it left off.  Saving and restoring the
unnumbered index would be easy also.

> =string.format("%3$12.5f %d\n", 11, 22, 33.33, 44)
    33.33000 44

All the existing flags and other modifiers are still present.

The n specifier has to be a nonnegative integral; getting that part
wrong throws some errors.  I'm not too keen about the wording on the
error message in my patch, but at least something is caught.  For

> =string.format("%-42$d\n", 1, 2, 3)
stdin:1: invalid '%n$' position in format (out of range)
stack traceback:
        [C]: in function 'format'
        stdin:1: in main chunk
        [C]: ?

> =string.format("%7.7$d\n", 1, 2, 3, 4)
stdin:1: invalid option '%$' to 'format'
stack traceback:
        [C]: in function 'format'
        stdin:1: in main chunk
        [C]: ?

Anyhow, patch follows.  It's not for me to say if this is worth
inclusion in base Lua source or in the "power patches" wiki, but I
figured I'd throw it out there.  (One note:  the "if
(isdigit(uchar(*strfrmt)))" which surrounds the change can be removed
entirely and the enclosed block used as-is.  The test is only to try
and speed up the normal case in which unnumbered arguments are used,
on the assumption that isdigit is a macro and strtol is expensive even
when it fails instantly.)

Comments welcome.

[3] there is no third note[4]
[4] but there is a fourth!

Attachment: strformat.patch
Description: Binary data