mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									8c4cf161a8
								
							
						
					
					
						commit
						4d42c44727
					
				
					 3 changed files with 176 additions and 3 deletions
				
			
		|  | @ -412,6 +412,24 @@ Examples:: | |||
| 
 | ||||
| Passed by reference. | ||||
| 
 | ||||
| Time and date (struct rtc_time) | ||||
| ------------------------------- | ||||
| 
 | ||||
| :: | ||||
| 
 | ||||
| 	%ptR		YYYY-mm-ddTHH:MM:SS | ||||
| 	%ptRd		YYYY-mm-dd | ||||
| 	%ptRt		HH:MM:SS | ||||
| 	%ptR[dt][r] | ||||
| 
 | ||||
| For printing date and time as represented by struct rtc_time structure in | ||||
| human readable format. | ||||
| 
 | ||||
| By default year will be incremented by 1900 and month by 1. Use %ptRr (raw) | ||||
| to suppress this behaviour. | ||||
| 
 | ||||
| Passed by reference. | ||||
| 
 | ||||
| struct clk | ||||
| ---------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include <linux/module.h> | ||||
| #include <linux/printk.h> | ||||
| #include <linux/random.h> | ||||
| #include <linux/rtc.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/string.h> | ||||
| 
 | ||||
|  | @ -249,12 +250,11 @@ plain_format(void) | |||
| #endif	/* BITS_PER_LONG == 64 */ | ||||
| 
 | ||||
| static int __init | ||||
| plain_hash(void) | ||||
| plain_hash_to_buffer(const void *p, char *buf, size_t len) | ||||
| { | ||||
| 	char buf[PLAIN_BUF_SIZE]; | ||||
| 	int nchars; | ||||
| 
 | ||||
| 	nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); | ||||
| 	nchars = snprintf(buf, len, "%p", p); | ||||
| 
 | ||||
| 	if (nchars != PTR_WIDTH) | ||||
| 		return -1; | ||||
|  | @ -265,6 +265,20 @@ plain_hash(void) | |||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int __init | ||||
| plain_hash(void) | ||||
| { | ||||
| 	char buf[PLAIN_BUF_SIZE]; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) | ||||
| 		return -1; | ||||
| 
 | ||||
|  | @ -294,6 +308,23 @@ plain(void) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void __init | ||||
| test_hashed(const char *fmt, const void *p) | ||||
| { | ||||
| 	char buf[PLAIN_BUF_SIZE]; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * No need to increase failed test counter since this is assumed | ||||
| 	 * to be called after plain(). | ||||
| 	 */ | ||||
| 	ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE); | ||||
| 	if (ret) | ||||
| 		return; | ||||
| 
 | ||||
| 	test(buf, fmt, p); | ||||
| } | ||||
| 
 | ||||
| static void __init | ||||
| symbol_ptr(void) | ||||
| { | ||||
|  | @ -418,6 +449,29 @@ struct_va_format(void) | |||
| { | ||||
| } | ||||
| 
 | ||||
| static void __init | ||||
| struct_rtc_time(void) | ||||
| { | ||||
| 	/* 1543210543 */ | ||||
| 	const struct rtc_time tm = { | ||||
| 		.tm_sec = 43, | ||||
| 		.tm_min = 35, | ||||
| 		.tm_hour = 5, | ||||
| 		.tm_mday = 26, | ||||
| 		.tm_mon = 10, | ||||
| 		.tm_year = 118, | ||||
| 	}; | ||||
| 
 | ||||
| 	test_hashed("%pt", &tm); | ||||
| 
 | ||||
| 	test("2018-11-26T05:35:43", "%ptR", &tm); | ||||
| 	test("0118-10-26T05:35:43", "%ptRr", &tm); | ||||
| 	test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm); | ||||
| 	test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm); | ||||
| 	test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm); | ||||
| 	test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm); | ||||
| } | ||||
| 
 | ||||
| static void __init | ||||
| struct_clk(void) | ||||
| { | ||||
|  | @ -529,6 +583,7 @@ test_pointer(void) | |||
| 	uuid(); | ||||
| 	dentry(); | ||||
| 	struct_va_format(); | ||||
| 	struct_rtc_time(); | ||||
| 	struct_clk(); | ||||
| 	bitmap(); | ||||
| 	netdev_features(); | ||||
|  |  | |||
							
								
								
									
										100
									
								
								lib/vsprintf.c
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								lib/vsprintf.c
									
									
									
									
									
								
							|  | @ -30,6 +30,7 @@ | |||
| #include <linux/ioport.h> | ||||
| #include <linux/dcache.h> | ||||
| #include <linux/cred.h> | ||||
| #include <linux/rtc.h> | ||||
| #include <linux/uuid.h> | ||||
| #include <linux/of.h> | ||||
| #include <net/addrconf.h> | ||||
|  | @ -822,6 +823,20 @@ static const struct printf_spec default_dec_spec = { | |||
| 	.precision = -1, | ||||
| }; | ||||
| 
 | ||||
| static const struct printf_spec default_dec02_spec = { | ||||
| 	.base = 10, | ||||
| 	.field_width = 2, | ||||
| 	.precision = -1, | ||||
| 	.flags = ZEROPAD, | ||||
| }; | ||||
| 
 | ||||
| static const struct printf_spec default_dec04_spec = { | ||||
| 	.base = 10, | ||||
| 	.field_width = 4, | ||||
| 	.precision = -1, | ||||
| 	.flags = ZEROPAD, | ||||
| }; | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *resource_string(char *buf, char *end, struct resource *res, | ||||
| 		      struct printf_spec spec, const char *fmt) | ||||
|  | @ -1549,6 +1564,87 @@ char *address_val(char *buf, char *end, const void *addr, const char *fmt) | |||
| 	return special_hex_number(buf, end, num, size); | ||||
| } | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r) | ||||
| { | ||||
| 	int year = tm->tm_year + (r ? 0 : 1900); | ||||
| 	int mon = tm->tm_mon + (r ? 0 : 1); | ||||
| 
 | ||||
| 	buf = number(buf, end, year, default_dec04_spec); | ||||
| 	if (buf < end) | ||||
| 		*buf = '-'; | ||||
| 	buf++; | ||||
| 
 | ||||
| 	buf = number(buf, end, mon, default_dec02_spec); | ||||
| 	if (buf < end) | ||||
| 		*buf = '-'; | ||||
| 	buf++; | ||||
| 
 | ||||
| 	return number(buf, end, tm->tm_mday, default_dec02_spec); | ||||
| } | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r) | ||||
| { | ||||
| 	buf = number(buf, end, tm->tm_hour, default_dec02_spec); | ||||
| 	if (buf < end) | ||||
| 		*buf = ':'; | ||||
| 	buf++; | ||||
| 
 | ||||
| 	buf = number(buf, end, tm->tm_min, default_dec02_spec); | ||||
| 	if (buf < end) | ||||
| 		*buf = ':'; | ||||
| 	buf++; | ||||
| 
 | ||||
| 	return number(buf, end, tm->tm_sec, default_dec02_spec); | ||||
| } | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *rtc_str(char *buf, char *end, const struct rtc_time *tm, const char *fmt) | ||||
| { | ||||
| 	bool have_t = true, have_d = true; | ||||
| 	bool raw = false; | ||||
| 	int count = 2; | ||||
| 
 | ||||
| 	switch (fmt[count]) { | ||||
| 	case 'd': | ||||
| 		have_t = false; | ||||
| 		count++; | ||||
| 		break; | ||||
| 	case 't': | ||||
| 		have_d = false; | ||||
| 		count++; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	raw = fmt[count] == 'r'; | ||||
| 
 | ||||
| 	if (have_d) | ||||
| 		buf = date_str(buf, end, tm, raw); | ||||
| 	if (have_d && have_t) { | ||||
| 		/* Respect ISO 8601 */ | ||||
| 		if (buf < end) | ||||
| 			*buf = 'T'; | ||||
| 		buf++; | ||||
| 	} | ||||
| 	if (have_t) | ||||
| 		buf = time_str(buf, end, tm, raw); | ||||
| 
 | ||||
| 	return buf; | ||||
| } | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, | ||||
| 		    const char *fmt) | ||||
| { | ||||
| 	switch (fmt[1]) { | ||||
| 	case 'R': | ||||
| 		return rtc_str(buf, end, (const struct rtc_time *)ptr, fmt); | ||||
| 	default: | ||||
| 		return ptr_to_id(buf, end, ptr, spec); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static noinline_for_stack | ||||
| char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, | ||||
| 	    const char *fmt) | ||||
|  | @ -1828,6 +1924,8 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, | |||
|  * - 'd[234]' For a dentry name (optionally 2-4 last components) | ||||
|  * - 'D[234]' Same as 'd' but for a struct file | ||||
|  * - 'g' For block_device name (gendisk + partition number) | ||||
|  * - 't[R][dt][r]' For time and date as represented: | ||||
|  *      R    struct rtc_time | ||||
|  * - 'C' For a clock, it prints the name (Common Clock Framework) or address | ||||
|  *       (legacy clock framework) of the clock | ||||
|  * - '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, | |||
| 		return address_val(buf, end, ptr, fmt); | ||||
| 	case 'd': | ||||
| 		return dentry_name(buf, end, ptr, spec, fmt); | ||||
| 	case 't': | ||||
| 		return time_and_date(buf, end, ptr, spec, fmt); | ||||
| 	case 'C': | ||||
| 		return clock(buf, end, ptr, spec, fmt); | ||||
| 	case 'D': | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Andy Shevchenko
						Andy Shevchenko