chiark / gitweb /
rename recentact to lowvol
[inn-innduct.git] / expire / convdate.c
1 /*  $Id: convdate.c 6372 2003-05-31 19:48:28Z rra $
2 **
3 **  Convert date strings and numbers to numbers and strings.
4 */
5
6 #include "config.h"
7 #include "clibrary.h"
8 #include <ctype.h>
9 #include <time.h>
10
11 #include "inn/messages.h"
12 #include "libinn.h"
13
14 static const char usage[] = "\
15 Usage: convdate -n [date ...]\n\
16        convdate [-dl] -c [time ...]\n\
17        convdate [-dl] [-s] [date ...]\n\
18 \n\
19 convdate -n converts a date (in any format parseable by parsedate) to the\n\
20 number of seconds since epoch.  convdate -s does the same, but converts\n\
21 to a date string.  convdate -c converts seconds since epoch to a date\n\
22 string.  The default output is the output of ctime (normally the same format\n\
23 as returned by the date command).  If -d is given, the output is formatted\n\
24 as a valid Usenet article Date header.  If -l is given with -d, format the\n\
25 time in local time rather than UTC.  If no options are given, the -s\n\
26 behavior is the default; if no dates are given, the current time is used.\n";
27
28 /* Whether to format the output as a Date header. */
29 static bool date_format = false;
30
31 /* Whether to use local time instead of UTC. */
32 static bool date_local = false;
33
34
35 /*
36 **  Return true if the given string is entirely digits.
37 */
38 static bool
39 isdigits(const char *p)
40 {
41     for (; *p; p++)
42         if (!CTYPE(isdigit, *p))
43             return false;
44     return true;
45 }
46
47
48 /*
49 **  Print date corresponding to the provided time_t.  By default, the output
50 **  of ctime is printed, but if date_format is true, makedate is used
51 **  instead.  If date_local is true, format in local time; otherwise, use
52 **  UTC.  Returns success.
53 */
54 static bool
55 print_date(time_t date)
56 {
57     char date_buffer[128];
58     char *result;
59
60     if (date_format) {
61         if (!makedate(date, date_local, date_buffer, sizeof(date_buffer))) {
62             warn("can't format %ld", (long) date);
63             return false;
64         } else {
65             printf("%s\n", date_buffer);
66         }
67     } else {
68         result = ctime(&date);
69         if (result == NULL) {
70             warn("can't format %ld", (long) date);
71             return false;
72         } else {
73             printf("%s", result);
74         }
75     }
76     return true;
77 }
78
79
80 /*
81 **  The core function.  Given a string representing a date (in some format
82 **  given by the mode) and a mode ('s', 'n', or 'c', corresponding to the
83 **  basic three options to the program), convert the date and print the
84 **  output.  date may be NULL, in which case the current date is used.
85 **  Returns true if conversion was successful, false otherwise.
86 */
87 static bool
88 convdate(const char *date, char mode)
89 {
90     time_t seconds;
91
92     /* Convert the given date to seconds or obtain the current time. */
93     if (date == NULL) {
94         seconds = time(NULL);
95     } else if (mode == 'c') {
96         if (!isdigits(date)) {
97             warn("\"%s\" doesn't look like a number", date);
98             return false;
99         } else {
100             seconds = (time_t) atol(date);
101         }
102     } else {
103         seconds = parsedate((char *) date, NULL);
104         if (seconds == (time_t) -1) {
105             warn("can't convert \"%s\"", date);
106             return false;
107         }
108     }
109
110     /* Output the resulting date. */
111     if (mode == 'n') {
112         printf("%ld\n", (long) seconds);
113         return true;
114     } else {
115         return print_date(seconds);
116     }
117 }
118
119
120 int
121 main(int argc, char *argv[])
122 {
123     int option, status;
124     char *date;
125     char mode = '\0';
126
127     message_program_name = "convdate";
128
129     /* Parse options. */
130     while ((option = getopt(argc, argv, "cdhlns")) != EOF) {
131         switch (option) {
132         case 'h':
133             printf("%s\n", usage);
134             exit(0);
135             break;
136         case 'd':
137             date_format = true;
138             break;
139         case 'l':
140             date_local = true;
141             break;
142         case 'c':
143         case 'n':
144         case 's':
145             if (mode != 0) die("only one of -c, -n, or -s is allowed");
146             mode = option;
147             break;
148         default:
149             fprintf(stderr, "%s", usage);
150             exit(1);
151             break;
152         }
153     }
154     if (mode == '\0')
155         mode = 's';
156     argc -= optind;
157     argv += optind;
158
159     /* Perform the desired action for each provided argument. */
160     if (argc == 0) {
161         exit(convdate(NULL, mode) ? 0 : 1);
162     } else {
163         for (date = *argv, status = 0; date != NULL; date = *++argv)
164             status += (convdate(date, mode) ? 0 : 1);
165         exit(status);
166     }
167 }