diff options
author | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2018-12-04 16:23:11 -0500 |
---|---|---|
committer | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2018-12-10 16:39:34 -0500 |
commit | 4d42c44727a062e233e446c6c86da1c84d762d79 (patch) | |
tree | b4992b55032b1f92172d8a09b9d515531e0933fb /lib/vsprintf.c | |
parent | 8c4cf161a8b42749e986a3503f6cd4f3b5682fe3 (diff) |
lib/vsprintf: Print time and date in human readable format via %pt
There are users which print time and date represented by content of
struct rtc_time in human readable format.
Instead of open coding that each time introduce %ptR[dt][r] specifier.
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Guan Xuetao <gxt@mprc.pku.edu.cn>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jason Wessel <jason.wessel@windriver.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Jonathan Hunter <jonathanh@nvidia.com>
Cc: Krzysztof Kozlowski <krzk@kernel.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Petr Mladek <pmladek@suse.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 37a54a6dd594..3add92329bae 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/ioport.h> | 30 | #include <linux/ioport.h> |
31 | #include <linux/dcache.h> | 31 | #include <linux/dcache.h> |
32 | #include <linux/cred.h> | 32 | #include <linux/cred.h> |
33 | #include <linux/rtc.h> | ||
33 | #include <linux/uuid.h> | 34 | #include <linux/uuid.h> |
34 | #include <linux/of.h> | 35 | #include <linux/of.h> |
35 | #include <net/addrconf.h> | 36 | #include <net/addrconf.h> |
@@ -822,6 +823,20 @@ static const struct printf_spec default_dec_spec = { | |||
822 | .precision = -1, | 823 | .precision = -1, |
823 | }; | 824 | }; |
824 | 825 | ||
826 | static const struct printf_spec default_dec02_spec = { | ||
827 | .base = 10, | ||
828 | .field_width = 2, | ||
829 | .precision = -1, | ||
830 | .flags = ZEROPAD, | ||
831 | }; | ||
832 | |||
833 | static const struct printf_spec default_dec04_spec = { | ||
834 | .base = 10, | ||
835 | .field_width = 4, | ||
836 | .precision = -1, | ||
837 | .flags = ZEROPAD, | ||
838 | }; | ||
839 | |||
825 | static noinline_for_stack | 840 | static noinline_for_stack |
826 | char *resource_string(char *buf, char *end, struct resource *res, | 841 | char *resource_string(char *buf, char *end, struct resource *res, |
827 | struct printf_spec spec, const char *fmt) | 842 | struct printf_spec spec, const char *fmt) |
@@ -1550,6 +1565,87 @@ char *address_val(char *buf, char *end, const void *addr, const char *fmt) | |||
1550 | } | 1565 | } |
1551 | 1566 | ||
1552 | static noinline_for_stack | 1567 | static noinline_for_stack |
1568 | char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r) | ||
1569 | { | ||
1570 | int year = tm->tm_year + (r ? 0 : 1900); | ||
1571 | int mon = tm->tm_mon + (r ? 0 : 1); | ||
1572 | |||
1573 | buf = number(buf, end, year, default_dec04_spec); | ||
1574 | if (buf < end) | ||
1575 | *buf = '-'; | ||
1576 | buf++; | ||
1577 | |||
1578 | buf = number(buf, end, mon, default_dec02_spec); | ||
1579 | if (buf < end) | ||
1580 | *buf = '-'; | ||
1581 | buf++; | ||
1582 | |||
1583 | return number(buf, end, tm->tm_mday, default_dec02_spec); | ||
1584 | } | ||
1585 | |||
1586 | static noinline_for_stack | ||
1587 | char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r) | ||
1588 | { | ||
1589 | buf = number(buf, end, tm->tm_hour, default_dec02_spec); | ||
1590 | if (buf < end) | ||
1591 | *buf = ':'; | ||
1592 | buf++; | ||
1593 | |||
1594 | buf = number(buf, end, tm->tm_min, default_dec02_spec); | ||
1595 | if (buf < end) | ||
1596 | *buf = ':'; | ||
1597 | buf++; | ||
1598 | |||
1599 | return number(buf, end, tm->tm_sec, default_dec02_spec); | ||
1600 | } | ||
1601 | |||
1602 | static noinline_for_stack | ||
1603 | char *rtc_str(char *buf, char *end, const struct rtc_time *tm, const char *fmt) | ||
1604 | { | ||
1605 | bool have_t = true, have_d = true; | ||
1606 | bool raw = false; | ||
1607 | int count = 2; | ||
1608 | |||
1609 | switch (fmt[count]) { | ||
1610 | case 'd': | ||
1611 | have_t = false; | ||
1612 | count++; | ||
1613 | break; | ||
1614 | case 't': | ||
1615 | have_d = false; | ||
1616 | count++; | ||
1617 | break; | ||
1618 | } | ||
1619 | |||
1620 | raw = fmt[count] == 'r'; | ||
1621 | |||
1622 | if (have_d) | ||
1623 | buf = date_str(buf, end, tm, raw); | ||
1624 | if (have_d && have_t) { | ||
1625 | /* Respect ISO 8601 */ | ||
1626 | if (buf < end) | ||
1627 | *buf = 'T'; | ||
1628 | buf++; | ||
1629 | } | ||
1630 | if (have_t) | ||
1631 | buf = time_str(buf, end, tm, raw); | ||
1632 | |||
1633 | return buf; | ||
1634 | } | ||
1635 | |||
1636 | static noinline_for_stack | ||
1637 | char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, | ||
1638 | const char *fmt) | ||
1639 | { | ||
1640 | switch (fmt[1]) { | ||
1641 | case 'R': | ||
1642 | return rtc_str(buf, end, (const struct rtc_time *)ptr, fmt); | ||
1643 | default: | ||
1644 | return ptr_to_id(buf, end, ptr, spec); | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | static noinline_for_stack | ||
1553 | char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, | 1649 | char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, |
1554 | const char *fmt) | 1650 | const char *fmt) |
1555 | { | 1651 | { |
@@ -1828,6 +1924,8 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, | |||
1828 | * - 'd[234]' For a dentry name (optionally 2-4 last components) | 1924 | * - 'd[234]' For a dentry name (optionally 2-4 last components) |
1829 | * - 'D[234]' Same as 'd' but for a struct file | 1925 | * - 'D[234]' Same as 'd' but for a struct file |
1830 | * - 'g' For block_device name (gendisk + partition number) | 1926 | * - 'g' For block_device name (gendisk + partition number) |
1927 | * - 't[R][dt][r]' For time and date as represented: | ||
1928 | * R struct rtc_time | ||
1831 | * - 'C' For a clock, it prints the name (Common Clock Framework) or address | 1929 | * - 'C' For a clock, it prints the name (Common Clock Framework) or address |
1832 | * (legacy clock framework) of the clock | 1930 | * (legacy clock framework) of the clock |
1833 | * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address | 1931 | * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address |
@@ -1952,6 +2050,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
1952 | return address_val(buf, end, ptr, fmt); | 2050 | return address_val(buf, end, ptr, fmt); |
1953 | case 'd': | 2051 | case 'd': |
1954 | return dentry_name(buf, end, ptr, spec, fmt); | 2052 | return dentry_name(buf, end, ptr, spec, fmt); |
2053 | case 't': | ||
2054 | return time_and_date(buf, end, ptr, spec, fmt); | ||
1955 | case 'C': | 2055 | case 'C': |
1956 | return clock(buf, end, ptr, spec, fmt); | 2056 | return clock(buf, end, ptr, spec, fmt); |
1957 | case 'D': | 2057 | case 'D': |