|
1
|
/* |
|
2
|
** This C program generates the "VERSION.h" header file from information |
|
3
|
** extracted out of the "manifest", "manifest.uuid", and "VERSION" files. |
|
4
|
** Call this program with three arguments: |
|
5
|
** |
|
6
|
** ./a.out manifest.uuid manifest VERSION |
|
7
|
** |
|
8
|
** Note that the manifest.uuid and manifest files are generated by Fossil. |
|
9
|
** |
|
10
|
** The output becomes the "VERSION.h" file. The output is a C-language |
|
11
|
** header that contains #defines for various properties of the build: |
|
12
|
** |
|
13
|
** MANIFEST_UUID These values are text strings that |
|
14
|
** MANIFEST_VERSION identify the Fossil check-in to which |
|
15
|
** the source tree belongs. They do not |
|
16
|
** take into account any uncommitted edits. |
|
17
|
** |
|
18
|
** FOSSIL_BUILD_HASH A hexadecimal string that is a strong hash |
|
19
|
** of the MANIFEST_UUID together with the |
|
20
|
** current time of the build. We normally want |
|
21
|
** this to be different on each build, as the |
|
22
|
** value is used to expire ETag: fields in |
|
23
|
** HTTP requests. But if you need to do |
|
24
|
** repeatable byte-for-byte identical builds, |
|
25
|
** add the -DFOSSIL_BUILD_EPOCH=n option. |
|
26
|
** |
|
27
|
** MANIFEST_DATE The date/time of the source-code check-in |
|
28
|
** MANIFEST_YEAR in various formats. |
|
29
|
** MANIFEST_NUMERIC_DATE |
|
30
|
** MANIFEST_NUMERIC_TIME |
|
31
|
** |
|
32
|
** RELEASE_VERSION The version number (from the VERSION source |
|
33
|
** RELEASE_VERSION_NUMBER file) in various format. |
|
34
|
** RELEASE_RESOURCE_VERSION |
|
35
|
** |
|
36
|
** New #defines may be added in the future. |
|
37
|
*/ |
|
38
|
#include <stdio.h> |
|
39
|
#include <string.h> |
|
40
|
#include <stdlib.h> |
|
41
|
#include <ctype.h> |
|
42
|
#include <time.h> |
|
43
|
|
|
44
|
#if defined(_MSC_VER) && (_MSC_VER < 1800) /* MSVS 2013 */ |
|
45
|
# define strtoll _strtoi64 |
|
46
|
#endif |
|
47
|
|
|
48
|
static FILE *open_for_reading(const char *zFilename){ |
|
49
|
FILE *f = fopen(zFilename, "r"); |
|
50
|
if( f==0 ){ |
|
51
|
fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); |
|
52
|
exit(1); |
|
53
|
} |
|
54
|
return f; |
|
55
|
} |
|
56
|
|
|
57
|
/* |
|
58
|
** Given an arbitrary-length input string key zIn, generate |
|
59
|
** an N-byte hexadecimal hash of that string into zOut. |
|
60
|
*/ |
|
61
|
static void hash(const char *zIn, int N, char *zOut){ |
|
62
|
unsigned char i, j, t; |
|
63
|
int m, n; |
|
64
|
unsigned char s[256]; |
|
65
|
for(m=0; m<256; m++){ s[m] = m; } |
|
66
|
for(j=0, m=n=0; m<256; m++, n++){ |
|
67
|
j += s[m] + zIn[n]; |
|
68
|
if( zIn[n]==0 ){ n = -1; } |
|
69
|
t = s[j]; |
|
70
|
s[j] = s[m]; |
|
71
|
s[m] = t; |
|
72
|
} |
|
73
|
i = j = 0; |
|
74
|
for(n=0; n<N-2; n+=2){ |
|
75
|
i++; |
|
76
|
t = s[i]; |
|
77
|
j += t; |
|
78
|
s[i] = s[j]; |
|
79
|
s[j] = t; |
|
80
|
t += s[i]; |
|
81
|
zOut[n] = "0123456789abcdef"[(t>>4)&0xf]; |
|
82
|
zOut[n+1] = "0123456789abcdef"[t&0xf]; |
|
83
|
} |
|
84
|
zOut[n] = 0; |
|
85
|
} |
|
86
|
|
|
87
|
/* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */ |
|
88
|
static void local_strcpy(char *dest, const char *src){ |
|
89
|
while( (*(dest++) = *(src++))!=0 ){} |
|
90
|
} |
|
91
|
|
|
92
|
int main(int argc, char *argv[]){ |
|
93
|
FILE *m,*u,*v; |
|
94
|
char *z; |
|
95
|
#if defined(__DMC__) /* e.g. 0x857 */ |
|
96
|
int i = 0; |
|
97
|
#endif |
|
98
|
int j = 0, x = 0, d = 0; |
|
99
|
size_t n; |
|
100
|
int vn[3]; |
|
101
|
char b[1000]; |
|
102
|
char vx[1000]; |
|
103
|
if( argc!=4 ){ |
|
104
|
fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]); |
|
105
|
exit(1); |
|
106
|
} |
|
107
|
memset(b,0,sizeof(b)); |
|
108
|
memset(vx,0,sizeof(vx)); |
|
109
|
u = open_for_reading(argv[1]); |
|
110
|
if( fgets(b, sizeof(b)-1,u)==0 ){ |
|
111
|
fprintf(stderr, "malformed manifest.uuid file: %s\n", argv[1]); |
|
112
|
exit(1); |
|
113
|
} |
|
114
|
fclose(u); |
|
115
|
for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} |
|
116
|
*z = 0; |
|
117
|
printf("#define MANIFEST_UUID \"%s\"\n",b); |
|
118
|
printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b); |
|
119
|
n = strlen(b); |
|
120
|
if( n + 50 < sizeof(b) ){ |
|
121
|
#ifdef FOSSIL_BUILD_EPOCH |
|
122
|
#define str(s) #s |
|
123
|
snprintf(b+n, sizeof(b)-n, |
|
124
|
"%d", (int)strtoll(str(FOSSIL_BUILD_EPOCH), 0, 10)); |
|
125
|
#else |
|
126
|
const char *zEpoch = getenv("SOURCE_DATE_EPOCH"); |
|
127
|
if( zEpoch && isdigit(zEpoch[0]) ){ |
|
128
|
snprintf(b+n, sizeof(b)-n, "%d", (int)strtoll(zEpoch, 0, 10)); |
|
129
|
}else{ |
|
130
|
snprintf(b+n, sizeof(b)-n, "%d", (int)time(0)); |
|
131
|
} |
|
132
|
#endif |
|
133
|
hash(b,33,vx); |
|
134
|
printf("#define FOSSIL_BUILD_HASH \"%s\"\n", vx); |
|
135
|
} |
|
136
|
m = open_for_reading(argv[2]); |
|
137
|
while(b == fgets(b, sizeof(b)-1,m)){ |
|
138
|
if(0 == strncmp("D ",b,2)){ |
|
139
|
int k, n; |
|
140
|
char zDateNum[30]; |
|
141
|
printf("#define MANIFEST_DATE \"%.10s %.8s\"\n",b+2,b+13); |
|
142
|
printf("#define MANIFEST_YEAR \"%.4s\"\n",b+2); |
|
143
|
n = 0; |
|
144
|
for(k=0; k<10; k++){ |
|
145
|
if( isdigit(b[k+2]) ) zDateNum[n++] = b[k+2]; |
|
146
|
} |
|
147
|
zDateNum[n] = 0; |
|
148
|
printf("#define MANIFEST_NUMERIC_DATE %s\n", zDateNum); |
|
149
|
n = 0; |
|
150
|
for(k=0; k<8; k++){ |
|
151
|
if( isdigit(b[k+13]) ) zDateNum[n++] = b[k+13]; |
|
152
|
} |
|
153
|
zDateNum[n] = 0; |
|
154
|
for(k=0; zDateNum[k]=='0'; k++){} |
|
155
|
printf("#define MANIFEST_NUMERIC_TIME %s\n", zDateNum+k); |
|
156
|
} |
|
157
|
} |
|
158
|
fclose(m); |
|
159
|
v = open_for_reading(argv[3]); |
|
160
|
if( fgets(b, sizeof(b)-1,v)==0 ){ |
|
161
|
fprintf(stderr, "malformed VERSION file: %s\n", argv[3]); |
|
162
|
exit(1); |
|
163
|
} |
|
164
|
fclose(v); |
|
165
|
for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} |
|
166
|
*z = 0; |
|
167
|
printf("#define RELEASE_VERSION \"%s\"\n", b); |
|
168
|
z=b; |
|
169
|
vn[0] = vn[1] = vn[2] = 0; |
|
170
|
while(1){ |
|
171
|
if( z[0]>='0' && z[0]<='9' ){ |
|
172
|
x = x*10 + z[0] - '0'; |
|
173
|
}else{ |
|
174
|
if( j<3 ) vn[j++] = x; |
|
175
|
x = 0; |
|
176
|
if( z[0]==0 ) break; |
|
177
|
} |
|
178
|
z++; |
|
179
|
} |
|
180
|
for(z=vx; z[0]=='0'; z++){} |
|
181
|
printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]); |
|
182
|
memset(vx,0,sizeof(vx)); |
|
183
|
local_strcpy(vx,b); |
|
184
|
for(z=vx; z[0]; z++){ |
|
185
|
if( z[0]=='-' ){ |
|
186
|
z[0] = 0; |
|
187
|
break; |
|
188
|
} |
|
189
|
if( z[0]!='.' ) continue; |
|
190
|
if ( d<3 ){ |
|
191
|
z[0] = ','; |
|
192
|
d++; |
|
193
|
}else{ |
|
194
|
z[0] = '\0'; |
|
195
|
break; |
|
196
|
} |
|
197
|
} |
|
198
|
printf("#define RELEASE_RESOURCE_VERSION %s", vx); |
|
199
|
while( d<3 ){ printf(",0"); d++; } |
|
200
|
printf("\n"); |
|
201
|
#if defined(__DMC__) /* e.g. 0x857 */ |
|
202
|
d = (__DMC__ & 0xF00) >> 8; /* major */ |
|
203
|
x = (__DMC__ & 0x0F0) >> 4; /* minor */ |
|
204
|
i = (__DMC__ & 0x00F); /* revision */ |
|
205
|
printf("#define COMPILER_VERSION \"%d.%d.%d\"\n", d, x, i); |
|
206
|
#elif defined(__POCC__) /* e.g. 700 */ |
|
207
|
d = (__POCC__ / 100); /* major */ |
|
208
|
x = (__POCC__ % 100); /* minor */ |
|
209
|
printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x); |
|
210
|
#elif defined(_MSC_VER) /* e.g. 1800 */ |
|
211
|
/* _MSC_FULL_VER also defined, e.g. 193030709 */ |
|
212
|
d = (_MSC_VER / 100); /* major */ |
|
213
|
x = (_MSC_VER % 100); /* minor */ |
|
214
|
printf("#define COMPILER_VERSION \"%d.%02d.", d, x); |
|
215
|
printf("%05d\"\n",(int)(_MSC_FULL_VER % 100000)); /* build (patch) */ |
|
216
|
#endif |
|
217
|
return 0; |
|
218
|
} |
|
219
|
|