home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / sh-utils-1.12-src.tgz / tar.out / fsf / sh-utils / src / date.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  388 lines

  1. /* date - print or set the system date and time
  2.    Copyright (C) 89, 90, 91, 92, 93, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.    David MacKenzie <djm@gnu.ai.mit.edu> */
  19.  
  20. #include <config.h>
  21. #include <stdio.h>
  22. #include <getopt.h>
  23. #include <sys/types.h>
  24.  
  25. #include "version.h"
  26. #include "system.h"
  27. #include "getline.h"
  28.  
  29. #ifdef TM_IN_SYS_TIME
  30. #include <sys/time.h>
  31. #else
  32. #include <time.h>
  33. #endif
  34.  
  35. #ifndef STDC_HEADERS
  36. size_t strftime ();
  37. time_t time ();
  38. #endif
  39.  
  40. int stime ();
  41.  
  42. char *xrealloc ();
  43. time_t get_date ();
  44. time_t posixtime ();
  45. void error ();
  46.  
  47. static void show_date ();
  48. static void usage ();
  49.  
  50. /* The name this program was run with, for error messages. */
  51. char *program_name;
  52.  
  53. /* If non-zero, display usage information and exit.  */
  54. static int show_help;
  55.  
  56. /* If non-zero, print the version on standard output and exit.  */
  57. static int show_version;
  58.  
  59. /* If non-zero, print or set Coordinated Universal Time.  */
  60. static int universal_time = 0;
  61.  
  62. static struct option const long_options[] =
  63. {
  64.   {"date", required_argument, NULL, 'd'},
  65.   {"file", required_argument, NULL, 'f'},
  66.   {"help", no_argument, &show_help, 1},
  67.   {"set", required_argument, NULL, 's'},
  68.   {"uct", no_argument, NULL, 'u'},
  69.   {"utc", no_argument, NULL, 'u'},
  70.   {"universal", no_argument, NULL, 'u'},
  71.   {"version", no_argument, &show_version, 1},
  72.   {NULL, 0, NULL, 0}
  73. };
  74.  
  75. /* Parse each line in INPUT_FILENAME as with --date and display the
  76.    each resulting time and date.  If the file cannot be opened, tell why
  77.    then exit.  Issue a diagnostic for any lines that cannot be parsed.
  78.    If any line cannot be parsed, return non-zero;  otherwise return zero.  */
  79.  
  80. static int
  81. batch_convert (input_filename, format)
  82.      const char *input_filename;
  83.      const char *format;
  84. {
  85.   int have_read_stdin;
  86.   int status;
  87.   FILE *in_stream;
  88.   char *line;
  89.   int line_length;
  90.   int buflen;
  91.   time_t when;
  92.  
  93.   if (strcmp (input_filename, "-") == 0)
  94.     {
  95.       input_filename = "standard input";
  96.       in_stream = stdin;
  97.       have_read_stdin = 1;
  98.     }
  99.   else
  100.     {
  101.       in_stream = fopen (input_filename, "r");
  102.       if (in_stream == NULL)
  103.     {
  104.       error (0, errno, "%s", input_filename);
  105.     }
  106.       have_read_stdin = 0;
  107.     }
  108.  
  109.   line = NULL;
  110.   buflen = 0;
  111.  
  112.   status = 0;
  113.   while (1)
  114.     {
  115.       line_length = getline (&line, &buflen, in_stream);
  116.       if (line_length < 0)
  117.     {
  118.       /* FIXME: detect/handle error here.  */
  119.       break;
  120.     }
  121.       when = get_date (line, NULL);
  122.       if (when == -1)
  123.     {
  124.       error (0, 0, "invalid date `%s'", line);
  125.       status = 1;
  126.     }
  127.       else
  128.     {
  129.       show_date (format, when);
  130.     }
  131.     }
  132.  
  133.   if (have_read_stdin && fclose (stdin) == EOF)
  134.     error (2, errno, "standard input");
  135.  
  136.   if (line != NULL)
  137.     free (line);
  138.  
  139.   return status;
  140. }
  141.  
  142. main (argc, argv)
  143.      int argc;
  144.      char **argv;
  145. {
  146.   int optc;
  147.   const char *datestr = NULL;
  148.   time_t when;
  149.   int set_date = 0;
  150.   int print_date = 0;
  151.   char *format;
  152.   char *batch_file = NULL;
  153.   int n_args;
  154.   int status;
  155.  
  156.   program_name = argv[0];
  157.  
  158.   while ((optc = getopt_long (argc, argv, "d:f:s:u", long_options, (int *) 0))
  159.      != EOF)
  160.     switch (optc)
  161.       {
  162.       case 0:
  163.     break;
  164.       case 'd':
  165.     datestr = optarg;
  166.     print_date = 1;
  167.     break;
  168.       case 'f':
  169.     batch_file = optarg;
  170.     break;
  171.       case 's':
  172.     datestr = optarg;
  173.     set_date = 1;
  174.     break;
  175.       case 'u':
  176.     universal_time = 1;
  177.     break;
  178.       default:
  179.     usage (1);
  180.       }
  181.  
  182.   if (show_version)
  183.     {
  184.       printf ("date - %s\n", version_string);
  185.       exit (0);
  186.     }
  187.  
  188.   if (show_help)
  189.     usage (0);
  190.  
  191.   n_args = argc - optind;
  192.  
  193.   if (set_date && print_date)
  194.     {
  195.       error (0, 0,
  196.       "the options to print and set the time may not be used together");
  197.       usage (1);
  198.     }
  199.  
  200.   if (n_args > 1)
  201.     {
  202.       error (0, 0, "too many non-option arguments");
  203.       usage (1);
  204.     }
  205.  
  206.   if ((set_date || print_date || batch_file != NULL)
  207.       && n_args == 1 && argv[optind][0] != '+')
  208.     {
  209.       error (0, 0, "\
  210. when using the print, set time, or batch options, any\n\
  211. non-option argument must be a format string beginning with `+'");
  212.       usage (1);
  213.     }
  214.  
  215.   if (batch_file != NULL)
  216.     {
  217.       if (set_date || print_date)
  218.     {
  219.       error (0, 0, "\
  220. neither print nor set options may be used when reading dates from a file");
  221.       usage (1);
  222.     }
  223.       status = batch_convert (batch_file,
  224.                   (n_args == 1 ? argv[optind] + 1 : NULL));
  225.     }
  226.   else
  227.     {
  228.       status = 0;
  229.  
  230.       if (!print_date && !set_date)
  231.     {
  232.       if (n_args == 1 && argv[optind][0] != '+')
  233.         {
  234.           /* Prepare to set system clock to the specified date/time
  235.          given in the POSIX-format.  */
  236.           set_date = 1;
  237.           datestr = argv[optind];
  238.           when = posixtime (datestr);
  239.           format = NULL;
  240.         }
  241.       else
  242.         {
  243.           /* Prepare to print the current date/time.  */
  244.           print_date = 1;
  245.           datestr = "undefined";
  246.           time (&when);
  247.           format = (n_args == 1 ? argv[optind] + 1 : NULL);
  248.         }
  249.     }
  250.       else
  251.     {
  252.       /* (print_date || set_date) */
  253.       when = get_date (datestr, NULL);
  254.       format = (n_args == 1 ? argv[optind] + 1 : NULL);
  255.     }
  256.  
  257.       if (when == -1)
  258.     error (1, 0, "invalid date `%s'", datestr);
  259.  
  260.       if (set_date)
  261.     {
  262.       /* Set the system clock to the specified date, then regardless of
  263.          the success of that operation, format and print that date.  */
  264.       if (stime (&when) == -1)
  265.         error (0, errno, "cannot set date");
  266.     }
  267.  
  268.       show_date (format, when);
  269.     }
  270.  
  271.   if (fclose (stdout) == EOF)
  272.     error (2, errno, "write error");
  273.  
  274.   exit (status);
  275. }
  276.  
  277. /* Display the date and/or time in WHEN according to the format specified
  278.    in FORMAT, followed by a newline.  If FORMAT is NULL, use the
  279.    standard output format (ctime style but with a timezone inserted). */
  280.  
  281. static void
  282. show_date (format, when)
  283.      const char *format;
  284.      time_t when;
  285. {
  286.   struct tm *tm;
  287.   char *out = NULL;
  288.   size_t out_length = 0;
  289.  
  290.   tm = (universal_time ? gmtime : localtime) (&when);
  291.  
  292.   if (format == NULL)
  293.     {
  294.       /* Print the date in the default format.  Vanilla ANSI C strftime
  295.          doesn't support %e, but POSIX requires it.  If you don't use
  296.          a GNU strftime, make sure yours supports %e.  */
  297.       format = (universal_time
  298.         ? "%a %b %e %H:%M:%S UTC %Y"
  299.         : "%a %b %e %H:%M:%S %Z %Y");
  300.     }
  301.   else if (*format == '\0')
  302.     {
  303.       printf ("\n");
  304.       return;
  305.     }
  306.  
  307.   do
  308.     {
  309.       out_length += 200;
  310.       out = (char *) xrealloc (out, out_length);
  311.     }
  312.   while (strftime (out, out_length, format, tm) == 0);
  313.  
  314.   printf ("%s\n", out);
  315.   free (out);
  316. }
  317.  
  318. static void
  319. usage (status)
  320.      int status;
  321. {
  322.   if (status != 0)
  323.     fprintf (stderr, "Try `%s --help' for more information.\n",
  324.          program_name);
  325.   else
  326.     {
  327.       printf ("\
  328. Usage: %s [OPTION]... [+FORMAT]\n\
  329.   or:  %s [OPTION] [MMDDhhmm[[CC]YY][.ss]]\n\
  330. ",
  331.           program_name, program_name);
  332.       printf ("\
  333. \n\
  334.   -d, --date=STRING        display time described by STRING, not `now'\n\
  335.   -f, --file=DATEFILE      like --date once for each line of DATEFILE\n\
  336.   -s, --set=STRING         set time described by STRING\n\
  337.   -u, --utc, --universal   print or set Coordinated Universal Time\n\
  338.       --help               display this help and exit\n\
  339.       --version            output version information and exit\n\
  340. ");
  341.       printf ("\
  342. \n\
  343. FORMAT controls the output.  The only valid option for the second form\n\
  344. specifies Coordinated Universal Time.  Interpreted sequences are:\n\
  345. \n\
  346.   %%%%   a literal %%\n\
  347.   %%a   locale's abbreviated weekday name (Sun..Sat)\n\
  348.   %%A   locale's full weekday name, variable length (Sunday..Saturday)\n\
  349.   %%b   locale's abbreviated month name (Jan..Dec)\n\
  350.   %%B   locale's full month name, variable length (January..December)\n\
  351.   %%c   locale's date and time (Sat Nov 04 12:02:33 EST 1989)\n\
  352.   %%d   day of month (01..31)\n\
  353.   %%D   date (mm/dd/yy)\n\
  354.   %%h   same as %%b\n\
  355.   %%H   hour (00..23)\n\
  356.   %%I   hour (01..12)\n\
  357.   %%j   day of year (001..366)\n\
  358.   %%k   hour ( 0..23)\n\
  359.   %%l   hour ( 1..12)\n\
  360.   %%m   month (01..12)\n\
  361.   %%M   minute (00..59)\n\
  362.   %%n   a newline\n\
  363.   %%p   locale's AM or PM\n\
  364.   %%r   time, 12-hour (hh:mm:ss [AP]M)\n\
  365.   %%s   seconds since 00:00:00, Jan 1, 1970 (a GNU extension)\n\
  366.   %%S   second (00..61)\n\
  367.   %%t   a horizontal tab\n\
  368.   %%T   time, 24-hour (hh:mm:ss)\n\
  369.   %%U   week number of year with Sunday as first day of week (00..53)\n\
  370.   %%w   day of week (0..6);  0 represents Sunday\n\
  371.   %%W   week number of year with Monday as first day of week (00..53)\n\
  372.   %%x   locale's date representation (mm/dd/yy)\n\
  373.   %%X   locale's time representation (%%H:%%M:%%S)\n\
  374.   %%y   last two digits of year (00..99)\n\
  375.   %%Y   year (1970...)\n\
  376.   %%Z   time zone (e.g., EDT), or nothing if no time zone is determinable\n\
  377. \n\
  378. By default, `date' pads numeric fields with zeroes.  GNU `date'\n\
  379. recognizes the following nonstandard modifiers between `%%' and a\n\
  380. numeric directive.\n\
  381. \n\
  382.   `-' (hyphen) do not pad the field\n\
  383.   `_' (underscore) pad the field with spaces\n\
  384. ");
  385.     }
  386.   exit (status);
  387. }
  388.