diff options
author | Ron Yorston <rmy@pobox.com> | 2021-09-21 15:19:18 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-09-21 15:19:18 +0100 |
commit | 90b3ba992ecb39e32e5a66b2e37579becc56d286 (patch) | |
tree | 4c4a2c9e1baeb8230d78efd058bb4bcabc3fd12b | |
parent | df34f5e92b1d10f0bb858d2ea6e8c249e87ac593 (diff) | |
parent | 56f0e886db0543a27f369d7f95eb9da2fb3d069c (diff) | |
download | busybox-w32-90b3ba992ecb39e32e5a66b2e37579becc56d286.tar.gz busybox-w32-90b3ba992ecb39e32e5a66b2e37579becc56d286.tar.bz2 busybox-w32-90b3ba992ecb39e32e5a66b2e37579becc56d286.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | archival/ar.c | 3 | ||||
-rw-r--r-- | archival/libarchive/header_verbose_list.c | 5 | ||||
-rw-r--r-- | coreutils/chmod.c | 6 | ||||
-rw-r--r-- | coreutils/ls.c | 3 | ||||
-rw-r--r-- | coreutils/stat.c | 6 | ||||
-rw-r--r-- | include/libbb.h | 7 | ||||
-rw-r--r-- | libbb/lineedit.c | 11 | ||||
-rw-r--r-- | libbb/mode_string.c | 34 | ||||
-rw-r--r-- | libbb/parse_mode.c | 5 | ||||
-rw-r--r-- | libbb/time.c | 23 | ||||
-rw-r--r-- | util-linux/cal.c | 38 |
11 files changed, 77 insertions, 64 deletions
diff --git a/archival/ar.c b/archival/ar.c index 1879ec79f..beccab217 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
@@ -213,9 +213,10 @@ static int write_ar_archive(archive_handle_t *handle) | |||
213 | 213 | ||
214 | static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header) | 214 | static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header) |
215 | { | 215 | { |
216 | const char *mode = bb_mode_string(file_header->mode); | 216 | char mode[12]; |
217 | char *mtime; | 217 | char *mtime; |
218 | 218 | ||
219 | bb_mode_string(mode, file_header->mode); | ||
219 | mtime = ctime(&file_header->mtime); | 220 | mtime = ctime(&file_header->mtime); |
220 | mtime[16] = ' '; | 221 | mtime[16] = ' '; |
221 | memmove(&mtime[17], &mtime[20], 4); | 222 | memmove(&mtime[17], &mtime[20], 4); |
diff --git a/archival/libarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c index be5140f8b..a575a08a0 100644 --- a/archival/libarchive/header_verbose_list.c +++ b/archival/libarchive/header_verbose_list.c | |||
@@ -9,6 +9,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) | |||
9 | { | 9 | { |
10 | struct tm tm_time; | 10 | struct tm tm_time; |
11 | struct tm *ptm = &tm_time; //localtime(&file_header->mtime); | 11 | struct tm *ptm = &tm_time; //localtime(&file_header->mtime); |
12 | char modestr[12]; | ||
12 | 13 | ||
13 | #if ENABLE_FEATURE_TAR_UNAME_GNAME | 14 | #if ENABLE_FEATURE_TAR_UNAME_GNAME |
14 | char uid[sizeof(int)*3 + 2]; | 15 | char uid[sizeof(int)*3 + 2]; |
@@ -29,7 +30,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) | |||
29 | group = utoa(file_header->gid); | 30 | group = utoa(file_header->gid); |
30 | } | 31 | } |
31 | printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", | 32 | printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", |
32 | bb_mode_string(file_header->mode), | 33 | bb_mode_string(modestr, file_header->mode), |
33 | user, | 34 | user, |
34 | group, | 35 | group, |
35 | file_header->size, | 36 | file_header->size, |
@@ -46,7 +47,7 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header) | |||
46 | localtime_r(&file_header->mtime, ptm); | 47 | localtime_r(&file_header->mtime, ptm); |
47 | 48 | ||
48 | printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", | 49 | printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", |
49 | bb_mode_string(file_header->mode), | 50 | bb_mode_string(modestr, file_header->mode), |
50 | (unsigned)file_header->uid, | 51 | (unsigned)file_header->uid, |
51 | (unsigned)file_header->gid, | 52 | (unsigned)file_header->gid, |
52 | file_header->size, | 53 | file_header->size, |
diff --git a/coreutils/chmod.c b/coreutils/chmod.c index e260adab2..5832cc51b 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c | |||
@@ -88,10 +88,12 @@ static int FAST_FUNC fileAction(struct recursive_state *state, | |||
88 | 88 | ||
89 | if (chmod(fileName, newmode) == 0) { | 89 | if (chmod(fileName, newmode) == 0) { |
90 | if (OPT_VERBOSE | 90 | if (OPT_VERBOSE |
91 | || (OPT_CHANGED && statbuf->st_mode != newmode) | 91 | || (OPT_CHANGED |
92 | && (statbuf->st_mode & 07777) != (newmode & 07777)) | ||
92 | ) { | 93 | ) { |
94 | char modestr[12]; | ||
93 | printf("mode of '%s' changed to %04o (%s)\n", fileName, | 95 | printf("mode of '%s' changed to %04o (%s)\n", fileName, |
94 | newmode & 07777, bb_mode_string(newmode)+1); | 96 | newmode & 07777, bb_mode_string(modestr, newmode)+1); |
95 | } | 97 | } |
96 | return TRUE; | 98 | return TRUE; |
97 | } | 99 | } |
diff --git a/coreutils/ls.c b/coreutils/ls.c index 0330f62df..58b8fde75 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -510,7 +510,8 @@ static NOINLINE unsigned display_single(const struct dnode *dn) | |||
510 | column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); | 510 | column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); |
511 | if (opt & OPT_l) { | 511 | if (opt & OPT_l) { |
512 | /* long listing: show mode */ | 512 | /* long listing: show mode */ |
513 | column += printf("%-10s ", (char *) bb_mode_string(dn->dn_mode)); | 513 | char modestr[12]; |
514 | column += printf("%-10s ", bb_mode_string(modestr, dn->dn_mode)); | ||
514 | /* long listing: show number of links */ | 515 | /* long listing: show number of links */ |
515 | column += printf("%4lu ", (long) dn->dn_nlink); | 516 | column += printf("%4lu ", (long) dn->dn_nlink); |
516 | /* long listing: show user/group */ | 517 | /* long listing: show user/group */ |
diff --git a/coreutils/stat.c b/coreutils/stat.c index 96cbf6dc6..940ade89a 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c | |||
@@ -340,7 +340,8 @@ static void FAST_FUNC print_stat(char *pformat, const char m, | |||
340 | strcat(pformat, "lo"); | 340 | strcat(pformat, "lo"); |
341 | printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))); | 341 | printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))); |
342 | } else if (m == 'A') { | 342 | } else if (m == 'A') { |
343 | printfs(pformat, bb_mode_string(statbuf->st_mode)); | 343 | char modestr[12]; |
344 | printfs(pformat, bb_mode_string(modestr, statbuf->st_mode)); | ||
344 | } else if (m == 'f') { | 345 | } else if (m == 'f') { |
345 | strcat(pformat, "lx"); | 346 | strcat(pformat, "lx"); |
346 | printf(pformat, (unsigned long) statbuf->st_mode); | 347 | printf(pformat, (unsigned long) statbuf->st_mode); |
@@ -703,6 +704,7 @@ static bool do_stat(const char *filename, const char *format) | |||
703 | bb_putchar('\n'); | 704 | bb_putchar('\n'); |
704 | # endif | 705 | # endif |
705 | } else { | 706 | } else { |
707 | char modestr[12]; | ||
706 | char *linkname = NULL; | 708 | char *linkname = NULL; |
707 | struct passwd *pw_ent; | 709 | struct passwd *pw_ent; |
708 | struct group *gw_ent; | 710 | struct group *gw_ent; |
@@ -737,7 +739,7 @@ static bool do_stat(const char *filename, const char *format) | |||
737 | bb_putchar('\n'); | 739 | bb_putchar('\n'); |
738 | printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n", | 740 | printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n", |
739 | (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), | 741 | (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), |
740 | bb_mode_string(statbuf.st_mode), | 742 | bb_mode_string(modestr, statbuf.st_mode), |
741 | (unsigned long) statbuf.st_uid, | 743 | (unsigned long) statbuf.st_uid, |
742 | (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN", | 744 | (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN", |
743 | (unsigned long) statbuf.st_gid, | 745 | (unsigned long) statbuf.st_gid, |
diff --git a/include/libbb.h b/include/libbb.h index cee37f9d8..3a958b555 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -459,9 +459,8 @@ void *xmmap_anon(size_t size) FAST_FUNC; | |||
459 | # define cached_pagesize(var) (var) | 459 | # define cached_pagesize(var) (var) |
460 | #endif | 460 | #endif |
461 | 461 | ||
462 | 462 | /* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */ | |
463 | //TODO: supply a pointer to char[11] buffer (avoid statics)? | 463 | extern char *bb_mode_string(char buf[11], mode_t mode) FAST_FUNC; |
464 | extern const char *bb_mode_string(mode_t mode) FAST_FUNC; | ||
465 | extern int is_directory(const char *name, int followLinks) FAST_FUNC; | 464 | extern int is_directory(const char *name, int followLinks) FAST_FUNC; |
466 | enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing them! */ | 465 | enum { /* cp.c, mv.c, install.c depend on these values. CAREFUL when changing them! */ |
467 | FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ | 466 | FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ |
@@ -1651,7 +1650,7 @@ char *bb_ask_noecho_stdin(const char *prompt) FAST_FUNC; | |||
1651 | int bb_ask_y_confirmation_FILE(FILE *fp) FAST_FUNC; | 1650 | int bb_ask_y_confirmation_FILE(FILE *fp) FAST_FUNC; |
1652 | int bb_ask_y_confirmation(void) FAST_FUNC; | 1651 | int bb_ask_y_confirmation(void) FAST_FUNC; |
1653 | 1652 | ||
1654 | /* Returns -1 if input is invalid. current_mode is a base for e.g. "u+rw" */ | 1653 | /* Returns -1 if input is invalid. cur_mode is a base for e.g. "u+rw" */ |
1655 | int bb_parse_mode(const char* s, unsigned cur_mode) FAST_FUNC; | 1654 | int bb_parse_mode(const char* s, unsigned cur_mode) FAST_FUNC; |
1656 | 1655 | ||
1657 | /* | 1656 | /* |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index f17c9a215..7c46fa5db 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -1219,7 +1219,16 @@ static void showfiles(void) | |||
1219 | 1219 | ||
1220 | static const char *is_special_char(char c) | 1220 | static const char *is_special_char(char c) |
1221 | { | 1221 | { |
1222 | return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c); | 1222 | // {: It's mandatory to escape { only if entire name is "{" |
1223 | // (otherwise it's not special. Example: file named "{ " | ||
1224 | // can be escaped simply as "{\ "; "{a" or "a{" need no escaping), | ||
1225 | // or if shell supports brace expansion | ||
1226 | // (ash doesn't, hush optionally does). | ||
1227 | // (): unlike {, shell treats () specially even in contexts | ||
1228 | // where they clearly are not valid (e.g. "echo )" is an error). | ||
1229 | // #: needs escaping to not start a shell comment. | ||
1230 | return strchr(" `'\"\\#$~?*[{()&;|<>", c); | ||
1231 | // Used to also have %^=+}]: but not necessary to escape? | ||
1223 | } | 1232 | } |
1224 | 1233 | ||
1225 | static char *quote_special_chars(char *found) | 1234 | static char *quote_special_chars(char *found) |
diff --git a/libbb/mode_string.c b/libbb/mode_string.c index dc3f9f88c..906c03964 100644 --- a/libbb/mode_string.c +++ b/libbb/mode_string.c | |||
@@ -16,16 +16,18 @@ | |||
16 | #error permission bitflag value assumption(s) violated! | 16 | #error permission bitflag value assumption(s) violated! |
17 | #endif | 17 | #endif |
18 | 18 | ||
19 | /* Generate ls-style "mode string" like "-rwsr-xr-x" or "drwxrwxrwt" */ | ||
20 | |||
19 | #if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \ | 21 | #if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \ |
20 | || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 && S_IFBLK != 0030000 ) \ | 22 | || ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 && S_IFBLK != 0030000 ) \ |
21 | || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \ | 23 | || ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \ |
22 | || ( S_IFIFO != 0010000 ) | 24 | || ( S_IFIFO != 0010000 ) |
23 | #warning mode type bitflag value assumption(s) violated! falling back to larger version | 25 | # warning mode type bitflag value assumption(s) violated! falling back to larger version |
24 | 26 | ||
25 | #if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777 | 27 | # if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777 |
26 | #undef mode_t | 28 | # undef mode_t |
27 | #define mode_t unsigned short | 29 | # define mode_t unsigned short |
28 | #endif | 30 | # endif |
29 | 31 | ||
30 | static const mode_t mode_flags[] ALIGN4 = { | 32 | static const mode_t mode_flags[] ALIGN4 = { |
31 | S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, | 33 | S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, |
@@ -33,19 +35,14 @@ static const mode_t mode_flags[] ALIGN4 = { | |||
33 | S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX | 35 | S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX |
34 | }; | 36 | }; |
35 | 37 | ||
36 | /* The static const char arrays below are duplicated for the two cases | ||
37 | * because moving them ahead of the mode_flags declaration cause a text | ||
38 | * size increase with the gcc version I'm using. */ | ||
39 | |||
40 | /* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C', | 38 | /* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C', |
41 | * and 'B' types don't appear to be available on linux. So I removed them. */ | 39 | * and 'B' types don't appear to be available on linux. So I removed them. */ |
42 | static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???"; | 40 | static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???"; |
43 | /***************************************** 0123456789abcdef */ | 41 | /***************************************** 0123456789abcdef */ |
44 | static const char mode_chars[7] ALIGN1 = "rwxSTst"; | 42 | static const char mode_chars[7] ALIGN1 = "rwxSTst"; |
45 | 43 | ||
46 | const char* FAST_FUNC bb_mode_string(mode_t mode) | 44 | char* FAST_FUNC bb_mode_string(char buf[11], mode_t mode) |
47 | { | 45 | { |
48 | static char buf[12]; | ||
49 | char *p = buf; | 46 | char *p = buf; |
50 | 47 | ||
51 | int i, j, k; | 48 | int i, j, k; |
@@ -67,10 +64,7 @@ const char* FAST_FUNC bb_mode_string(mode_t mode) | |||
67 | i += 4; | 64 | i += 4; |
68 | } while (i < 12); | 65 | } while (i < 12); |
69 | 66 | ||
70 | /* Note: We don't bother with nul termination because bss initialization | 67 | buf[10] = '\0'; |
71 | * should have taken care of that for us. If the user scribbled in buf | ||
72 | * memory, they deserve whatever happens. But we'll at least assert. */ | ||
73 | assert(buf[10] == 0); | ||
74 | 68 | ||
75 | return buf; | 69 | return buf; |
76 | } | 70 | } |
@@ -80,12 +74,11 @@ const char* FAST_FUNC bb_mode_string(mode_t mode) | |||
80 | /* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C', | 74 | /* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C', |
81 | * and 'B' types don't appear to be available on linux. So I removed them. */ | 75 | * and 'B' types don't appear to be available on linux. So I removed them. */ |
82 | static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???"; | 76 | static const char type_chars[16] ALIGN1 = "?pc?d?b?-?l?s???"; |
83 | /********************************** 0123456789abcdef */ | 77 | /***************************************** 0123456789abcdef */ |
84 | static const char mode_chars[7] ALIGN1 = "rwxSTst"; | 78 | static const char mode_chars[7] ALIGN1 = "rwxSTst"; |
85 | 79 | ||
86 | const char* FAST_FUNC bb_mode_string(mode_t mode) | 80 | char* FAST_FUNC bb_mode_string(char buf[11], mode_t mode) |
87 | { | 81 | { |
88 | static char buf[12]; | ||
89 | char *p = buf; | 82 | char *p = buf; |
90 | 83 | ||
91 | int i, j, k, m; | 84 | int i, j, k, m; |
@@ -109,10 +102,7 @@ const char* FAST_FUNC bb_mode_string(mode_t mode) | |||
109 | } | 102 | } |
110 | } while (i < 3); | 103 | } while (i < 3); |
111 | 104 | ||
112 | /* Note: We don't bother with nul termination because bss initialization | 105 | buf[10] = '\0'; |
113 | * should have taken care of that for us. If the user scribbled in buf | ||
114 | * memory, they deserve whatever happens. But we'll at least assert. */ | ||
115 | assert(buf[10] == 0); | ||
116 | 106 | ||
117 | return buf; | 107 | return buf; |
118 | } | 108 | } |
diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c index dc65860f6..1d238e1e0 100644 --- a/libbb/parse_mode.c +++ b/libbb/parse_mode.c | |||
@@ -16,13 +16,14 @@ | |||
16 | 16 | ||
17 | int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode) | 17 | int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode) |
18 | { | 18 | { |
19 | static const mode_t who_mask[] = { | 19 | /* should be mode_t really, but in all Unixes these constants fit into uint16 */ |
20 | static const uint16_t who_mask[] ALIGN2 = { | ||
20 | S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ | 21 | S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ |
21 | S_ISUID | S_IRWXU, /* u */ | 22 | S_ISUID | S_IRWXU, /* u */ |
22 | S_ISGID | S_IRWXG, /* g */ | 23 | S_ISGID | S_IRWXG, /* g */ |
23 | S_IRWXO /* o */ | 24 | S_IRWXO /* o */ |
24 | }; | 25 | }; |
25 | static const mode_t perm_mask[] = { | 26 | static const uint16_t perm_mask[] ALIGN2 = { |
26 | S_IRUSR | S_IRGRP | S_IROTH, /* r */ | 27 | S_IRUSR | S_IRGRP | S_IROTH, /* r */ |
27 | S_IWUSR | S_IWGRP | S_IWOTH, /* w */ | 28 | S_IWUSR | S_IWGRP | S_IWOTH, /* w */ |
28 | S_IXUSR | S_IXGRP | S_IXOTH, /* x */ | 29 | S_IXUSR | S_IXGRP | S_IXOTH, /* x */ |
diff --git a/libbb/time.c b/libbb/time.c index ed4f50470..e7c9fa65e 100644 --- a/libbb/time.c +++ b/libbb/time.c | |||
@@ -13,6 +13,7 @@ | |||
13 | int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | 13 | int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) |
14 | { | 14 | { |
15 | char end = '\0'; | 15 | char end = '\0'; |
16 | time_t t; | ||
16 | #if ENABLE_DESKTOP | 17 | #if ENABLE_DESKTOP |
17 | /* | 18 | /* |
18 | * strptime is BIG: ~1k in uclibc, ~10k in glibc | 19 | * strptime is BIG: ~1k in uclibc, ~10k in glibc |
@@ -29,10 +30,10 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
29 | "%b %d %T %Y" "\0" /* month_name d HH:MM:SS YYYY */ | 30 | "%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 %R" "\0" /* yyyy-mm-dd HH:MM */ |
31 | "%Y-%m-%d %T" "\0" /* yyyy-mm-dd HH:MM:SS */ | 32 | "%Y-%m-%d %T" "\0" /* yyyy-mm-dd HH:MM:SS */ |
32 | #if ENABLE_FEATURE_TIMEZONE | 33 | # if ENABLE_FEATURE_TIMEZONE |
33 | "%Y-%m-%d %R %z" "\0" /* yyyy-mm-dd HH:MM TZ */ | 34 | "%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 | "%Y-%m-%d %T %z" "\0" /* yyyy-mm-dd HH:MM:SS TZ */ |
35 | #endif | 36 | # endif |
36 | "%Y-%m-%d %H" "\0" /* yyyy-mm-dd HH */ | 37 | "%Y-%m-%d %H" "\0" /* yyyy-mm-dd HH */ |
37 | "%Y-%m-%d" "\0" /* yyyy-mm-dd */ | 38 | "%Y-%m-%d" "\0" /* yyyy-mm-dd */ |
38 | /* extra NUL */; | 39 | /* extra NUL */; |
@@ -50,11 +51,8 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
50 | endp = strptime(date_str, fmt, ptm); | 51 | endp = strptime(date_str, fmt, ptm); |
51 | #endif | 52 | #endif |
52 | if (endp && *endp == '\0') { | 53 | if (endp && *endp == '\0') { |
53 | #if ENABLE_FEATURE_TIMEZONE | 54 | # if ENABLE_FEATURE_TIMEZONE |
54 | if (strchr(fmt, 'z')) { | 55 | if (strchr(fmt, 'z')) { |
55 | time_t t; | ||
56 | struct tm *utm; | ||
57 | |||
58 | /* we have timezone offset: obtain Unix time_t */ | 56 | /* we have timezone offset: obtain Unix time_t */ |
59 | #if ENABLE_PLATFORM_MINGW32 | 57 | #if ENABLE_PLATFORM_MINGW32 |
60 | ptm->tm_sec -= gmtoff; | 58 | ptm->tm_sec -= gmtoff; |
@@ -66,13 +64,9 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
66 | if (t == (time_t)-1) | 64 | if (t == (time_t)-1) |
67 | break; | 65 | break; |
68 | /* convert Unix time_t to struct tm in user's locale */ | 66 | /* convert Unix time_t to struct tm in user's locale */ |
69 | utm = localtime(&t); | 67 | goto localise; |
70 | if (!utm) | ||
71 | break; | ||
72 | *ptm = *utm; | ||
73 | return 0; | ||
74 | } | 68 | } |
75 | #endif | 69 | # endif |
76 | return 1; | 70 | return 1; |
77 | } | 71 | } |
78 | *ptm = save; | 72 | *ptm = save; |
@@ -150,13 +144,14 @@ int FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) | |||
150 | } else | 144 | } else |
151 | #endif /* ENABLE_DESKTOP */ | 145 | #endif /* ENABLE_DESKTOP */ |
152 | if (date_str[0] == '@') { | 146 | if (date_str[0] == '@') { |
153 | time_t t; | ||
154 | if (sizeof(t) <= sizeof(long)) | 147 | if (sizeof(t) <= sizeof(long)) |
155 | t = bb_strtol(date_str + 1, NULL, 10); | 148 | t = bb_strtol(date_str + 1, NULL, 10); |
156 | else /* time_t is 64 bits but longs are smaller */ | 149 | else /* time_t is 64 bits but longs are smaller */ |
157 | t = bb_strtoll(date_str + 1, NULL, 10); | 150 | t = bb_strtoll(date_str + 1, NULL, 10); |
158 | if (!errno) { | 151 | if (!errno) { |
159 | struct tm *lt = localtime(&t); | 152 | struct tm *lt; |
153 | IF_FEATURE_TIMEZONE(localise:) | ||
154 | lt = localtime(&t); | ||
160 | if (lt) { | 155 | if (lt) { |
161 | *ptm = *lt; | 156 | *ptm = *lt; |
162 | return 0; | 157 | return 0; |
diff --git a/util-linux/cal.c b/util-linux/cal.c index 006bc817b..6ba6ebf98 100644 --- a/util-linux/cal.c +++ b/util-linux/cal.c | |||
@@ -27,10 +27,11 @@ | |||
27 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */ | 27 | /* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */ |
28 | 28 | ||
29 | //usage:#define cal_trivial_usage | 29 | //usage:#define cal_trivial_usage |
30 | //usage: "[-jy] [[MONTH] YEAR]" | 30 | //usage: "[-jmy] [[MONTH] YEAR]" |
31 | //usage:#define cal_full_usage "\n\n" | 31 | //usage:#define cal_full_usage "\n\n" |
32 | //usage: "Display a calendar\n" | 32 | //usage: "Display a calendar\n" |
33 | //usage: "\n -j Use julian dates" | 33 | //usage: "\n -j Use julian dates" |
34 | //usage: "\n -m Week starts on Monday" | ||
34 | //usage: "\n -y Display the entire year" | 35 | //usage: "\n -y Display the entire year" |
35 | 36 | ||
36 | #include "libbb.h" | 37 | #include "libbb.h" |
@@ -38,6 +39,8 @@ | |||
38 | 39 | ||
39 | /* We often use "unsigned" instead of "int", it's easier to div on most CPUs */ | 40 | /* We often use "unsigned" instead of "int", it's easier to div on most CPUs */ |
40 | 41 | ||
42 | #define SUNDAY 0 | ||
43 | #define MONDAY 1 | ||
41 | #define THURSDAY 4 /* for reformation */ | 44 | #define THURSDAY 4 /* for reformation */ |
42 | #define SATURDAY 6 /* 1 Jan 1 was a Saturday */ | 45 | #define SATURDAY 6 /* 1 Jan 1 was a Saturday */ |
43 | 46 | ||
@@ -81,7 +84,7 @@ static int leap_year(unsigned yr) | |||
81 | ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) | 84 | ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) |
82 | 85 | ||
83 | static void center(char *, unsigned, unsigned); | 86 | static void center(char *, unsigned, unsigned); |
84 | static void day_array(unsigned, unsigned, unsigned *); | 87 | static void day_array(unsigned, unsigned, unsigned, unsigned *); |
85 | static void trim_trailing_spaces_and_print(char *); | 88 | static void trim_trailing_spaces_and_print(char *); |
86 | 89 | ||
87 | static void blank_string(char *buf, size_t buflen); | 90 | static void blank_string(char *buf, size_t buflen); |
@@ -93,12 +96,18 @@ static char *build_row(char *p, unsigned *dp); | |||
93 | #define J_WEEK_LEN (WEEK_LEN + 7) | 96 | #define J_WEEK_LEN (WEEK_LEN + 7) |
94 | #define HEAD_SEP 2 /* spaces between day headings */ | 97 | #define HEAD_SEP 2 /* spaces between day headings */ |
95 | 98 | ||
99 | enum { | ||
100 | OPT_JULIAN = (1 << 0), | ||
101 | OPT_MONDAY = (1 << 1), | ||
102 | OPT_YEAR = (1 << 2), | ||
103 | }; | ||
104 | |||
96 | int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 105 | int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
97 | int cal_main(int argc UNUSED_PARAM, char **argv) | 106 | int cal_main(int argc UNUSED_PARAM, char **argv) |
98 | { | 107 | { |
99 | struct tm zero_tm; | 108 | struct tm zero_tm; |
100 | time_t now; | 109 | time_t now; |
101 | unsigned month, year, flags, i; | 110 | unsigned month, year, flags, i, weekstart; |
102 | char *month_names[12]; | 111 | char *month_names[12]; |
103 | /* normal heading: */ | 112 | /* normal heading: */ |
104 | /* "Su Mo Tu We Th Fr Sa" */ | 113 | /* "Su Mo Tu We Th Fr Sa" */ |
@@ -110,10 +119,11 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
110 | 119 | ||
111 | init_unicode(); | 120 | init_unicode(); |
112 | 121 | ||
113 | flags = getopt32(argv, "jy"); | 122 | flags = getopt32(argv, "jmy"); |
114 | /* This sets julian = flags & 1: */ | 123 | /* This sets julian = flags & OPT_JULIAN: */ |
115 | option_mask32 &= 1; | 124 | option_mask32 &= OPT_JULIAN; |
116 | month = 0; | 125 | month = 0; |
126 | weekstart = (flags & OPT_MONDAY) ? MONDAY : SUNDAY; | ||
117 | argv += optind; | 127 | argv += optind; |
118 | 128 | ||
119 | if (!argv[0]) { | 129 | if (!argv[0]) { |
@@ -122,7 +132,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
122 | time(&now); | 132 | time(&now); |
123 | ptm = localtime(&now); | 133 | ptm = localtime(&now); |
124 | year = ptm->tm_year + 1900; | 134 | year = ptm->tm_year + 1900; |
125 | if (!(flags & 2)) { /* no -y */ | 135 | if (!(flags & OPT_YEAR)) { /* no -y */ |
126 | month = ptm->tm_mon + 1; | 136 | month = ptm->tm_mon + 1; |
127 | } | 137 | } |
128 | } else { | 138 | } else { |
@@ -130,7 +140,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
130 | if (argv[2]) { | 140 | if (argv[2]) { |
131 | bb_show_usage(); | 141 | bb_show_usage(); |
132 | } | 142 | } |
133 | if (!(flags & 2)) { /* no -y */ | 143 | if (!(flags & OPT_YEAR)) { /* no -y */ |
134 | month = xatou_range(*argv, 1, 12); | 144 | month = xatou_range(*argv, 1, 12); |
135 | } | 145 | } |
136 | argv++; | 146 | argv++; |
@@ -148,7 +158,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
148 | month_names[i] = xstrdup(buf); | 158 | month_names[i] = xstrdup(buf); |
149 | 159 | ||
150 | if (i < 7) { | 160 | if (i < 7) { |
151 | zero_tm.tm_wday = i; | 161 | zero_tm.tm_wday = (i + weekstart) % 7; |
152 | /* abbreviated weekday name according to locale */ | 162 | /* abbreviated weekday name according to locale */ |
153 | strftime(buf, sizeof(buf), "%a", &zero_tm); | 163 | strftime(buf, sizeof(buf), "%a", &zero_tm); |
154 | #if ENABLE_UNICODE_SUPPORT | 164 | #if ENABLE_UNICODE_SUPPORT |
@@ -173,7 +183,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
173 | unsigned *dp = days; | 183 | unsigned *dp = days; |
174 | char lineout[30]; | 184 | char lineout[30]; |
175 | 185 | ||
176 | day_array(month, year, dp); | 186 | day_array(month, year, weekstart, dp); |
177 | len = sprintf(lineout, "%s %u", month_names[month - 1], year); | 187 | len = sprintf(lineout, "%s %u", month_names[month - 1], year); |
178 | printf("%*s%s\n%s\n", | 188 | printf("%*s%s\n%s\n", |
179 | ((7*julian + WEEK_LEN) - len) / 2, "", | 189 | ((7*julian + WEEK_LEN) - len) / 2, "", |
@@ -197,7 +207,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
197 | ); | 207 | ); |
198 | puts("\n"); /* two \n's */ | 208 | puts("\n"); /* two \n's */ |
199 | for (i = 0; i < 12; i++) { | 209 | for (i = 0; i < 12; i++) { |
200 | day_array(i + 1, year, days[i]); | 210 | day_array(i + 1, year, weekstart, days[i]); |
201 | } | 211 | } |
202 | blank_string(lineout, sizeof(lineout)); | 212 | blank_string(lineout, sizeof(lineout)); |
203 | week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN); | 213 | week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN); |
@@ -233,7 +243,8 @@ int cal_main(int argc UNUSED_PARAM, char **argv) | |||
233 | * out end to end. You would have 42 numbers or spaces. This routine | 243 | * out end to end. You would have 42 numbers or spaces. This routine |
234 | * builds that array for any month from Jan. 1 through Dec. 9999. | 244 | * builds that array for any month from Jan. 1 through Dec. 9999. |
235 | */ | 245 | */ |
236 | static void day_array(unsigned month, unsigned year, unsigned *days) | 246 | static void day_array(unsigned month, unsigned year, unsigned weekstart, |
247 | unsigned *days) | ||
237 | { | 248 | { |
238 | unsigned long temp; | 249 | unsigned long temp; |
239 | unsigned i; | 250 | unsigned i; |
@@ -249,7 +260,7 @@ static void day_array(unsigned month, unsigned year, unsigned *days) | |||
249 | size_t oday = 0; | 260 | size_t oday = 0; |
250 | 261 | ||
251 | do { | 262 | do { |
252 | days[oday+2] = sep1752[oday] + j_offset; | 263 | days[oday+2-weekstart] = sep1752[oday] + j_offset; |
253 | } while (++oday < sizeof(sep1752)); | 264 | } while (++oday < sizeof(sep1752)); |
254 | 265 | ||
255 | return; | 266 | return; |
@@ -280,6 +291,7 @@ static void day_array(unsigned month, unsigned year, unsigned *days) | |||
280 | } else { | 291 | } else { |
281 | dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); | 292 | dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); |
282 | } | 293 | } |
294 | dw = (dw - weekstart + 7) % 7; | ||
283 | 295 | ||
284 | if (!julian) { | 296 | if (!julian) { |
285 | day = 1; | 297 | day = 1; |