diff options
author | Ron Yorston <rmy@pobox.com> | 2021-09-17 11:36:53 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-09-17 11:38:52 +0100 |
commit | 46299d0c4f4c9a4bbad38bbbe26f196e1bccdc52 (patch) | |
tree | 6194cdabc0858ae3bed0276679b3b80a722f4150 | |
parent | cf91de46997888b7096352805c05401e7ebae01e (diff) | |
parent | 9fe1548bbfde548d54acaab113656a56ea0ccc72 (diff) | |
download | busybox-w32-46299d0c4f4c9a4bbad38bbbe26f196e1bccdc52.tar.gz busybox-w32-46299d0c4f4c9a4bbad38bbbe26f196e1bccdc52.tar.bz2 busybox-w32-46299d0c4f4c9a4bbad38bbbe26f196e1bccdc52.zip |
Merge branch 'busybox' into merge
Disable FEATURE_TIMEZONE for now.
-rw-r--r-- | configs/mingw32_defconfig | 1 | ||||
-rw-r--r-- | configs/mingw64_defconfig | 1 | ||||
-rw-r--r-- | coreutils/date.c | 7 | ||||
-rw-r--r-- | coreutils/df.c | 26 | ||||
-rw-r--r-- | coreutils/touch.c | 6 | ||||
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/Config.src | 11 | ||||
-rw-r--r-- | libbb/time.c | 78 | ||||
-rw-r--r-- | shell/ash.c | 58 | ||||
-rw-r--r-- | testsuite/date/date-timezone | 32 | ||||
-rw-r--r-- | util-linux/getopt.c | 64 |
11 files changed, 194 insertions, 92 deletions
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index 765653a43..0882741d5 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig | |||
@@ -147,6 +147,7 @@ CONFIG_FEATURE_COPYBUF_KB=4 | |||
147 | # CONFIG_MONOTONIC_SYSCALL is not set | 147 | # CONFIG_MONOTONIC_SYSCALL is not set |
148 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | 148 | # CONFIG_IOCTL_HEX2STR_ERROR is not set |
149 | # CONFIG_FEATURE_HWIB is not set | 149 | # CONFIG_FEATURE_HWIB is not set |
150 | # CONFIG_FEATURE_TIMEZONE is not set | ||
150 | 151 | ||
151 | # | 152 | # |
152 | # Applets | 153 | # Applets |
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 656ebb101..358d19d4e 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig | |||
@@ -147,6 +147,7 @@ CONFIG_FEATURE_COPYBUF_KB=4 | |||
147 | # CONFIG_MONOTONIC_SYSCALL is not set | 147 | # CONFIG_MONOTONIC_SYSCALL is not set |
148 | # CONFIG_IOCTL_HEX2STR_ERROR is not set | 148 | # CONFIG_IOCTL_HEX2STR_ERROR is not set |
149 | # CONFIG_FEATURE_HWIB is not set | 149 | # CONFIG_FEATURE_HWIB is not set |
150 | # CONFIG_FEATURE_TIMEZONE is not set | ||
150 | 151 | ||
151 | # | 152 | # |
152 | # Applets | 153 | # Applets |
diff --git a/coreutils/date.c b/coreutils/date.c index d64ff94b9..4e62a6fb0 100644 --- a/coreutils/date.c +++ b/coreutils/date.c | |||
@@ -291,6 +291,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
291 | 291 | ||
292 | /* If date string is given, update tm_time, and maybe set date */ | 292 | /* If date string is given, update tm_time, and maybe set date */ |
293 | if (date_str != NULL) { | 293 | if (date_str != NULL) { |
294 | int check_dst = 1; | ||
294 | /* Zero out fields - take her back to midnight! */ | 295 | /* Zero out fields - take her back to midnight! */ |
295 | tm_time.tm_sec = 0; | 296 | tm_time.tm_sec = 0; |
296 | tm_time.tm_min = 0; | 297 | tm_time.tm_min = 0; |
@@ -301,12 +302,12 @@ int date_main(int argc UNUSED_PARAM, char **argv) | |||
301 | if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) | 302 | if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) |
302 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | 303 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
303 | } else { | 304 | } else { |
304 | parse_datestr(date_str, &tm_time); | 305 | check_dst = parse_datestr(date_str, &tm_time); |
305 | } | 306 | } |
306 | 307 | ||
307 | /* Correct any day of week and day of year etc. fields */ | 308 | /* Correct any day of week and day of year etc. fields */ |
308 | /* Be sure to recheck dst (but not if date is time_t format) */ | 309 | /* Be sure to recheck dst (but not if date is UTC) */ |
309 | if (date_str[0] != '@') | 310 | if (check_dst) |
310 | tm_time.tm_isdst = -1; | 311 | tm_time.tm_isdst = -1; |
311 | ts.tv_sec = validate_tm_time(date_str, &tm_time); | 312 | ts.tv_sec = validate_tm_time(date_str, &tm_time); |
312 | ts.tv_nsec = 0; | 313 | ts.tv_nsec = 0; |
diff --git a/coreutils/df.c b/coreutils/df.c index e8d4bc8f2..9f8b3a71e 100644 --- a/coreutils/df.c +++ b/coreutils/df.c | |||
@@ -99,15 +99,16 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
99 | struct mntent *mount_entry; | 99 | struct mntent *mount_entry; |
100 | struct statvfs s; | 100 | struct statvfs s; |
101 | enum { | 101 | enum { |
102 | OPT_KILO = (1 << 0), | 102 | OPT_KILO = (1 << 0), |
103 | OPT_POSIX = (1 << 1), | 103 | OPT_POSIX = (1 << 1), |
104 | OPT_FSTYPE = (1 << 2), | 104 | OPT_FSTYPE = (1 << 2), |
105 | OPT_t = (1 << 3), | 105 | OPT_t = (1 << 3), |
106 | OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, | 106 | OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, |
107 | OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, | 107 | OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, |
108 | OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, | 108 | OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, |
109 | OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 109 | OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, |
110 | OPT_MEGA = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | 110 | OPT_HUMANDEC = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, |
111 | OPT_MEGA = (1 << (6 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, | ||
111 | }; | 112 | }; |
112 | const char *disp_units_hdr = NULL; | 113 | const char *disp_units_hdr = NULL; |
113 | char *chp, *opt_t; | 114 | char *chp, *opt_t; |
@@ -124,7 +125,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
124 | opt = getopt32(argv, "^" | 125 | opt = getopt32(argv, "^" |
125 | "kPTt:" | 126 | "kPTt:" |
126 | IF_FEATURE_DF_FANCY("aiB:") | 127 | IF_FEATURE_DF_FANCY("aiB:") |
127 | IF_FEATURE_HUMAN_READABLE("hm") | 128 | IF_FEATURE_HUMAN_READABLE("hHm") |
128 | "\0" | 129 | "\0" |
129 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY | 130 | #if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY |
130 | "k-mB:m-Bk:B-km" | 131 | "k-mB:m-Bk:B-km" |
@@ -151,8 +152,11 @@ int df_main(int argc UNUSED_PARAM, char **argv) | |||
151 | got_it: ; | 152 | got_it: ; |
152 | } | 153 | } |
153 | 154 | ||
154 | if (opt & OPT_HUMAN) { | 155 | if (opt & (OPT_HUMAN|OPT_HUMANDEC)) { |
155 | df_disp_hr = 0; | 156 | df_disp_hr = 0; |
157 | //TODO: need to add support in make_human_readable_str() for "decimal human readable" | ||
158 | //if (opt & OPT_HUMANDEC) | ||
159 | // df_disp_hr--; | ||
156 | disp_units_hdr = " Size"; | 160 | disp_units_hdr = " Size"; |
157 | } | 161 | } |
158 | if (opt & OPT_INODE) | 162 | if (opt & OPT_INODE) |
diff --git a/coreutils/touch.c b/coreutils/touch.c index 78100ba1d..7e13a27be 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c | |||
@@ -140,15 +140,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv) | |||
140 | if (opts & (OPT_d|OPT_t)) { | 140 | if (opts & (OPT_d|OPT_t)) { |
141 | struct tm tm_time; | 141 | struct tm tm_time; |
142 | time_t t; | 142 | time_t t; |
143 | int check_dst; | ||
143 | 144 | ||
144 | //memset(&tm_time, 0, sizeof(tm_time)); | 145 | //memset(&tm_time, 0, sizeof(tm_time)); |
145 | /* Better than memset: makes "HH:MM" dates meaningful */ | 146 | /* Better than memset: makes "HH:MM" dates meaningful */ |
146 | time(&t); | 147 | time(&t); |
147 | localtime_r(&t, &tm_time); | 148 | localtime_r(&t, &tm_time); |
148 | parse_datestr(date_str, &tm_time); | 149 | check_dst = parse_datestr(date_str, &tm_time); |
149 | 150 | ||
150 | /* Correct any day of week and day of year etc. fields */ | 151 | /* Correct any day of week and day of year etc. fields */ |
151 | tm_time.tm_isdst = -1; /* Be sure to recheck dst */ | 152 | if (check_dst) |
153 | tm_time.tm_isdst = -1; /* recheck dst unless date is UTC */ | ||
152 | t = validate_tm_time(date_str, &tm_time); | 154 | t = validate_tm_time(date_str, &tm_time); |
153 | 155 | ||
154 | timebuf[1].tv_sec = timebuf[0].tv_sec = t; | 156 | timebuf[1].tv_sec = timebuf[0].tv_sec = t; |
diff --git a/include/libbb.h b/include/libbb.h index 7a43967cb..cee37f9d8 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -730,7 +730,7 @@ struct BUG_too_small { | |||
730 | }; | 730 | }; |
731 | 731 | ||
732 | 732 | ||
733 | void parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC; | 733 | int parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC; |
734 | time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC; | 734 | time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC; |
735 | char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; | 735 | char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; |
736 | char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; | 736 | char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; |
diff --git a/libbb/Config.src b/libbb/Config.src index f97de8ef7..58c5fad50 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
@@ -395,3 +395,14 @@ config FEATURE_HWIB | |||
395 | default y | 395 | default y |
396 | help | 396 | help |
397 | Support for printing infiniband addresses in network applets. | 397 | Support for printing infiniband addresses in network applets. |
398 | |||
399 | config FEATURE_TIMEZONE | ||
400 | bool "Allow timezone in dates" | ||
401 | default y | ||
402 | depends on DESKTOP | ||
403 | help | ||
404 | Permit the use of timezones when parsing user-provided data | ||
405 | strings, e.g. '1996-04-09 12:45:00 -0500'. | ||
406 | |||
407 | This requires support for the '%z' extension to strptime() which | ||
408 | may not be available in all implementations. | ||
diff --git a/libbb/time.c b/libbb/time.c index cf5f2e5c8..41a69c754 100644 --- a/libbb/time.c +++ b/libbb/time.c | |||
@@ -8,16 +8,74 @@ | |||
8 | */ | 8 | */ |
9 | #include "libbb.h" | 9 | #include "libbb.h" |
10 | 10 | ||
11 | void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | 11 | /* Returns 0 if the time structure contains an absolute UTC time which |
12 | * should not be subject to DST adjustment by the caller. */ | ||
13 | int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | ||
12 | { | 14 | { |
13 | char end = '\0'; | 15 | char end = '\0'; |
16 | #if ENABLE_DESKTOP | ||
17 | /* | ||
18 | * strptime is BIG: ~1k in uclibc, ~10k in glibc | ||
19 | * We need it for 'month_name d HH:MM:SS YYYY', supported by GNU date, | ||
20 | * but if we've linked it we might as well use it for everything. | ||
21 | */ | ||
22 | static const char fmt_str[] ALIGN1 = | ||
23 | "%R" "\0" /* HH:MM */ | ||
24 | "%T" "\0" /* HH:MM:SS */ | ||
25 | "%m.%d-%R" "\0" /* mm.dd-HH:MM */ | ||
26 | "%m.%d-%T" "\0" /* mm.dd-HH:MM:SS */ | ||
27 | "%Y.%m.%d-%R" "\0" /* yyyy.mm.dd-HH:MM */ | ||
28 | "%Y.%m.%d-%T" "\0" /* yyyy.mm.dd-HH:MM:SS */ | ||
29 | "%b %d %T %Y" "\0" /* month_name d HH:MM:SS YYYY */ | ||
30 | "%Y-%m-%d %R" "\0" /* yyyy-mm-dd HH:MM */ | ||
31 | "%Y-%m-%d %T" "\0" /* yyyy-mm-dd HH:MM:SS */ | ||
32 | #if ENABLE_FEATURE_TIMEZONE | ||
33 | "%Y-%m-%d %R %z" "\0" /* yyyy-mm-dd HH:MM TZ */ | ||
34 | "%Y-%m-%d %T %z" "\0" /* yyyy-mm-dd HH:MM:SS TZ */ | ||
35 | #endif | ||
36 | "%Y-%m-%d %H" "\0" /* yyyy-mm-dd HH */ | ||
37 | "%Y-%m-%d" "\0" /* yyyy-mm-dd */ | ||
38 | /* extra NUL */; | ||
39 | struct tm save; | ||
40 | const char *fmt; | ||
41 | char *endp; | ||
42 | |||
43 | save = *ptm; | ||
44 | fmt = fmt_str; | ||
45 | while (*fmt) { | ||
46 | endp = strptime(date_str, fmt, ptm); | ||
47 | if (endp && *endp == '\0') { | ||
48 | #if ENABLE_FEATURE_TIMEZONE | ||
49 | if (strchr(fmt, 'z')) { | ||
50 | time_t t; | ||
51 | struct tm *utm; | ||
52 | |||
53 | /* we have timezone offset: obtain Unix time_t */ | ||
54 | ptm->tm_sec -= ptm->tm_gmtoff; | ||
55 | ptm->tm_isdst = 0; | ||
56 | t = timegm(ptm); | ||
57 | if (t == (time_t)-1) | ||
58 | break; | ||
59 | /* convert Unix time_t to struct tm in user's locale */ | ||
60 | utm = localtime(&t); | ||
61 | if (!utm) | ||
62 | break; | ||
63 | *ptm = *utm; | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | return 1; | ||
68 | } | ||
69 | *ptm = save; | ||
70 | while (*++fmt) | ||
71 | continue; | ||
72 | ++fmt; | ||
73 | } | ||
74 | #else | ||
14 | const char *last_colon = strrchr(date_str, ':'); | 75 | const char *last_colon = strrchr(date_str, ':'); |
15 | 76 | ||
16 | if (last_colon != NULL) { | 77 | if (last_colon != NULL) { |
17 | /* Parse input and assign appropriately to ptm */ | 78 | /* Parse input and assign appropriately to ptm */ |
18 | #if ENABLE_DESKTOP | ||
19 | const char *endp; | ||
20 | #endif | ||
21 | 79 | ||
22 | /* HH:MM */ | 80 | /* HH:MM */ |
23 | if (sscanf(date_str, "%u:%u%c", | 81 | if (sscanf(date_str, "%u:%u%c", |
@@ -50,14 +108,6 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
50 | ptm->tm_year -= 1900; /* Adjust years */ | 108 | ptm->tm_year -= 1900; /* Adjust years */ |
51 | ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ | 109 | ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ |
52 | } else | 110 | } else |
53 | #if ENABLE_DESKTOP /* strptime is BIG: ~1k in uclibc, ~10k in glibc */ | ||
54 | /* month_name d HH:MM:SS YYYY. Supported by GNU date */ | ||
55 | if ((endp = strptime(date_str, "%b %d %T %Y", ptm)) != NULL | ||
56 | && *endp == '\0' | ||
57 | ) { | ||
58 | return; /* don't fall through to end == ":" check */ | ||
59 | } else | ||
60 | #endif | ||
61 | { | 111 | { |
62 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | 112 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
63 | } | 113 | } |
@@ -89,6 +139,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
89 | ptm->tm_year -= 1900; /* Adjust years */ | 139 | ptm->tm_year -= 1900; /* Adjust years */ |
90 | ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ | 140 | ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ |
91 | } else | 141 | } else |
142 | #endif /* ENABLE_DESKTOP */ | ||
92 | if (date_str[0] == '@') { | 143 | if (date_str[0] == '@') { |
93 | time_t t; | 144 | time_t t; |
94 | if (sizeof(t) <= sizeof(long)) | 145 | if (sizeof(t) <= sizeof(long)) |
@@ -99,7 +150,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
99 | struct tm *lt = localtime(&t); | 150 | struct tm *lt = localtime(&t); |
100 | if (lt) { | 151 | if (lt) { |
101 | *ptm = *lt; | 152 | *ptm = *lt; |
102 | return; | 153 | return 0; |
103 | } | 154 | } |
104 | } | 155 | } |
105 | end = '1'; | 156 | end = '1'; |
@@ -216,6 +267,7 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
216 | if (end != '\0') { | 267 | if (end != '\0') { |
217 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); | 268 | bb_error_msg_and_die(bb_msg_invalid_date, date_str); |
218 | } | 269 | } |
270 | return 1; | ||
219 | } | 271 | } |
220 | 272 | ||
221 | time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm) | 273 | time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm) |
diff --git a/shell/ash.c b/shell/ash.c index 7544204d1..5adb95bc5 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -2355,6 +2355,7 @@ static const struct { | |||
2355 | { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, | 2355 | { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset }, |
2356 | #endif | 2356 | #endif |
2357 | { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL }, | 2357 | { VSTRFIXED|VTEXTFIXED , NULL /* inited to linenovar */, NULL }, |
2358 | { VSTRFIXED|VTEXTFIXED , NULL /* inited to funcnamevar */, NULL }, | ||
2358 | #if ENABLE_ASH_RANDOM_SUPPORT | 2359 | #if ENABLE_ASH_RANDOM_SUPPORT |
2359 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, | 2360 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random }, |
2360 | #endif | 2361 | #endif |
@@ -2384,6 +2385,8 @@ struct globals_var { | |||
2384 | struct var varinit[ARRAY_SIZE(varinit_data)]; | 2385 | struct var varinit[ARRAY_SIZE(varinit_data)]; |
2385 | int lineno; | 2386 | int lineno; |
2386 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; | 2387 | char linenovar[sizeof("LINENO=") + sizeof(int)*3]; |
2388 | char funcnamevar[sizeof("FUNCNAME=") + 64]; | ||
2389 | char *funcname; | ||
2387 | unsigned trap_depth; | 2390 | unsigned trap_depth; |
2388 | bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */ | 2391 | bool in_trap_ERR; /* ERR cannot recurse, no need to be a counter */ |
2389 | }; | 2392 | }; |
@@ -2396,6 +2399,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2396 | #define varinit (G_var.varinit ) | 2399 | #define varinit (G_var.varinit ) |
2397 | #define lineno (G_var.lineno ) | 2400 | #define lineno (G_var.lineno ) |
2398 | #define linenovar (G_var.linenovar ) | 2401 | #define linenovar (G_var.linenovar ) |
2402 | #define funcnamevar (G_var.funcnamevar ) | ||
2403 | #define funcname (G_var.funcname ) | ||
2399 | #define trap_depth (G_var.trap_depth ) | 2404 | #define trap_depth (G_var.trap_depth ) |
2400 | #define in_trap_ERR (G_var.in_trap_ERR ) | 2405 | #define in_trap_ERR (G_var.in_trap_ERR ) |
2401 | #define vifs varinit[0] | 2406 | #define vifs varinit[0] |
@@ -2413,13 +2418,14 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2413 | #endif | 2418 | #endif |
2414 | #define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS) | 2419 | #define VAR_OFFSET2 (VAR_OFFSET1 + ENABLE_ASH_GETOPTS) |
2415 | #define vlineno varinit[VAR_OFFSET2 + 5] | 2420 | #define vlineno varinit[VAR_OFFSET2 + 5] |
2421 | #define vfuncname varinit[VAR_OFFSET2 + 6] | ||
2416 | #if ENABLE_ASH_RANDOM_SUPPORT | 2422 | #if ENABLE_ASH_RANDOM_SUPPORT |
2417 | # define vrandom varinit[VAR_OFFSET2 + 6] | 2423 | # define vrandom varinit[VAR_OFFSET2 + 7] |
2418 | #endif | 2424 | #endif |
2419 | #define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT) | 2425 | #define VAR_OFFSET3 (VAR_OFFSET2 + ENABLE_ASH_RANDOM_SUPPORT) |
2420 | #if BASH_EPOCH_VARS | 2426 | #if BASH_EPOCH_VARS |
2421 | # define vepochs varinit[VAR_OFFSET3 + 6] | 2427 | # define vepochs varinit[VAR_OFFSET3 + 7] |
2422 | # define vepochr varinit[VAR_OFFSET3 + 7] | 2428 | # define vepochr varinit[VAR_OFFSET3 + 8] |
2423 | #endif | 2429 | #endif |
2424 | #define INIT_G_var() do { \ | 2430 | #define INIT_G_var() do { \ |
2425 | unsigned i; \ | 2431 | unsigned i; \ |
@@ -2432,6 +2438,8 @@ extern struct globals_var *BB_GLOBAL_CONST ash_ptr_to_globals_var; | |||
2432 | } \ | 2438 | } \ |
2433 | strcpy(linenovar, "LINENO="); \ | 2439 | strcpy(linenovar, "LINENO="); \ |
2434 | vlineno.var_text = linenovar; \ | 2440 | vlineno.var_text = linenovar; \ |
2441 | strcpy(funcnamevar, "FUNCNAME="); \ | ||
2442 | vfuncname.var_text = funcnamevar; \ | ||
2435 | } while (0) | 2443 | } while (0) |
2436 | 2444 | ||
2437 | /* | 2445 | /* |
@@ -2571,6 +2579,9 @@ lookupvar(const char *name) | |||
2571 | if (!(v->flags & VUNSET)) { | 2579 | if (!(v->flags & VUNSET)) { |
2572 | if (v->var_text == linenovar) { | 2580 | if (v->var_text == linenovar) { |
2573 | fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); | 2581 | fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); |
2582 | } else | ||
2583 | if (v->var_text == funcnamevar) { | ||
2584 | safe_strncpy(funcnamevar+9, funcname ? funcname : "", sizeof(funcnamevar)-9); | ||
2574 | } | 2585 | } |
2575 | return var_end(v->var_text); | 2586 | return var_end(v->var_text); |
2576 | } | 2587 | } |
@@ -6015,7 +6026,7 @@ stoppedjobs(void) | |||
6015 | int retval; | 6026 | int retval; |
6016 | 6027 | ||
6017 | retval = 0; | 6028 | retval = 0; |
6018 | if (job_warning) | 6029 | if (!iflag || job_warning) |
6019 | goto out; | 6030 | goto out; |
6020 | jp = curjob; | 6031 | jp = curjob; |
6021 | if (jp && jp->state == JOBSTOPPED) { | 6032 | if (jp && jp->state == JOBSTOPPED) { |
@@ -10654,6 +10665,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10654 | int e; | 10665 | int e; |
10655 | int savelineno; | 10666 | int savelineno; |
10656 | int savefuncline; | 10667 | int savefuncline; |
10668 | char *savefuncname; | ||
10657 | char *savetrap = NULL; | 10669 | char *savetrap = NULL; |
10658 | 10670 | ||
10659 | if (!Eflag) { | 10671 | if (!Eflag) { |
@@ -10663,6 +10675,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10663 | savelineno = lineno; | 10675 | savelineno = lineno; |
10664 | saveparam = shellparam; | 10676 | saveparam = shellparam; |
10665 | savefuncline = funcline; | 10677 | savefuncline = funcline; |
10678 | savefuncname = funcname; | ||
10666 | savehandler = exception_handler; | 10679 | savehandler = exception_handler; |
10667 | e = setjmp(jmploc.loc); | 10680 | e = setjmp(jmploc.loc); |
10668 | if (e) { | 10681 | if (e) { |
@@ -10672,6 +10685,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10672 | exception_handler = &jmploc; | 10685 | exception_handler = &jmploc; |
10673 | shellparam.malloced = 0; | 10686 | shellparam.malloced = 0; |
10674 | func->count++; | 10687 | func->count++; |
10688 | funcname = func->n.ndefun.text; | ||
10675 | funcline = func->n.ndefun.linno; | 10689 | funcline = func->n.ndefun.linno; |
10676 | INT_ON; | 10690 | INT_ON; |
10677 | shellparam.nparam = argc - 1; | 10691 | shellparam.nparam = argc - 1; |
@@ -10683,6 +10697,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
10683 | evaltree(func->n.ndefun.body, flags & EV_TESTED); | 10697 | evaltree(func->n.ndefun.body, flags & EV_TESTED); |
10684 | funcdone: | 10698 | funcdone: |
10685 | INT_OFF; | 10699 | INT_OFF; |
10700 | funcname = savefuncname; | ||
10686 | if (savetrap) { | 10701 | if (savetrap) { |
10687 | if (!trap[NTRAP_ERR]) | 10702 | if (!trap[NTRAP_ERR]) |
10688 | trap[NTRAP_ERR] = savetrap; | 10703 | trap[NTRAP_ERR] = savetrap; |
@@ -11650,9 +11665,7 @@ preadfd(void) | |||
11650 | * Refill the input buffer and return the next input character: | 11665 | * Refill the input buffer and return the next input character: |
11651 | * | 11666 | * |
11652 | * 1) If a string was pushed back on the input, pop it; | 11667 | * 1) If a string was pushed back on the input, pop it; |
11653 | * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM) | 11668 | * 2) If we are reading from a string we can't refill the buffer, return EOF. |
11654 | * or we are reading from a string so we can't refill the buffer, | ||
11655 | * return EOF. | ||
11656 | * 3) If there is more stuff in this buffer, use it else call read to fill it. | 11669 | * 3) If there is more stuff in this buffer, use it else call read to fill it. |
11657 | * 4) Process input up to the next newline, deleting nul characters. | 11670 | * 4) Process input up to the next newline, deleting nul characters. |
11658 | */ | 11671 | */ |
@@ -11669,21 +11682,9 @@ preadbuffer(void) | |||
11669 | popstring(); | 11682 | popstring(); |
11670 | return __pgetc(); | 11683 | return __pgetc(); |
11671 | } | 11684 | } |
11672 | /* on both branches above g_parsefile->left_in_line < 0. | ||
11673 | * "pgetc" needs refilling. | ||
11674 | */ | ||
11675 | 11685 | ||
11676 | /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read", | 11686 | if (g_parsefile->buf == NULL) { |
11677 | * pungetc() may increment it a few times. | ||
11678 | * Assuming it won't increment it to less than -90. | ||
11679 | */ | ||
11680 | if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) { | ||
11681 | pgetc_debug("preadbuffer PEOF1"); | 11687 | pgetc_debug("preadbuffer PEOF1"); |
11682 | /* even in failure keep left_in_line and next_to_pgetc | ||
11683 | * in lock step, for correct multi-layer pungetc. | ||
11684 | * left_in_line was decremented before preadbuffer(), | ||
11685 | * must inc next_to_pgetc: */ | ||
11686 | g_parsefile->next_to_pgetc++; | ||
11687 | return PEOF; | 11688 | return PEOF; |
11688 | } | 11689 | } |
11689 | 11690 | ||
@@ -11693,10 +11694,8 @@ preadbuffer(void) | |||
11693 | again: | 11694 | again: |
11694 | more = preadfd(); | 11695 | more = preadfd(); |
11695 | if (more <= 0) { | 11696 | if (more <= 0) { |
11696 | /* don't try reading again */ | 11697 | g_parsefile->left_in_buffer = g_parsefile->left_in_line = 0; |
11697 | g_parsefile->left_in_line = -99; | ||
11698 | pgetc_debug("preadbuffer PEOF2"); | 11698 | pgetc_debug("preadbuffer PEOF2"); |
11699 | g_parsefile->next_to_pgetc++; | ||
11700 | return PEOF; | 11699 | return PEOF; |
11701 | } | 11700 | } |
11702 | } | 11701 | } |
@@ -14376,12 +14375,13 @@ cmdloop(int top) | |||
14376 | if (!top || numeof >= 50) | 14375 | if (!top || numeof >= 50) |
14377 | break; | 14376 | break; |
14378 | if (!stoppedjobs()) { | 14377 | if (!stoppedjobs()) { |
14378 | if (!iflag) | ||
14379 | break; | ||
14379 | if (!Iflag) { | 14380 | if (!Iflag) { |
14380 | if (iflag) { | 14381 | newline_and_flush(stderr); |
14381 | newline_and_flush(stderr); | ||
14382 | } | ||
14383 | break; | 14382 | break; |
14384 | } | 14383 | } |
14384 | /* "set -o ignoreeof" active, do not exit command loop on ^D */ | ||
14385 | out2str("\nUse \"exit\" to leave shell.\n"); | 14385 | out2str("\nUse \"exit\" to leave shell.\n"); |
14386 | } | 14386 | } |
14387 | numeof++; | 14387 | numeof++; |
@@ -14508,6 +14508,12 @@ exitcmd(int argc UNUSED_PARAM, char **argv) | |||
14508 | if (argv[1]) | 14508 | if (argv[1]) |
14509 | savestatus = number(argv[1]); | 14509 | savestatus = number(argv[1]); |
14510 | 14510 | ||
14511 | //TODO: this script | ||
14512 | // trap 'echo trap:$FUNCNAME' EXIT | ||
14513 | // f() { exit; } | ||
14514 | // f | ||
14515 | //prints "trap:f" in bash. We can call exitshell() here to achieve this. | ||
14516 | //For now, keeping dash code: | ||
14511 | raise_exception(EXEXIT); | 14517 | raise_exception(EXEXIT); |
14512 | /* NOTREACHED */ | 14518 | /* NOTREACHED */ |
14513 | } | 14519 | } |
diff --git a/testsuite/date/date-timezone b/testsuite/date/date-timezone new file mode 100644 index 000000000..8628aa1d7 --- /dev/null +++ b/testsuite/date/date-timezone | |||
@@ -0,0 +1,32 @@ | |||
1 | # FEATURE: CONFIG_FEATURE_TIMEZONE | ||
2 | |||
3 | # 'Z' is UTC | ||
4 | dt=$(TZ=UTC0 busybox date -d '1999-1-2 3:4:5Z') | ||
5 | dt=$(echo "$dt" | cut -b1-19) | ||
6 | test x"$dt" = x"Sat Jan 2 03:04:05" | ||
7 | |||
8 | # '+0600' is six hours ahead of UTC | ||
9 | dt=$(TZ=UTC0 busybox date -d '1999-1-2 3:4:5 +0600') | ||
10 | dt=$(echo "$dt" | cut -b1-19) | ||
11 | test x"$dt" = x"Fri Jan 1 21:04:05" | ||
12 | |||
13 | # '-0600' is six hours behind UTC | ||
14 | dt=$(TZ=UTC0 busybox date -d '1999-1-2 3:4:5 -0600') | ||
15 | dt=$(echo "$dt" | cut -b1-19) | ||
16 | test x"$dt" = x"Sat Jan 2 09:04:05" | ||
17 | |||
18 | # before dst is switched on | ||
19 | dt=$(TZ=GMT0BST,M3.5.0/1,M10.5.0/2 busybox date -d '2021-03-28 00:59:59 +0000') | ||
20 | test x"$dt" = x"Sun Mar 28 00:59:59 GMT 2021" | ||
21 | |||
22 | # after dst is switched on | ||
23 | dt=$(TZ=GMT0BST,M3.5.0/1,M10.5.0/2 busybox date -d '2021-03-28 01:00:01 +0000') | ||
24 | test x"$dt" = x"Sun Mar 28 02:00:01 BST 2021" | ||
25 | |||
26 | # before dst is switched off | ||
27 | dt=$(TZ=GMT0BST,M3.5.0/1,M10.5.0/2 busybox date -d '2021-10-31 00:00:01 +0000') | ||
28 | test x"$dt" = x"Sun Oct 31 01:00:01 BST 2021" | ||
29 | |||
30 | # after dst is switched off: back to 01:00:01 but with different TZ | ||
31 | dt=$(TZ=GMT0BST,M3.5.0/1,M10.5.0/2 busybox date -d '2021-10-31 01:00:01 +0000') | ||
32 | test x"$dt" = x"Sun Oct 31 01:00:01 GMT 2021" | ||
diff --git a/util-linux/getopt.c b/util-linux/getopt.c index 1fa402429..4148586d3 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c | |||
@@ -156,57 +156,43 @@ enum { | |||
156 | static const char *normalize(const char *arg) | 156 | static const char *normalize(const char *arg) |
157 | { | 157 | { |
158 | char *bufptr; | 158 | char *bufptr; |
159 | #if ENABLE_FEATURE_CLEAN_UP | ||
160 | static char *BUFFER = NULL; | ||
161 | free(BUFFER); | ||
162 | #else | ||
163 | char *BUFFER; | 159 | char *BUFFER; |
164 | #endif | ||
165 | 160 | ||
166 | if (!quote) { /* Just copy arg */ | 161 | if (!quote) { /* Just return arg */ |
167 | BUFFER = xstrdup(arg); | 162 | return arg; |
168 | return BUFFER; | ||
169 | } | 163 | } |
170 | 164 | ||
171 | /* Each character in arg may take up to four characters in the result: | 165 | /* Each character in arg may take up to four characters in the result: |
172 | For a quote we need a closing quote, a backslash, a quote and an | 166 | For a quote we need a closing quote, a backslash, a quote and an |
173 | opening quote! We need also the global opening and closing quote, | 167 | opening quote! We need also the global opening and closing quote, |
174 | and one extra character for '\0'. */ | 168 | and one extra character for '\0'. */ |
175 | BUFFER = xmalloc(strlen(arg)*4 + 3); | 169 | BUFFER = auto_string(xmalloc(strlen(arg)*4 + 3)); |
176 | 170 | ||
177 | bufptr = BUFFER; | 171 | bufptr = BUFFER; |
178 | *bufptr ++= '\''; | 172 | *bufptr ++= '\''; |
179 | 173 | ||
180 | while (*arg) { | 174 | while (*arg) { |
181 | if (*arg == '\'') { | 175 | if (shell_TCSH && *arg == '\n') { |
182 | /* Quote: replace it with: '\'' */ | ||
183 | *bufptr ++= '\''; | ||
184 | *bufptr ++= '\\'; | ||
185 | *bufptr ++= '\''; | ||
186 | *bufptr ++= '\''; | ||
187 | } else if (shell_TCSH && *arg == '!') { | ||
188 | /* Exclamation mark: replace it with: \! */ | ||
189 | *bufptr ++= '\''; | ||
190 | *bufptr ++= '\\'; | ||
191 | *bufptr ++= '!'; | ||
192 | *bufptr ++= '\''; | ||
193 | } else if (shell_TCSH && *arg == '\n') { | ||
194 | /* Newline: replace it with: \n */ | 176 | /* Newline: replace it with: \n */ |
195 | *bufptr ++= '\\'; | 177 | *bufptr++ = '\\'; |
196 | *bufptr ++= 'n'; | 178 | *bufptr++ = 'n'; |
197 | } else if (shell_TCSH && isspace(*arg)) { | ||
198 | /* Non-newline whitespace: replace it with \<ws> */ | ||
199 | *bufptr ++= '\''; | ||
200 | *bufptr ++= '\\'; | ||
201 | *bufptr ++= *arg; | ||
202 | *bufptr ++= '\''; | ||
203 | } else | 179 | } else |
180 | if ((shell_TCSH && (*arg == '!' || isspace(*arg))) | ||
181 | || *arg == '\'' | ||
182 | ) { | ||
183 | /* Quote exclamation marks, non-NL whitespace and quotes */ | ||
184 | *bufptr++ = '\''; | ||
185 | *bufptr++ = '\\'; | ||
186 | *bufptr++ = *arg; | ||
187 | *bufptr++ = '\''; | ||
188 | } else { | ||
204 | /* Just copy */ | 189 | /* Just copy */ |
205 | *bufptr ++= *arg; | 190 | *bufptr ++= *arg; |
191 | } | ||
206 | arg++; | 192 | arg++; |
207 | } | 193 | } |
208 | *bufptr ++= '\''; | 194 | *bufptr++ = '\''; |
209 | *bufptr ++= '\0'; | 195 | *bufptr++ = '\0'; |
210 | return BUFFER; | 196 | return BUFFER; |
211 | } | 197 | } |
212 | 198 | ||
@@ -327,12 +313,18 @@ static struct option *add_long_options(struct option *long_options, char *option | |||
327 | 313 | ||
328 | static void set_shell(const char *new_shell) | 314 | static void set_shell(const char *new_shell) |
329 | { | 315 | { |
330 | if (strcmp(new_shell, "bash") == 0 || strcmp(new_shell, "sh") == 0) | 316 | switch (index_in_strings("bash\0sh\0tcsh\0csh\0", new_shell)) { |
331 | return; | 317 | case 0: |
332 | if (strcmp(new_shell, "tcsh") == 0 || strcmp(new_shell, "csh") == 0) | 318 | case 1: |
319 | break; | ||
320 | case 2: | ||
321 | case 3: | ||
333 | option_mask32 |= SHELL_IS_TCSH; | 322 | option_mask32 |= SHELL_IS_TCSH; |
334 | else | 323 | break; |
324 | default: | ||
335 | bb_error_msg("unknown shell '%s', assuming bash", new_shell); | 325 | bb_error_msg("unknown shell '%s', assuming bash", new_shell); |
326 | break; | ||
327 | } | ||
336 | } | 328 | } |
337 | 329 | ||
338 | 330 | ||