1 /* -*- mode:c; indent-tabs-mode:nil; c-basic-offset:2 -*-
2  * Author: Travis Cross <tc@traviscross.com>
3  */
4 
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/wait.h>
10 #include <time.h>
11 
12 static int show_unclean = 0;
13 
sys(char * buf,int buflen,char * cmd)14 static int sys(char *buf, int buflen, char *cmd) {
15   int i, p[2];
16   if (pipe(p)) return 255;
17   if (!(i=fork())) {
18     close(p[0]);
19     dup2(p[1],1);
20     close(p[1]);
21     execlp("sh","sh","-c",cmd,NULL);
22   } else {
23     int s, x=0;
24     close(p[1]);
25     waitpid(i,&s,0);
26     if (!(WIFEXITED(s))) return 255;
27     if (WEXITSTATUS(s)) return WEXITSTATUS(s);
28     if (buf) {
29       while (buflen>1 && (x=read(p[0],buf,buflen-1))>0) buf+=x,buflen-=x;
30       close(p[0]);
31       if (x<0) return 255;
32       *buf=0;
33     } else close(p[0]);
34   }
35   return 0;
36 }
37 
sys1(char * buf,int buflen,char * cmd)38 static int sys1(char *buf, int buflen, char *cmd) {
39   int r; char *c;
40   if ((r=sys(buf,buflen,cmd))) return r;
41   if ((c=strstr(buf,"\n"))) *c=0;
42   return 0;
43 }
44 
print_version(void)45 static int print_version(void) {
46   char xver[256], xdate[256], xfdate[256], xcommit[256];
47   time_t xdate_t; struct tm *xdate_tm;
48   if ((sys1(xdate,sizeof(xdate),"git log -n1 --format='%ct' HEAD"))) return 1;
49   xdate_t=(time_t)atoi(xdate);
50   if (!(xdate_tm=gmtime(&xdate_t))) return 1;
51   strftime(xfdate,sizeof(xfdate),"%Y%m%dT%H%M%SZ",xdate_tm);
52   if ((sys1(xcommit,sizeof(xcommit),"git rev-list -n1 --abbrev=10 --abbrev-commit HEAD")))
53     return 1;
54   snprintf(xver,sizeof(xver),"+git~%s~%s",xfdate,xcommit);
55   if (show_unclean && (sys(NULL,0,"git diff-index --quiet HEAD"))) {
56     char buf[256], now[256]; time_t now_t=time(NULL); struct tm *now_tm;
57     if (!(now_tm=gmtime(&now_t))) return 1;
58     strftime(now,sizeof(now),"%Y%m%dT%H%M%SZ",now_tm);
59     snprintf(buf,sizeof(buf),"%s+unclean~%s",xver,now);
60     strncpy(xver,buf,sizeof(xver));
61   }
62   printf("%s\n",xver);
63   return 0;
64 }
65 
print_human_version(void)66 static int print_human_version(void) {
67   char xver[256], xdate[256], xfdate[256], xcommit[256];
68   time_t xdate_t; struct tm *xdate_tm;
69   if ((sys1(xdate,sizeof(xdate),"git log -n1 --format='%ct' HEAD"))) return 1;
70   xdate_t=(time_t)atoi(xdate);
71   if (!(xdate_tm=gmtime(&xdate_t))) return 1;
72   strftime(xfdate,sizeof(xfdate),"%Y-%m-%d %H:%M:%SZ",xdate_tm);
73   if ((sys1(xcommit,sizeof(xcommit),"git rev-list -n1 --abbrev=7 --abbrev-commit HEAD")))
74     return 1;
75   snprintf(xver,sizeof(xver),"git %s %s",xcommit,xfdate);
76   if (show_unclean && (sys(NULL,0,"git diff-index --quiet HEAD"))) {
77     char buf[256], now[256]; time_t now_t=time(NULL); struct tm *now_tm;
78     if (!(now_tm=gmtime(&now_t))) return 1;
79     strftime(now,sizeof(now),"%Y-%m-%d %H:%M:%SZ",now_tm);
80     snprintf(buf,sizeof(buf),"%s unclean %s",xver,now);
81     strncpy(xver,buf,sizeof(xver));
82   }
83   printf("%s\n",xver);
84   return 0;
85 }
86 
main(int argc,char ** argv)87 int main(int argc, char **argv) {
88   if (argc > 1 && !strcasecmp(argv[1],"-h"))
89     return print_human_version();
90   else
91     return print_version();
92 }
93 
94