Browse Source

Fix #3 Add support for relative dates

Date formats

        Two date formats are allowed for dates arguments (-d , -m) :
        - the same than in the logfile
        - relative from now prefixing the argument with '#-' and given a unit
                - y : year
                - M : Month
                - d : day
                - h : hour
                - m : min
                - s : sec
Yann Weber 7 years ago
parent
commit
5e527d0f3b
2 changed files with 285 additions and 24 deletions
  1. 65
    0
      src/include/ttail_init.h
  2. 220
    24
      src/ttail_init.c

+ 65
- 0
src/include/ttail_init.h View File

@@ -44,6 +44,27 @@ POSIX) ",NULL},\
44 44
 	{"",NULL}\
45 45
 }
46 46
 
47
+#define TTAIL_HELP_TEXT "\tLOGFILES\n\t\tLogfiles, can take '-' as value to \
48
+tell ttail to read from stdin instead of files\n\n\
49
+Date formats\n\n\
50
+\tTwo date formats are allowed for dates arguments (-d , -m) :\n\
51
+\t- the same than in the logfile\n\
52
+\t- relative from now prefixing the argument with '#-' and given a unit\n\
53
+\t\t- y : year\n\
54
+\t\t- M : Month\n\
55
+\t\t- d : day\n\
56
+\t\t- h : hour\n\
57
+\t\t- m : min\n\
58
+\t\t- s : sec\n\
59
+"
60
+
61
+#define TTAIL_NORMDATE(ttail,tm,FIELD) {\
62
+	if(ttail->flag & TTAIL_FLAG_DATE_MIN && (tm)->FIELD == -1)\
63
+	{ ttail->date_min.FIELD = -1; }\
64
+	if(ttail->flag & TTAIL_FLAG_DATE_MAX && (tm)->FIELD == -1)\
65
+	{ ttail->date_max.FIELD = -1; }\
66
+}
67
+
47 68
 /**<! Print help & usage */
48 69
 void usage();
49 70
 
@@ -220,6 +241,50 @@ int ttail_set_flag_re_ci(ttail_t*);
220 241
  */
221 242
 int ttail_set_dates(ttail_t*, char*[2]);
222 243
 
244
+/**@brief Set a date using format or format detection
245
+ *
246
+ *@param ttail_t ttail instance
247
+ *@param char*[2] dates {min,max} both can be NULL
248
+ *@param int c the date id to handle
249
+ *@return -1 if error 0 else
250
+ */
251
+int _ttail_set_date_fmt(ttail_t*, char*, int);
252
+
253
+/**@brief Set a date relative from now
254
+ *
255
+ *Relative date formats are "-#", an integer followed by a unit. Regcognized
256
+ *units are :
257
+ *- y[ear]
258
+ *- M[onth]
259
+ *- d[ay]
260
+ *- h[our]
261
+ *- m[in]
262
+ *- s[ec]
263
+ *
264
+ *Examples :
265
+ *- -#2s
266
+ *- -#3Month
267
+ *@param ttail_t ttail instance
268
+ *@param char*[2] dates {min,max} both can be NULL
269
+ *@param int c the date id to handle
270
+ *@return -1 if error 0 else
271
+ *@todo checks
272
+ */
273
+int _ttail_set_date_relative(ttail_t*, char*, int);
274
+
275
+/**@brief Normalize dates
276
+ *
277
+ *When dates are relatives from now all the struct tm fields are set. In 
278
+ *logfiles year or seconds can be missing from date format. In those case we 
279
+ *have to set to -1 missing fields
280
+ *@note must be called after arg parsing, ttail_set_dates() calls and
281
+ *ttail_format_guess() calls
282
+ *@param ttail_t* An initialized ttail_t
283
+ *@return -1 if error 0 else
284
+ *@todo checks
285
+ */
286
+int _ttail_norm_dates(ttail_t*);
287
+
223 288
 /**@brief Attempt to guess a dateformat
224 289
  *@param ttail_t* ttail if manage to guess set the ttail_t.fmt
225 290
  *@param const char* date as a dtring

+ 220
- 24
src/ttail_init.c View File

@@ -29,8 +29,7 @@ void usage()
29 29
 		printf("\t\t%s\n\n", help[i][0]);
30 30
 		i++;
31 31
 	}
32
-	printf("\tLOGFILES\n\t\tLogfiles, can take '-' as value to tell ttail \
33
-to read from stdin instead of files\n");
32
+	printf(TTAIL_HELP_TEXT);
34 33
 }
35 34
 
36 35
 ttail_t *ttail_init(int argc, char **argv)
@@ -398,33 +397,19 @@ int ttail_set_dates(ttail_t* res, char* dates[2])
398 397
 		{
399 398
 			continue;
400 399
 		}
401
-		if(!(res->flag & TTAIL_FLAG_FORMAT))
400
+		date = dates[c];
401
+		if(!strncmp(date, "#-", 2))
402 402
 		{
403
-			/* no format specified */
404
-			ret = ttail_format_guess(res, dates[c],
405
-				c==0?&(res->date_min):&(res->date_max));
406
-			if(ret < 0)
407
-			{
408
-				fprintf(stderr, "Unable to guess format for \
409
-date '%s'\n", dates[c]);
410
-				return -1;
411
-			}
412
-			res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
413
-			continue;
403
+			/* relative date */
404
+			ret = _ttail_set_date_relative(res, date, c);
414 405
 		}
415
-		date = strptime(dates[c], res->fmt, 
416
-			c==0?&(res->date_min):&(res->date_max));
417
-		if(!date)
406
+		else
418 407
 		{
419
-			fprintf(stderr, "Unable to parse date-%s '%s' with \
420
-format '%s'\n", c==0?"min":"max", dates[c], res->fmt);
421
-			return -1;
408
+			/* date from format */
409
+			ret = _ttail_set_date_fmt(res, date, c);
422 410
 		}
423
-		else if(*date != '\0')
411
+		if(ret < 0)
424 412
 		{
425
-			fprintf(stderr, "Leading caracters for date-%s : '%s' \
426
-is not matched in '%s'\n",\
427
-				c==0?"min":"max", date, dates[c]);
428 413
 			return -1;
429 414
 		}
430 415
 		res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
@@ -436,6 +421,217 @@ is not matched in '%s'\n",\
436 421
 	return 0;
437 422
 }
438 423
 
424
+int _ttail_set_date_fmt(ttail_t* res, char* date, int c)
425
+{
426
+	int ret;
427
+	char *endp;
428
+
429
+	if(!(res->flag & TTAIL_FLAG_FORMAT))
430
+	{
431
+		/* no format specified */
432
+		ret = ttail_format_guess(res, date,
433
+			c==0?&(res->date_min):&(res->date_max));
434
+		if(ret < 0)
435
+		{
436
+			fprintf(stderr, "Unable to guess format for \
437
+date '%s'\n", date);
438
+			return -1;
439
+		}
440
+		res->flag |= c?TTAIL_FLAG_DATE_MAX:TTAIL_FLAG_DATE_MIN;
441
+		return 0;
442
+	}
443
+	endp = strptime(date, res->fmt, 
444
+		c==0?&(res->date_min):&(res->date_max));
445
+	if(!endp)
446
+	{
447
+		fprintf(stderr, "Unable to parse date-%s '%s' with \
448
+format '%s'\n", c==0?"min":"max", date, res->fmt);
449
+		return -1;
450
+	}
451
+	else if(*endp != '\0')
452
+	{
453
+		fprintf(stderr, "Leading caracters for date-%s : '%s' \
454
+is not matched in '%s'\n",\
455
+			c==0?"min":"max", endp, date);
456
+		return -1;
457
+	}
458
+	return 0;
459
+}
460
+int _ttail_set_date_relative(ttail_t* res, char* date, int c)
461
+{
462
+	time_t now;
463
+	char *unit;
464
+	int value;
465
+	struct tm *tm, *tm_p;
466
+	short mod;
467
+	
468
+	tm = c==0?&(res->date_min):&(res->date_max);
469
+	ttail_tm_init(tm);
470
+	if(time(&now) < 0)
471
+	{
472
+		fprintf(stderr, "Unable to retrieve time using time()\n");
473
+		return -1;
474
+	}
475
+	if(!(tm_p = localtime(&now)))
476
+	{
477
+		fprintf(stderr, "Unable to retrieve localtime using localtime()\n");
478
+		return -1;
479
+	}
480
+
481
+	memcpy(tm, tm_p, sizeof(struct tm));
482
+
483
+	mod = 0;
484
+	unit = NULL;
485
+	value = (int)strtol(date+2, &unit, 10);
486
+	switch(*unit)
487
+	{
488
+		case 's':
489
+			if(*(unit+1) == '\0' || !strcmp(unit, "sec"))
490
+			{
491
+				tm->tm_sec -= value;
492
+				if(tm->tm_sec < 0)
493
+				{
494
+					mod = 1;
495
+					value = abs(tm->tm_sec);
496
+					tm->tm_sec = 60 - (value % 60);
497
+					value /= 60;
498
+					value++;
499
+				}
500
+				if(!mod)
501
+				{
502
+					break;
503
+				}
504
+			}
505
+		case 'm':
506
+			if(mod || *(unit+1) == '\0' || !strcmp(unit, "min"))
507
+			{
508
+				mod = 0;
509
+				tm->tm_min -= value;
510
+				if(tm->tm_min < 0)
511
+				{
512
+					mod = 1;
513
+					value = abs(tm->tm_min);
514
+					tm->tm_min = 60 - (value % 60);
515
+					value /= 60;
516
+					value++;
517
+					printf("Value left : %d\n", value);
518
+				}
519
+				if(!mod)
520
+				{
521
+					break;
522
+				}
523
+			}
524
+		case 'h':
525
+			if(mod || *(unit+1) == '\0' || !strcmp(unit, "hour"))
526
+			{
527
+				mod = 0;
528
+				tm->tm_hour -= value;
529
+				if(tm->tm_hour < 0)
530
+				{
531
+					mod = 1;
532
+					value = abs(tm->tm_hour);
533
+					tm->tm_hour = 24 - (value % 24);
534
+					value /= 24;
535
+					value++;
536
+				}
537
+				if(!mod)
538
+				{
539
+					break;
540
+				}
541
+			}
542
+		case 'd':
543
+			if(mod || *(unit+1) == '\0' || !strcmp(unit, "day"))
544
+			{
545
+				mod = 0;
546
+				tm->tm_mday -= value;
547
+				if(tm->tm_mday < 0)
548
+				{
549
+					mod = 1;
550
+					value = abs(tm->tm_mday);
551
+					tm->tm_mday = 31 - (value % 31);
552
+					value /= 31;
553
+					value++;
554
+				}
555
+				if(!mod)
556
+				{
557
+					break;
558
+				}
559
+			}
560
+		case 'M':
561
+			if(*(unit+1) == '\0' || !strcmp(unit, "Month"))
562
+			{
563
+				mod = 0;
564
+				tm->tm_mon -= value;
565
+				if(tm->tm_mon < 0)
566
+				{
567
+					mod = 1;
568
+					value = abs(tm->tm_mon);
569
+					tm->tm_mon = 12 - (value % 12);
570
+					value /= 12;
571
+					value++;
572
+				}
573
+				if(!mod)
574
+				{
575
+					break;
576
+				}
577
+			}
578
+		case 'y':
579
+			if(mod || *(unit+1) == '\0' || !strcmp(unit, "year"))
580
+			{
581
+				tm->tm_year -= value;
582
+				break;
583
+			}
584
+		default:
585
+			fprintf(stderr,"Invalid relative date '%s'\n", date);
586
+			return -1;
587
+	}
588
+	return 0;
589
+
590
+}
591
+
592
+int _ttail_norm_dates(ttail_t* ttail)
593
+{
594
+	struct tm *tm_p, tm;
595
+	/* Huge buffer but no way to make a difference between error and
596
+	   buffer too small using strftime */
597
+	char date[4096], *endp;
598
+	size_t date_len;
599
+	time_t now;
600
+
601
+	if(time(&now) < 0)
602
+	{
603
+		perror("Unable to retrieve time using time()\n");
604
+		return -1;
605
+	}
606
+	if(!(tm_p = localtime(&now)))
607
+	{
608
+		perror("Unable to retrieve localtime using localtime()\n");
609
+		return -1;
610
+	}
611
+	if(!(date_len = strftime(date, sizeof(date), ttail->fmt, tm_p)))
612
+	{
613
+		fprintf(stderr, "Unable to print the current date using strftime()\n");
614
+		return -1;
615
+	}
616
+	ttail_tm_init(&tm);
617
+	endp = strptime(date, ttail->fmt, &tm);
618
+	if(!endp || *endp != '\0')
619
+	{
620
+		fprintf(stderr, "An error occured, unable to strptime() a date\
621
+we just strftime() !\n");
622
+		exit(EXIT_FAILURE);
623
+	}
624
+	
625
+	TTAIL_NORMDATE(ttail, &tm, tm_sec);
626
+	TTAIL_NORMDATE(ttail, &tm, tm_min);
627
+	TTAIL_NORMDATE(ttail, &tm, tm_hour);
628
+	TTAIL_NORMDATE(ttail, &tm, tm_mday);
629
+	TTAIL_NORMDATE(ttail, &tm, tm_mon);
630
+	TTAIL_NORMDATE(ttail, &tm, tm_year);
631
+	
632
+	return 0;
633
+}
634
+
439 635
 int ttail_format_guess(ttail_t* t, const char* date_str, struct tm* tm)
440 636
 {
441 637
 	int i, res;

Loading…
Cancel
Save