43 "\nusage: prune_tsv [options] <past-date-offset>\n\n"
45 " This program removes lines read from stdin that contain a timestamp\n"
46 " or date string representing a date that is older than the current time\n"
47 " minus <past-date-offset>. The <past-date-offset> argument can be specified\n"
48 " as days, months, or years (examples: 1y, 6m, 21d). The --field option\n"
49 " can be used to select the tab delimted field to search (default == 0). If\n"
50 " the field contains all digits, then it is interpreted as nanoseconds since\n"
51 " the epoch (or seconds if --seconds option is supplied). Otherwise, the\n"
52 " field is searched for the pattern YYYY-MM-DD, which is taken to be the date.\n\n"
55 struct AppPolicy :
Policy {
56 static void init_options() {
58 (
"field",
i32()->default_value(0),
"Field number of each line to parse")
59 (
"newer",
boo()->zero_tokens()->default_value(
false),
60 "Remove lines that are newer than calculated cutoff date")
61 (
"seconds",
boo()->zero_tokens()->default_value(
false),
62 "Interpret all-digit fields as seconds instead of nanoseconds")
63 (
"zhack",
boo()->zero_tokens()->default_value(
false),
"")
69 if (!
has(
"past-date-offset")) {
71 quick_exit(EXIT_FAILURE);
76 typedef Meta::list<AppPolicy, DefaultCommPolicy>
Policies;
78 inline char *get_field(
char *line,
int fieldno,
char **endptr) {
79 char *ptr, *base = line;
81 ptr = strchr(base,
'\t');
82 while (fieldno && ptr) {
85 ptr = strchr(base,
'\t');
98 inline const char *find_date(
const char *
str,
bool *formattedp) {
99 const char *slash =
str;
100 bool alldigits =
true;
102 while (*slash !=
'-' && *slash !=
'\t' && *slash !=
'\n' && *slash) {
103 if (!isdigit(*slash))
109 if (alldigits && slash > str) {
117 if (slash - str > 4 &&
118 isdigit(*(slash-4)) &&
119 isdigit(*(slash-3)) &&
120 isdigit(*(slash-2)) &&
121 isdigit(*(slash-1)) &&
122 isdigit(*(slash+1)) &&
123 isdigit(*(slash+2)) &&
125 isdigit(*(slash+4)) &&
126 isdigit(*(slash+5))) {
130 }
while ((slash = strchr(slash+1,
'-')) != 0);
135 inline time_t find_seconds(
const char *str) {
136 const char *period = strchr(str,
'.');
141 const char *ptr = period;
142 while (ptr > str && isdigit(*(ptr-1)))
145 return strtol(ptr, 0, 10);
148 time_t parse_date_offset(
const char *str) {
149 time_t date_offset = 0;
151 long n = strtol(str, &end, 10);
153 if (end == str || *end ==
'\0') {
154 cout <<
"\nERROR: Invalid <past-date-offset> argument: " << str <<
"\n" << endl;
155 quick_exit(EXIT_FAILURE);
158 if (*end ==
'd' || *end ==
'D')
159 date_offset = n * 24 * 60 * 60;
160 else if (*end ==
'm' || *end ==
'M')
161 date_offset = n * 30 * 24 * 60 * 60;
162 else if (*end ==
'y' || *end ==
'Y')
163 date_offset = n * 365 * 24 * 60 * 60;
165 cout <<
"\nERROR: Invalid <past-date-offset> argument: " << str <<
"\n" << endl;
166 quick_exit(EXIT_FAILURE);
177 int main(
int argc,
char **argv) {
178 string date_offset_str;
181 time_t date_offset, cutoff_time, line_time;
186 bool seconds =
false;
189 char *line_buffer =
new char [ 1024 * 1024 ];
191 ios::sync_with_stdio(
false);
194 init_with_policies<Policies>(argc, argv);
196 field = get_i32(
"field");
198 date_offset_str = get_str(
"past-date-offset");
199 date_offset = parse_date_offset(date_offset_str.c_str());
200 newer = get_bool(
"newer");
201 seconds = get_bool(
"seconds");
203 cutoff_time = time(0) - date_offset;
205 if (get_bool(
"zhack")) {
209 cin.getline(line_buffer, 1024*1024);
210 if (cin.eof() && cin.gcount() <= 1)
212 if ((base = get_field(line_buffer, field, &end)) &&
213 (line_seconds = find_seconds(base)) &&
214 ((!newer && line_seconds < cutoff_time) ||
215 (newer && line_seconds > cutoff_time)))
219 cout << line_buffer <<
"\n";
223 localtime_r(&cutoff_time, &tm);
224 strftime(cutoff,
sizeof(cutoff),
"%F", &tm);
226 cin.getline(line_buffer, 1024*1024);
227 if (line_buffer[0] == 0)
229 if ((base = get_field(line_buffer, field, &end)) &&
230 (base = find_date(base, &formatted))) {
232 if ((!newer && memcmp(base, cutoff, 10) < 0) ||
233 (newer && memcmp(base, cutoff, 10) >= 0))
238 line_time = (time_t)strtoll(base, &end, 10);
240 line_time = (time_t)(strtoll(base, &end, 10) / 1000000000LL);
241 if ((!newer && (line_time < cutoff_time)) ||
242 (newer && (line_time >= cutoff_time)))
248 cout << line_buffer <<
"\n";
252 quick_exit(EXIT_SUCCESS);
254 catch (std::exception &e) {
255 cerr <<
"Error - " << e.what() << endl;
Declarations for configuration properties.
Interface and base of config policy.
void init(int argc, char *argv[], const Desc *desc=NULL)
Initialize with default policy.
Po::typed_value< String > * str(String *v=0)
Desc & cmdline_desc(const char *usage)
A macro which definds global functions like get_bool(), get_str(), get_i16() etc. ...
bool has(const String &name)
Check existence of a configuration value.
Po::typed_value< int32_t > * i32(int32_t *v=0)
Logging routines and macros.
Compatibility Macros for C/C++.
Po::typed_value< bool > * boo(bool *v=0)
Initialization helper for applications.
Meta::list< MyPolicy, DefaultPolicy > Policies
int main(int argc, char **argv)
Desc & cmdline_hidden_desc()
Get the command line hidden options description (for positional options)
PositionalDesc & cmdline_positional_desc()
Get the command line positional options description.