Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/date.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 10  Line 10 
10   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
11  */  */
12    
 #include "libbb.h"  
   
13  /* This 'date' command supports only 2 time setting formats,  /* This 'date' command supports only 2 time setting formats,
14     all the GNU strftime stuff (its in libc, lets use it),     all the GNU strftime stuff (its in libc, lets use it),
15     setting time using UTC and displaying it, as well as     setting time using UTC and displaying it, as well as
# Line 23  Line 21 
21    
22  /* Default input handling to save surprising some people */  /* Default input handling to save surprising some people */
23    
24    /* GNU coreutils 6.9 man page:
25     * date [OPTION]... [+FORMAT]
26     * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
27     * -d, --date=STRING
28     *      display time described by STRING, not `now'
29     * -f, --file=DATEFILE
30     *      like --date once for each line of DATEFILE
31     * -r, --reference=FILE
32     *      display the last modification time of FILE
33     * -R, --rfc-2822
34     *      output date and time in RFC 2822 format.
35     *      Example: Mon, 07 Aug 2006 12:34:56 -0600
36     * --rfc-3339=TIMESPEC
37     *      output date and time in RFC 3339 format.
38     *      TIMESPEC='date', 'seconds', or 'ns'
39     *      Date and time components are separated by a single space:
40     *      2006-08-07 12:34:56-06:00
41     * -s, --set=STRING
42     *      set time described by STRING
43     * -u, --utc, --universal
44     *      print or set Coordinated Universal Time
45     *
46     * Busybox:
47     * long options are not supported
48     * -f is not supported
49     * -I seems to roughly match --rfc-3339, but -I has _optional_ param
50     *    (thus "-I seconds" doesn't work, only "-Iseconds"),
51     *    and does not support -Ins
52     * -D FMT is a bbox extension for _input_ conversion of -d DATE
53     */
54    #include "libbb.h"
55    
56  #define DATE_OPT_RFC2822 0x01  enum {
57  #define DATE_OPT_SET 0x02   OPT_RFC2822   = (1 << 0), /* R */
58  #define DATE_OPT_UTC 0x04   OPT_SET       = (1 << 1), /* s */
59  #define DATE_OPT_DATE 0x08   OPT_UTC       = (1 << 2), /* u */
60  #define DATE_OPT_REFERENCE 0x10   OPT_DATE      = (1 << 3), /* d */
61  #define DATE_OPT_TIMESPEC 0x20   OPT_REFERENCE = (1 << 4), /* r */
62  #define DATE_OPT_HINT 0x40   OPT_TIMESPEC  = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */
63     OPT_HINT      = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */
64    };
65    
66  static void maybe_set_utc(int opt)  static void maybe_set_utc(int opt)
67  {  {
68   if (opt & DATE_OPT_UTC)   if (opt & OPT_UTC)
69   putenv((char*)"TZ=UTC0");   putenv((char*)"TZ=UTC0");
70  }  }
71    
72    #if ENABLE_LONG_OPTS
73    static const char date_longopts[] ALIGN1 =
74     "rfc-822\0"   No_argument       "R"
75     "rfc-2822\0"  No_argument       "R"
76     "set\0"       Required_argument "s"
77     "utc\0"       No_argument       "u"
78     /* "universal\0" No_argument       "u" */
79     "date\0"      Required_argument "d"
80     "reference\0" Required_argument "r"
81     ;
82    #endif
83    
84  int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
85  int date_main(int argc UNUSED_PARAM, char **argv)  int date_main(int argc UNUSED_PARAM, char **argv)
86  {  {
87   struct tm tm_time;   struct tm tm_time;
88     char buf_fmt_dt2str[64];
89   time_t tm;   time_t tm;
90   unsigned opt;   unsigned opt;
91   int ifmt = -1;   int ifmt = -1;
# Line 52  int date_main(int argc UNUSED_PARAM, cha Line 96  int date_main(int argc UNUSED_PARAM, cha
96   char *isofmt_arg = NULL;   char *isofmt_arg = NULL;
97    
98   opt_complementary = "d--s:s--d"   opt_complementary = "d--s:s--d"
99   USE_FEATURE_DATE_ISOFMT(":R--I:I--R");   IF_FEATURE_DATE_ISOFMT(":R--I:I--R");
100     IF_LONG_OPTS(applet_long_options = date_longopts;)
101   opt = getopt32(argv, "Rs:ud:r:"   opt = getopt32(argv, "Rs:ud:r:"
102   USE_FEATURE_DATE_ISOFMT("I::D:"),   IF_FEATURE_DATE_ISOFMT("I::D:"),
103   &date_str, &date_str, &filename   &date_str, &date_str, &filename
104   USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));   IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
105   argv += optind;   argv += optind;
106   maybe_set_utc(opt);   maybe_set_utc(opt);
107    
108   if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_TIMESPEC)) {   if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_TIMESPEC)) {
109   ifmt = 0; /* default is date */   ifmt = 0; /* default is date */
110   if (isofmt_arg) {   if (isofmt_arg) {
111   static const char isoformats[] ALIGN1 =   static const char isoformats[] ALIGN1 =
112   "date\0""hours\0""minutes\0""seconds\0";   "date\0""hours\0""minutes\0""seconds\0"; /* ns? */
113   ifmt = index_in_strings(isoformats, isofmt_arg);   ifmt = index_in_substrings(isoformats, isofmt_arg);
114   if (ifmt < 0)   if (ifmt < 0)
115   bb_show_usage();   bb_show_usage();
116   }   }
# Line 73  int date_main(int argc UNUSED_PARAM, cha Line 118  int date_main(int argc UNUSED_PARAM, cha
118    
119   fmt_dt2str = NULL;   fmt_dt2str = NULL;
120   if (argv[0] && argv[0][0] == '+') {   if (argv[0] && argv[0][0] == '+') {
121   fmt_dt2str = &argv[0][1]; /* Skip over the '+' */   fmt_dt2str = &argv[0][1]; /* skip over the '+' */
122   argv++;   argv++;
123   }   }
124   if (!(opt & (DATE_OPT_SET | DATE_OPT_DATE))) {   if (!(opt & (OPT_SET | OPT_DATE))) {
125   opt |= DATE_OPT_SET;   opt |= OPT_SET;
126   date_str = argv[0]; /* can be NULL */   date_str = argv[0]; /* can be NULL */
127   if (date_str)   if (date_str) {
128    #if ENABLE_FEATURE_DATE_COMPAT
129     int len = strspn(date_str, "0123456789");
130     if (date_str[len] == '\0'
131     || (date_str[len] == '.'
132        && isdigit(date_str[len+1])
133        && isdigit(date_str[len+2])
134        && date_str[len+3] == '\0'
135        )
136     ) {
137     /* Dreaded MMDDhhmm[[CC]YY][.ss] format!
138     * It does not match -d or -s format.
139     * Some users actually do use it.
140     */
141     len -= 8;
142     if (len < 0 || len > 4 || (len & 1))
143     bb_error_msg_and_die(bb_msg_invalid_date, date_str);
144     if (len != 0) { /* move YY or CCYY to front */
145     char buf[4];
146     memcpy(buf, date_str + 8, len);
147     memmove(date_str + len, date_str, 8);
148     memcpy(date_str, buf, len);
149     }
150     }
151    #endif
152   argv++;   argv++;
153     }
154   }   }
155   if (*argv)   if (*argv)
156   bb_show_usage();   bb_show_usage();
157    
158   /* Now we have parsed all the information except the date format   /* Now we have parsed all the information except the date format
159     which depends on whether the clock is being set or read */   * which depends on whether the clock is being set or read */
160    
161   if (opt & DATE_OPT_REFERENCE) {   if (opt & OPT_REFERENCE) {
162   struct stat statbuf;   struct stat statbuf;
163   xstat(filename, &statbuf);   xstat(filename, &statbuf);
164   tm = statbuf.st_mtime;   tm = statbuf.st_mtime;
165   } else   } else {
166   time(&tm);   time(&tm);
167   memcpy(&tm_time, localtime(&tm), sizeof(tm_time));   }
168     localtime_r(&tm, &tm_time);
169    
170   /* If date string is given, update tm_time, and maybe set date */   /* If date string is given, update tm_time, and maybe set date */
171   if (date_str != NULL) {   if (date_str != NULL) {
# Line 104  int date_main(int argc UNUSED_PARAM, cha Line 175  int date_main(int argc UNUSED_PARAM, cha
175   tm_time.tm_hour = 0;   tm_time.tm_hour = 0;
176    
177   /* Process any date input to UNIX time since 1 Jan 1970 */   /* Process any date input to UNIX time since 1 Jan 1970 */
178   if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) {   if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_HINT)) {
179   if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)   if (strptime(date_str, fmt_str2dt, &tm_time) == NULL)
180   bb_error_msg_and_die(bb_msg_invalid_date, date_str);   bb_error_msg_and_die(bb_msg_invalid_date, date_str);
181   } else {   } else {
182   char end = '\0';   parse_datestr(date_str, &tm_time);
  const char *last_colon = strrchr(date_str, ':');  
   
  if (last_colon != NULL) {  
  /* Parse input and assign appropriately to tm_time */  
   
  if (sscanf(date_str, "%u:%u%c",  
  &tm_time.tm_hour,  
  &tm_time.tm_min,  
  &end) >= 2) {  
  /* no adjustments needed */  
  } else if (sscanf(date_str, "%u.%u-%u:%u%c",  
  &tm_time.tm_mon, &tm_time.tm_mday,  
  &tm_time.tm_hour, &tm_time.tm_min,  
  &end) >= 4) {  
  /* Adjust dates from 1-12 to 0-11 */  
  tm_time.tm_mon -= 1;  
  } else if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &tm_time.tm_year,  
  &tm_time.tm_mon, &tm_time.tm_mday,  
  &tm_time.tm_hour, &tm_time.tm_min,  
  &end) >= 5) {  
  tm_time.tm_year -= 1900; /* Adjust years */  
  tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */  
  } else if (sscanf(date_str, "%u-%u-%u %u:%u%c", &tm_time.tm_year,  
  &tm_time.tm_mon, &tm_time.tm_mday,  
  &tm_time.tm_hour, &tm_time.tm_min,  
  &end) >= 5) {  
  tm_time.tm_year -= 1900; /* Adjust years */  
  tm_time.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */  
 //TODO: coreutils 6.9 also accepts "YYYY-MM-DD HH" (no minutes)  
  } else {  
  bb_error_msg_and_die(bb_msg_invalid_date, date_str);  
  }  
  if (end == ':') {  
  if (sscanf(last_colon + 1, "%u%c", &tm_time.tm_sec, &end) == 1)  
  end = '\0';  
  /* else end != NUL and we error out */  
  }  
  } else {  
  if (sscanf(date_str, "%2u%2u%2u%2u%u%c", &tm_time.tm_mon,  
  &tm_time.tm_mday, &tm_time.tm_hour, &tm_time.tm_min,  
  &tm_time.tm_year, &end) < 4)  
  bb_error_msg_and_die(bb_msg_invalid_date, date_str);  
  /* correct for century  - minor Y2K problem here? */  
  if (tm_time.tm_year >= 1900) {  
  tm_time.tm_year -= 1900;  
  }  
  /* adjust date */  
  tm_time.tm_mon -= 1;  
  if (end == '.') {  
  if (sscanf(strchr(date_str, '.') + 1, "%u%c",  
  &tm_time.tm_sec, &end) == 1)  
  end = '\0';  
  /* else end != NUL and we error out */  
  }  
  }  
  if (end != '\0') {  
  bb_error_msg_and_die(bb_msg_invalid_date, date_str);  
  }  
183   }   }
184    
185   /* Correct any day of week and day of year etc. fields */   /* Correct any day of week and day of year etc. fields */
186   tm_time.tm_isdst = -1; /* Be sure to recheck dst. */   tm_time.tm_isdst = -1; /* Be sure to recheck dst */
187   tm = mktime(&tm_time);   tm = validate_tm_time(date_str, &tm_time);
188   if (tm < 0) {  
  bb_error_msg_and_die(bb_msg_invalid_date, date_str);  
  }  
189   maybe_set_utc(opt);   maybe_set_utc(opt);
190    
191   /* if setting time, set it */   /* if setting time, set it */
192   if ((opt & DATE_OPT_SET) && stime(&tm) < 0) {   if ((opt & OPT_SET) && stime(&tm) < 0) {
193   bb_perror_msg("cannot set date");   bb_perror_msg("can't set date");
194   }   }
195   }   }
196    
# Line 187  int date_main(int argc UNUSED_PARAM, cha Line 199  int date_main(int argc UNUSED_PARAM, cha
199   /* Deal with format string */   /* Deal with format string */
200   if (fmt_dt2str == NULL) {   if (fmt_dt2str == NULL) {
201   int i;   int i;
202   fmt_dt2str = xzalloc(32);   fmt_dt2str = buf_fmt_dt2str;
203   if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) {   if (ENABLE_FEATURE_DATE_ISOFMT && ifmt >= 0) {
204   strcpy(fmt_dt2str, "%Y-%m-%d");   /* -I[SPEC]: 0:date 1:hours 2:minutes 3:seconds */
205   if (ifmt > 0) {   strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S");
206   i = 8;   i = 8 + 3 * ifmt;
207   fmt_dt2str[i++] = 'T';   if (ifmt != 0) {
208   fmt_dt2str[i++] = '%';   /* TODO: if (ifmt==4) i += sprintf(&fmt_dt2str[i], ",%09u", nanoseconds); */
  fmt_dt2str[i++] = 'H';  
  if (ifmt > 1) {  
  fmt_dt2str[i++] = ':';  
  fmt_dt2str[i++] = '%';  
  fmt_dt2str[i++] = 'M';  
  if (ifmt > 2) {  
  fmt_dt2str[i++] = ':';  
  fmt_dt2str[i++] = '%';  
  fmt_dt2str[i++] = 'S';  
  }  
  }  
209   format_utc:   format_utc:
210   fmt_dt2str[i++] = '%';   fmt_dt2str[i++] = '%';
211   fmt_dt2str[i] = (opt & DATE_OPT_UTC) ? 'Z' : 'z';   fmt_dt2str[i++] = (opt & OPT_UTC) ? 'Z' : 'z';
212   }   }
213   } else if (opt & DATE_OPT_RFC2822) {   fmt_dt2str[i] = '\0';
214   /* Undo busybox.c for date -R */   } else if (opt & OPT_RFC2822) {
215     /* -R. undo busybox.c setlocale */
216   if (ENABLE_LOCALE_SUPPORT)   if (ENABLE_LOCALE_SUPPORT)
217   setlocale(LC_TIME, "C");   setlocale(LC_TIME, "C");
218   strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S ");   strcpy(fmt_dt2str, "%a, %d %b %Y %H:%M:%S ");
219   i = 22;   i = sizeof("%a, %d %b %Y %H:%M:%S ")-1;
220   goto format_utc;   goto format_utc;
221   } else /* default case */   } else { /* default case */
222   fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";   fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
223     }
224   }   }
225    
226  #define date_buf bb_common_bufsiz1  #define date_buf bb_common_bufsiz1
# Line 229  int date_main(int argc UNUSED_PARAM, cha Line 232  int date_main(int argc UNUSED_PARAM, cha
232   if (strncmp(fmt_dt2str, "%f", 2) == 0) {   if (strncmp(fmt_dt2str, "%f", 2) == 0) {
233   fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";   fmt_dt2str = (char*)"%Y.%m.%d-%H:%M:%S";
234   }   }
   
235   /* Generate output string */   /* Generate output string */
236   strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time);   strftime(date_buf, sizeof(date_buf), fmt_dt2str, &tm_time);
237   }   }

Legend:
Removed from v.983  
changed lines
  Added in v.984