/* ** This C program generates the "VERSION.h" header file from information ** extracted out of the "manifest", "manifest.uuid", and "VERSION" files. ** Call this program with three arguments: ** ** ./a.out manifest.uuid manifest VERSION ** ** Note that the manifest.uuid and manifest files are generated by Fossil. ** ** The output becomes the "VERSION.h" file. The output is a C-language ** header that contains #defines for various properties of the build: ** ** MANIFEST_UUID These values are text strings that ** MANIFEST_VERSION identify the Fossil check-in to which ** the source tree belongs. They do not ** take into account any uncommitted edits. ** ** FOSSIL_BUILD_HASH A hexadecimal string that is a strong hash ** of the MANIFEST_UUID together with the ** current time of the build. We normally want ** this to be different on each build, as the ** value is used to expire ETag: fields in ** HTTP requests. But if you need to do ** repeatable byte-for-byte identical builds, ** add the -DFOSSIL_BUILD_EPOCH=n option. ** ** MANIFEST_DATE The date/time of the source-code check-in ** MANIFEST_YEAR in various formats. ** MANIFEST_NUMERIC_DATE ** MANIFEST_NUMERIC_TIME ** ** RELEASE_VERSION The version number (from the VERSION source ** RELEASE_VERSION_NUMBER file) in various format. ** RELEASE_RESOURCE_VERSION ** ** New #defines may be added in the future. */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <time.h> #if defined(_MSC_VER) && (_MSC_VER < 1800) /* MSVS 2013 */ # define strtoll _strtoi64 #endif static FILE *open_for_reading(const char *zFilename){ FILE *f = fopen(zFilename, "r"); if( f==0 ){ fprintf(stderr, "cannot open \"%s\" for reading\n", zFilename); exit(1); } return f; } /* ** Given an arbitrary-length input string key zIn, generate ** an N-byte hexadecimal hash of that string into zOut. */ static void hash(const char *zIn, int N, char *zOut){ unsigned char i, j, t; int m, n; unsigned char s[256]; for(m=0; m<256; m++){ s[m] = m; } for(j=0, m=n=0; m<256; m++, n++){ j += s[m] + zIn[n]; if( zIn[n]==0 ){ n = -1; } t = s[j]; s[j] = s[m]; s[m] = t; } i = j = 0; for(n=0; n<N-2; n+=2){ i++; t = s[i]; j += t; s[i] = s[j]; s[j] = t; t += s[i]; zOut[n] = "0123456789abcdef"[(t>>4)&0xf]; zOut[n+1] = "0123456789abcdef"[t&0xf]; } zOut[n] = 0; } /* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */ static void local_strcpy(char *dest, const char *src){ while( (*(dest++) = *(src++))!=0 ){} } int main(int argc, char *argv[]){ FILE *m,*u,*v; char *z; #if defined(__DMC__) /* e.g. 0x857 */ int i = 0; #endif int j = 0, x = 0, d = 0; size_t n; int vn[3]; char b[1000]; char vx[1000]; if( argc!=4 ){ fprintf(stderr, "Usage: %s manifest.uuid manifest VERSION\n", argv[0]); exit(1); } memset(b,0,sizeof(b)); memset(vx,0,sizeof(vx)); u = open_for_reading(argv[1]); if( fgets(b, sizeof(b)-1,u)==0 ){ fprintf(stderr, "malformed manifest.uuid file: %s\n", argv[1]); exit(1); } fclose(u); for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} *z = 0; printf("#define MANIFEST_UUID \"%s\"\n",b); printf("#define MANIFEST_VERSION \"[%10.10s]\"\n",b); n = strlen(b); if( n + 50 < sizeof(b) ){ #ifdef FOSSIL_BUILD_EPOCH #define str(s) #s snprintf(b+n, sizeof(b)-n, "%d", (int)strtoll(str(FOSSIL_BUILD_EPOCH), 0, 10)); #else const char *zEpoch = getenv("SOURCE_DATE_EPOCH"); if( zEpoch && isdigit(zEpoch[0]) ){ snprintf(b+n, sizeof(b)-n, "%d", (int)strtoll(zEpoch, 0, 10)); }else{ snprintf(b+n, sizeof(b)-n, "%d", (int)time(0)); } #endif hash(b,33,vx); printf("#define FOSSIL_BUILD_HASH \"%s\"\n", vx); } m = open_for_reading(argv[2]); while(b == fgets(b, sizeof(b)-1,m)){ if(0 == strncmp("D ",b,2)){ int k, n; char zDateNum[30]; printf("#define MANIFEST_DATE \"%.10s %.8s\"\n",b+2,b+13); printf("#define MANIFEST_YEAR \"%.4s\"\n",b+2); n = 0; for(k=0; k<10; k++){ if( isdigit(b[k+2]) ) zDateNum[n++] = b[k+2]; } zDateNum[n] = 0; printf("#define MANIFEST_NUMERIC_DATE %s\n", zDateNum); n = 0; for(k=0; k<8; k++){ if( isdigit(b[k+13]) ) zDateNum[n++] = b[k+13]; } zDateNum[n] = 0; for(k=0; zDateNum[k]=='0'; k++){} printf("#define MANIFEST_NUMERIC_TIME %s\n", zDateNum+k); } } fclose(m); v = open_for_reading(argv[3]); if( fgets(b, sizeof(b)-1,v)==0 ){ fprintf(stderr, "malformed VERSION file: %s\n", argv[3]); exit(1); } fclose(v); for(z=b; z[0] && z[0]!='\r' && z[0]!='\n'; z++){} *z = 0; printf("#define RELEASE_VERSION \"%s\"\n", b); z=b; vn[0] = vn[1] = vn[2] = 0; while(1){ if( z[0]>='0' && z[0]<='9' ){ x = x*10 + z[0] - '0'; }else{ if( j<3 ) vn[j++] = x; x = 0; if( z[0]==0 ) break; } z++; } for(z=vx; z[0]=='0'; z++){} printf("#define RELEASE_VERSION_NUMBER %d%02d%02d\n", vn[0], vn[1], vn[2]); memset(vx,0,sizeof(vx)); local_strcpy(vx,b); for(z=vx; z[0]; z++){ if( z[0]=='-' ){ z[0] = 0; break; } if( z[0]!='.' ) continue; if ( d<3 ){ z[0] = ','; d++; }else{ z[0] = '\0'; break; } } printf("#define RELEASE_RESOURCE_VERSION %s", vx); while( d<3 ){ printf(",0"); d++; } printf("\n"); #if defined(__DMC__) /* e.g. 0x857 */ d = (__DMC__ & 0xF00) >> 8; /* major */ x = (__DMC__ & 0x0F0) >> 4; /* minor */ i = (__DMC__ & 0x00F); /* revision */ printf("#define COMPILER_VERSION \"%d.%d.%d\"\n", d, x, i); #elif defined(__POCC__) /* e.g. 700 */ d = (__POCC__ / 100); /* major */ x = (__POCC__ % 100); /* minor */ printf("#define COMPILER_VERSION \"%d.%02d\"\n", d, x); #elif defined(_MSC_VER) /* e.g. 1800 */ /* _MSC_FULL_VER also defined, e.g. 193030709 */ d = (_MSC_VER / 100); /* major */ x = (_MSC_VER % 100); /* minor */ printf("#define COMPILER_VERSION \"%d.%02d.", d, x); printf("%05d\"\n",(int)(_MSC_FULL_VER % 100000)); /* build (patch) */ #endif return 0; }