Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / config / mkvers.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 /* Make the AFS_component_version_number.c file. Do it in C since there's no
11 * guarantee of perl on an NT platform.
12 *
13 */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <time.h>
22
23 #define VERINFO_STRING_CHARS_MAX 950 /* max chars in verinfo string */
24 #define CFILE_STRING_CHARS_MAX 2000 /* max chars in C file string */
25
26 #define DEPTH_MAX 6 /* maximum depth of src dir search (>= 3) */
27
28 #define CMLDIR_DFLT "../../src/CML" /* default starting point for search */
29 #define CMLDIR_BUFSZ ((DEPTH_MAX * (sizeof("../") - 1)) + sizeof("src/CML"))
30 static char cmldir[CMLDIR_BUFSZ];
31
32 #define STATE "state"
33 #define STAMPS "stamps"
34
35 #define CML_STRING "cml_version_number[]=\"@(#)"
36 #define CML_VER_DECL "char " CML_STRING
37 char *cml_string = CML_VER_DECL;
38
39 #define VERINFO_BUILD_STRING "#define AFS_VERINFO_BUILD "
40
41 #define AFS_STRING "char* AFSVersion = \""
42 #define VERS_FILE "AFS_component_version_number"
43
44 #define MAXDELTAS 128
45 typedef struct {
46 char name[512];
47 char type;
48 } deltaNames;
49
50 deltaNames stateDeltas[MAXDELTAS], stampDeltas[MAXDELTAS];
51 FILE *fpStamps;
52 FILE *fpState;
53 FILE *fpVers;
54 int nStates = 0;
55 int nStamps = 0;
56
57 enum {
58 CF_DEFAULT,
59 CF_VERINFO,
60 CF_TEXT,
61 CF_XML
62 } cfgFormat = CF_DEFAULT;
63
64 char *programName;
65
66 void PrintStamps(void);
67
68 void
69 Usage(void)
70 {
71 printf
72 ("Usage: %s [-d directory] [-o output file name] [-c component] [-v | -t | -x]\n",
73 programName);
74 printf("%s creates the AFS_component_version_number.c file.\n",
75 programName);
76 printf("Options:\n");
77 printf("-d directory - path of the CML directory, default is %s.\n",
78 CMLDIR_DFLT);
79 printf("-o file name - alternate output file name.\n");
80 printf
81 ("-c component - if not \"afs\" prefix for cml_version_number variable.\n");
82 printf("-v generate NT versioninfo style declarations.\n");
83 printf("-t generate text file style information.\n");
84 printf("-x generate XML revision information.\n");
85 exit(1);
86 }
87
88 int
89 main(int argc, char **argv)
90 {
91 char stampsFile[1024];
92 char stateFile[1024];
93 char s[1024];
94 int i;
95 char *baseDir;
96 int argDir = 0;
97 char *outputFile = NULL;
98 char outputFileBuf[sizeof(VERS_FILE) + 4];
99 struct stat sbuf;
100 time_t versTime;
101 int reBuild = 0;
102 int code;
103 char *cml_prefix = NULL;
104
105 /* initialize cmldir buffer and set default starting directory */
106 for (i = 0; i < DEPTH_MAX; i++) {
107 strcat(cmldir, "../");
108 }
109 strcat(cmldir, "src/CML");
110
111 baseDir = strstr(cmldir, CMLDIR_DFLT);
112
113 programName = argv[0];
114
115 for (i = 1; i < argc; i++) {
116 if (!strcmp("-d", argv[i])) {
117 i++;
118 if (i >= argc || *argv[i] == '-') {
119 printf("Missing directory name for -d option.\n");
120 Usage();
121 }
122 baseDir = argv[i];
123 argDir = 1;
124 } else if (!strcmp("-o", argv[i])) {
125 i++;
126 if (i >= argc || *argv[i] == '-') {
127 printf("Missing output file name for -o option.\n");
128 Usage();
129 }
130 outputFile = argv[i];
131 } else if (!strcmp("-c", argv[i])) {
132 i++;
133 if (i >= argc || *argv[i] == '-') {
134 printf("Missing component for -c option.\n");
135 Usage();
136 }
137 cml_prefix = argv[i];
138 } else if (!strcmp("-v", argv[i])) {
139 if (cfgFormat == CF_DEFAULT || cfgFormat == CF_VERINFO) {
140 cfgFormat = CF_VERINFO;
141 } else {
142 printf("Specify only one alternative output format\n");
143 Usage();
144 }
145 } else if (!strcmp("-t", argv[i])) {
146 if (cfgFormat == CF_DEFAULT || cfgFormat == CF_TEXT) {
147 cfgFormat = CF_TEXT;
148 } else {
149 printf("Specify only one alternative output format\n");
150 Usage();
151 }
152 } else if (!strcmp("-x", argv[i])) {
153 if (cfgFormat == CF_DEFAULT || cfgFormat == CF_XML) {
154 cfgFormat = CF_XML;
155 } else {
156 printf("Specify only one alternative output format\n");
157 Usage();
158 }
159 } else {
160 printf("%s: Unknown argument.\n", argv[i]);
161 Usage();
162 }
163 }
164
165 /* set outputFile if not specified */
166
167 if (outputFile == NULL) {
168 strcpy(outputFileBuf, VERS_FILE);
169 if (cfgFormat == CF_VERINFO) {
170 strcat(outputFileBuf, ".h");
171 } else if (cfgFormat == CF_TEXT) {
172 strcat(outputFileBuf, ".txt");
173 } else if (cfgFormat == CF_XML) {
174 strcat(outputFileBuf, ".xml");
175 } else {
176 strcat(outputFileBuf, ".c");
177 }
178 outputFile = outputFileBuf;
179 }
180
181 /* Determine if we need to create the output file. */
182
183 if ((code = stat(outputFile, &sbuf)) < 0) {
184 reBuild = 1;
185 versTime = (time_t) 0; /* indicates no output file. */
186 } else {
187 versTime = sbuf.st_mtime;
188 }
189
190 sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
191 code = stat(stampsFile, &sbuf);
192
193 while (code < 0 && errno == ENOENT && !argDir && baseDir > cmldir) {
194 /* Try path at next level of depth. */
195 baseDir -= sizeof("../") - 1;
196 sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
197 code = stat(stampsFile, &sbuf);
198 }
199 if (code == 0 && versTime <= sbuf.st_mtime) {
200 reBuild = 1;
201 }
202
203 sprintf(stateFile, "%s/%s", baseDir, STATE);
204
205 if (!reBuild) {
206 code = stat(stateFile, &sbuf);
207 /* dont' check alternate base dir, since it would be reset above */
208 if (code == 0 && versTime <= sbuf.st_mtime)
209 reBuild = 1;
210 }
211
212 if (!reBuild) {
213 printf("Not rebuilding %s since it is up to date.\n", outputFile);
214 exit(0);
215 }
216
217 if (cml_prefix) {
218 cml_string =
219 (char *)malloc(strlen("char ") + strlen(cml_prefix) + strlen(CML_STRING) +
220 1);
221 if (!cml_string) {
222 printf("No space to use prefix in cml string, ignoring it.\n");
223 cml_string = CML_VER_DECL;
224 } else {
225 (void)sprintf(cml_string, "%s%s%s", "char ", cml_prefix,
226 CML_STRING);
227 }
228 }
229
230 fpState = fopen(stateFile, "r");
231 fpStamps = fopen(stampsFile, "r");
232 fpVers = fopen(outputFile, "w");
233
234 if (fpStamps == NULL || fpState == NULL || fpVers == NULL) {
235 if (fpVers) {
236 if (cfgFormat == CF_VERINFO) {
237 fprintf(fpVers,
238 "%s \"No configuration information available\"\n",
239 VERINFO_BUILD_STRING);
240 } else if (cfgFormat == CF_TEXT) {
241 fprintf(fpVers, "No configuration information available.\n");
242 } else {
243 fprintf(fpVers,
244 "%sNo configuration information available\";\n",
245 cml_string);
246 fprintf(fpVers, "%safs??\";\n", AFS_STRING);
247 }
248 fclose(fpVers);
249 } else {
250 fprintf(stderr, "Can't write version information to %s.\n",
251 outputFile);
252 }
253 fprintf(stderr,
254 "No configuration information available, continuing...\n");
255 exit(1);
256 }
257
258
259 nStates = 0;
260 while (fgets(s, sizeof(s), fpState)) {
261 if (*s == 'I' || *s == 'N' || *s == 'C' || *s == 'O') {
262 stateDeltas[nStates].type = *s;
263 s[strlen(s) - 1] = '\0';
264 (void)strcpy(stateDeltas[nStates].name, s + 2);
265 nStates++;
266 }
267
268 }
269 fclose(fpState);
270
271 PrintStamps();
272 fclose(fpVers);
273
274 return 0;
275 }
276
277
278 void
279 PrintStamps(void)
280 {
281 char *s;
282 char *c = NULL;
283 int i;
284 size_t outMax, outCount = 0;
285 time_t t = time(NULL);
286
287 if (cfgFormat == CF_VERINFO) {
288 outMax = VERINFO_STRING_CHARS_MAX;
289 } else if (cfgFormat == CF_TEXT) {
290 outMax = 0; /* signifies that there is no maximum */
291 } else {
292 outMax = CFILE_STRING_CHARS_MAX;
293 }
294
295 for (i = 0; i < nStates; i++) {
296 if (stateDeltas[i].type == 'C') {
297 if (cfgFormat == CF_VERINFO) {
298 fprintf(fpVers, "%s \"Base configuration %s",
299 VERINFO_BUILD_STRING, stateDeltas[i].name);
300 } else if (cfgFormat == CF_TEXT) {
301 fprintf(fpVers, "Base configuration %s\n",
302 stateDeltas[i].name);
303 } else if (cfgFormat == CF_XML) {
304 fprintf(fpVers,
305 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
306 "<revision>\n"
307 "<revnumber>\n"
308 "Base configuration %s\n"
309 "</revnumber>\n"
310 "<date>\n"
311 "%s"
312 "</date>\n"
313 "</revision>\n",
314 stateDeltas[i].name, ctime(&t));
315 } else {
316 fprintf(fpVers, "%sBase configuration %s", cml_string,
317 stateDeltas[i].name);
318 }
319 c = stateDeltas[i].name;
320 break;
321 }
322 }
323
324 for (i = 0; i < nStates; i++) {
325 if (stateDeltas[i].type == 'I' || stateDeltas[i].type == 'N') {
326 outCount += strlen(stateDeltas[i].name) + 2;
327 if (outMax && outCount > outMax) {
328 break;
329 }
330 if (cfgFormat == CF_TEXT) {
331 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
332 stateDeltas[i].name);
333 } else if (cfgFormat == CF_XML) {
334 fprintf(fpVers,
335 "<revremark>\n"
336 ";%c%s"
337 "</revremark>\n",
338 stateDeltas[i].type,
339 stateDeltas[i].name);
340 } else {
341 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
342 stateDeltas[i].name);
343 }
344 }
345 }
346
347 for (i = 0; i < nStates; i++) {
348 if (stateDeltas[i].type == 'O') {
349 outCount += strlen(stateDeltas[i].name) + 2;
350 if (outMax && outCount > outMax) {
351 break;
352 }
353 if (cfgFormat == CF_TEXT) {
354 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
355 stateDeltas[i].name);
356 } else if (cfgFormat == CF_XML) {
357 fprintf(fpVers,
358 "<revremark>\n"
359 ";%c%s"
360 "</revremark>\n",
361 stateDeltas[i].type,
362 stateDeltas[i].name);
363 } else {
364 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
365 stateDeltas[i].name);
366 }
367 }
368 }
369
370 if (outMax && outCount > outMax) {
371 fprintf(fpVers, ";[LIST TRUNCATED]");
372 }
373
374 if (cfgFormat == CF_VERINFO) {
375 fprintf(fpVers, "\"\n");
376 } else if (cfgFormat == CF_DEFAULT) {
377 fprintf(fpVers, "\";\n");
378
379 if (c)
380 c += 3;
381 s = (char *)strchr(c, ' ');
382 if (s)
383 *s = '\0';
384 fprintf(fpVers, "%s%s\";\n", AFS_STRING, c ? c : "Unknown");
385 } else if (cfgFormat == CF_XML) {
386 fprintf(fpVers, "</revision>\n");
387 }
388 }