-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathversion.c
More file actions
198 lines (185 loc) · 5.66 KB
/
version.c
File metadata and controls
198 lines (185 loc) · 5.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#if 0
gcc -s -O2 -o ./sz0version version.c hash.o
exit
#endif
// This program is used for generating the version.inc file
#include <err.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "hash.h"
static int major,minor,patch;
static int major0,minor0,patch0;
static char**files;
static int nfiles;
static unsigned char oldhash[32];
static unsigned char newhash[32];
static size_t copy_stream(FILE*in,FILE*out,size_t len) {
char buf[0x2000];
size_t t=0;
size_t n;
size_t s;
while(len) {
if(len>0x2000) n=0x2000; else n=len;
if(s=fread(buf,1,n,in)) fwrite(buf,1,s,out);
if(s<n) return s+t;
len-=n;
t+=s;
}
return t;
}
static void read_status(void) {
char*line=0;
size_t line_size=0;
int i;
FILE*f=fopen("version.status","r");
if(!f) err(1,"Cannot open version.status file");
if(getline(&line,&line_size,f)<=0) errx(1,"Error in status file");
sscanf(line,"%d.%d.%d",&major,&minor,&patch);
major0=major; minor0=minor; patch0=patch;
if(getline(&line,&line_size,f)<=0) errx(1,"Error in status file");
if(*line>=0x20) for(i=0;i<32;i++) {
if(!line[i+i] || !line[i+i+1]) errx(1,"Error in status file");
sscanf(line+i+i,"%02hhX",oldhash+i);
}
while(getline(&line,&line_size,f)>0) {
i=strlen(line);
while(i && line[i-1]<=0x20) line[--i]=0;
if(!*line || *line=='#') continue;
files=realloc(files,++nfiles*sizeof(char*));
if(!files) err(1,"Allocation failed");
if(!(files[nfiles-1]=strdup(line))) err(1,"Allocation failed");
}
fclose(f);
}
static void calculate(void) {
FILE*ff=hash_stream(HASH_SHA3_256,0,newhash);
FILE*f;
int i;
if(!ff) err(1,"Cannot open hash stream");
for(i=0;i<nfiles;i++) {
fprintf(ff,"\x1C%s\x02",files[i]);
f=fopen(files[i],"r");
if(!f) err(1,"Cannot open \"%s\" file",files[i]);
copy_stream(f,ff,-1);
fclose(f);
}
fclose(ff);
newhash[2]^=newhash[0];
newhash[3]^=newhash[1];
if(memcmp(newhash+2,oldhash+2,30)) {
newhash[0]=1;
newhash[1]=major+minor+patch;
} else {
newhash[0]=oldhash[0];
newhash[1]=oldhash[1];
}
}
static void show_status(void) {
int i;
printf("Version = %d.%d.%d\nOld hash = ",major,minor,patch);
for(i=0;i<32;i++) printf("%02X",oldhash[i]);
printf("\nNew hash = ");
for(i=0;i<32;i++) printf("%02X",newhash[i]);
putchar('\n');
}
static void write_status(void) {
int i;
FILE*f=fopen("version.status","w");
if(!f) err(1,"Cannot open version.status file for writing");
fprintf(f,"%d.%d.%d\n",major,minor,patch);
for(i=0;i<32;i++) fprintf(f,"%02X",newhash[i]);
fputc('\n',f);
for(i=0;i<nfiles;i++) fprintf(f,"%s\n",files[i]);
fclose(f);
}
static int encode_number(FILE*f,int n) {
// (This currently assumes that the pieces of the version number cannot exceed 16383, but it is unlikely to exceed 16383 anyways)
if(n>127) {
fprintf(f,"%d,%d,",(n>>7)+128,n&127);
return 2;
} else {
fprintf(f,"%d,",n);
return 1;
}
}
static void write_version_inc(void) {
int i,s;
FILE*f=fopen("version.inc","w");
if(!f) err(1,"Cannot open version.inc file for writing");
fprintf(f,"// Auto-generated file; see version.doc for instructions\n");
fprintf(f,"const Uint8 version_hash[32]={");
for(i=0;i<32;i++) fprintf(f,"%d,",newhash[i]);
fprintf(f,"};\n");
fprintf(f,"const Uint8 version_rel_oid[]={0,");
s=encode_number(f,major);
s+=encode_number(f,minor);
i=s;
s+=encode_number(f,patch);
fprintf(f,"};\n");
fprintf(f,"const Uint8 version_rel_oid_length=%d;\n",s+1);
fprintf(f,"const Uint8 version_rel_oid_length_2=%d;\n",i+1);
fprintf(f,"const Uint8 version_is_release=%d;\n",*newhash==2);
fprintf(f,"const char version_name[]=\"Super ZZ Zero\\nVersion %d.%d.%d%s\\n\";\n",major,minor,patch,*newhash==2?"":"(modified)");
fclose(f);
}
static void new_version(void) {
//TODO: Possibly handle major versions differently
//TODO: Possibly check if program has been compiled already, to avoid publishing untested versions
int i;
char buf[256];
printf("New version number = %d.%d.%d\n",major,minor,patch);
if(*newhash==2) errx(1,"Program has not changed; version number will not be changed");
*newhash=2;
i=snprintf(buf,256,"./maker main.mak && fossil commit --tag v%d.%d.%d",major,minor,patch);
if(major!=major0) i+=snprintf(buf+i,256-i," --tag major");
if(major!=major0 || minor!=minor0) i+=snprintf(buf+i,256-i," --tag minor");
if(major!=major0 || minor!=minor0 || patch!=patch0) i+=snprintf(buf+i,256-i," --tag patch");
puts(buf);
write_status();
write_version_inc();
i=system(buf);
if(WIFSIGNALED(i) || !WIFEXITED(i) || WEXITSTATUS(i)) {
warnx("New version canceled; reverting to %d.%d.%d",major0,minor0,patch0);
*newhash=1;
major=major0; minor=minor0; patch=patch0;
write_status();
write_version_inc();
if(!WIFSIGNALED(i) || WTERMSIG(i)!=SIGQUIT) -system("./maker main.mak");
}
if(WIFSIGNALED(i)) {
kill(getpid(),WTERMSIG(i));
errx(1,"Signal %d received from child",WTERMSIG(i));
}
if(!WIFEXITED(i) || WEXITSTATUS(i)) {
errx(WEXITSTATUS(i)?:1,"Exit status %d from child",WEXITSTATUS(i));
}
warnx("New version successful.");
}
int main(int argc,char**argv) {
read_status();
calculate();
if(argc<2 || !strcmp(argv[1],"show")) {
show_status();
} else if(!strcmp(argv[1],"update")) {
write_status();
write_version_inc();
} else if(!strcmp(argv[1],"major")) {
major++; minor=patch=0;
new_version();
} else if(!strcmp(argv[1],"minor")) {
minor++; patch=0;
new_version();
} else if(!strcmp(argv[1],"patch")) {
patch++;
new_version();
} else {
errx(1,"Improper mode");
}
return 0;
}