windows-afsconfig-header-20080802
[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 <assert.h>
21 #include <string.h>
22
23
24 #define VERINFO_STRING_CHARS_MAX  950   /* max chars in verinfo string */
25 #define CFILE_STRING_CHARS_MAX    2000  /* max chars in C file string */
26
27 #define DEPTH_MAX  6            /* maximum depth of src dir search (>= 3) */
28
29 #define CMLDIR_DFLT   "../../src/CML"   /* default starting point for search */
30 #define CMLDIR_BUFSZ  ((DEPTH_MAX * (sizeof("../") - 1)) + sizeof("src/CML"))
31 static char cmldir[CMLDIR_BUFSZ];
32
33 #define STATE "state"
34 #define STAMPS "stamps"
35
36 #define CML_STRING "cml_version_number[]=\"@(#)"
37 #define CML_VER_DECL "char " CML_STRING
38 char *cml_string = CML_VER_DECL;
39
40 #define VERINFO_BUILD_STRING  "#define AFS_VERINFO_BUILD "
41
42 #define AFS_STRING "char* AFSVersion = \""
43 #define VERS_FILE "AFS_component_version_number"
44
45 #define MAXDELTAS 128
46 typedef struct {
47     char name[512];
48     char type;
49 } deltaNames;
50
51 deltaNames stateDeltas[MAXDELTAS], stampDeltas[MAXDELTAS];
52 FILE *fpStamps;
53 FILE *fpState;
54 FILE *fpVers;
55 int nStates = 0;
56 int nStamps = 0;
57
58 enum {
59     CF_DEFAULT,
60     CF_VERINFO,
61     CF_TEXT
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]\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     exit(1);
85 }
86
87 int
88 main(int argc, char **argv)
89 {
90     char stampsFile[1024];
91     char stateFile[1024];
92     char s[1024];
93     int i;
94     char *baseDir;
95     int argDir = 0;
96     char *outputFile = NULL;
97     char outputFileBuf[sizeof(VERS_FILE) + 2];
98     struct stat sbuf;
99     time_t versTime;
100     int reBuild = 0;
101     int code;
102     char *cml_prefix = NULL;
103
104     /* initialize cmldir buffer and set default starting directory */
105     for (i = 0; i < DEPTH_MAX; i++) {
106         strcat(cmldir, "../");
107     }
108     strcat(cmldir, "src/CML");
109
110     baseDir = strstr(cmldir, CMLDIR_DFLT);
111
112     programName = argv[0];
113
114     for (i = 1; i < argc; i++) {
115         if (!strcmp("-d", argv[i])) {
116             i++;
117             if (i >= argc || *argv[i] == '-') {
118                 printf("Missing directory name for -d option.\n");
119                 Usage();
120             }
121             baseDir = argv[i];
122             argDir = 1;
123         } else if (!strcmp("-o", argv[i])) {
124             i++;
125             if (i >= argc || *argv[i] == '-') {
126                 printf("Missing output file name for -o option.\n");
127                 Usage();
128             }
129             outputFile = argv[i];
130         } else if (!strcmp("-c", argv[i])) {
131             i++;
132             if (i >= argc || *argv[i] == '-') {
133                 printf("Missing component for -c option.\n");
134                 Usage();
135             }
136             cml_prefix = argv[i];
137         } else if (!strcmp("-v", argv[i])) {
138             if (cfgFormat == CF_DEFAULT || cfgFormat == CF_VERINFO) {
139                 cfgFormat = CF_VERINFO;
140             } else {
141                 printf("Specify only one alternative output format\n");
142                 Usage();
143             }
144         } else if (!strcmp("-t", argv[i])) {
145             if (cfgFormat == CF_DEFAULT || cfgFormat == CF_TEXT) {
146                 cfgFormat = CF_TEXT;
147             } else {
148                 printf("Specify only one alternative output format\n");
149                 Usage();
150             }
151         } else {
152             printf("%s: Unknown argument.\n", argv[i]);
153             Usage();
154         }
155     }
156
157     /* set outputFile if not specified */
158
159     if (outputFile == NULL) {
160         strcpy(outputFileBuf, VERS_FILE);
161         if (cfgFormat == CF_VERINFO) {
162             strcat(outputFileBuf, ".h");
163         } else if (cfgFormat == CF_TEXT) {
164             strcat(outputFileBuf, ".txt");
165         } else {
166             strcat(outputFileBuf, ".c");
167         }
168         outputFile = outputFileBuf;
169     }
170
171     /* Determine if we need to create the output file. */
172
173     if ((code = stat(outputFile, &sbuf)) < 0) {
174         reBuild = 1;
175         versTime = (time_t) 0;  /* inidicates no output file. */
176     } else {
177         versTime = sbuf.st_mtime;
178     }
179
180     sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
181     code = stat(stampsFile, &sbuf);
182
183     while (code < 0 && errno == ENOENT && !argDir && baseDir > cmldir) {
184         /* Try path at next level of depth. */
185         baseDir -= sizeof("../") - 1;
186         sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
187         code = stat(stampsFile, &sbuf);
188     }
189     if (code == 0 && versTime <= sbuf.st_mtime) {
190         reBuild = 1;
191     }
192
193     sprintf(stateFile, "%s/%s", baseDir, STATE);
194
195     if (!reBuild) {
196         code = stat(stateFile, &sbuf);
197         /* dont' check alternate base dir, since it would be reset above */
198         if (code == 0 && versTime <= sbuf.st_mtime)
199             reBuild = 1;
200     }
201
202     if (!reBuild) {
203         printf("Not rebuilding %s since it is up to date.\n", outputFile);
204         exit(0);
205     }
206
207     if (cml_prefix) {
208         cml_string =
209             (char *)malloc(strlen("char ") + strlen(cml_prefix) + strlen(CML_STRING) +
210                    1);
211         if (!cml_string) {
212             printf("No space to use prefix in cml string, ignoring it.\n");
213             cml_string = CML_VER_DECL;
214         } else {
215             (void)sprintf(cml_string, "%s%s%s", "char ", cml_prefix,
216                           CML_STRING);
217         }
218     }
219
220     fpState = fopen(stateFile, "r");
221     fpStamps = fopen(stampsFile, "r");
222     fpVers = fopen(outputFile, "w");
223
224     if (fpStamps == NULL || fpState == NULL || fpVers == NULL) {
225         if (fpVers) {
226             if (cfgFormat == CF_VERINFO) {
227                 fprintf(fpVers,
228                         "%s \"No configuration information available\"\n",
229                         VERINFO_BUILD_STRING);
230             } else if (cfgFormat == CF_TEXT) {
231                 fprintf(fpVers, "No configuration information available.\n");
232             } else {
233                 fprintf(fpVers,
234                         "%sNo configuration information available\";\n",
235                         cml_string);
236                 fprintf(fpVers, "%safs??\";\n", AFS_STRING);
237             }
238             fclose(fpVers);
239         } else {
240             fprintf(stderr, "Can't write version information to %s.\n",
241                     outputFile);
242         }
243         fprintf(stderr,
244                 "No configuration information available, continuing...\n");
245         exit(1);
246     }
247
248
249     nStates = 0;
250     while (fgets(s, sizeof(s), fpState)) {
251         if (*s == 'I' || *s == 'N' || *s == 'C' || *s == 'O') {
252             stateDeltas[nStates].type = *s;
253             s[strlen(s) - 1] = '\0';
254             (void)strcpy(stateDeltas[nStates].name, s + 2);
255             nStates++;
256         }
257
258     }
259     fclose(fpState);
260
261     PrintStamps();
262     fclose(fpVers);
263
264     return 0;
265 }
266
267
268 void
269 PrintStamps(void)
270 {
271     char *s;
272     char *c = NULL;
273     int i;
274     size_t outMax, outCount = 0;
275
276     if (cfgFormat == CF_VERINFO) {
277         outMax = VERINFO_STRING_CHARS_MAX;
278     } else if (cfgFormat == CF_TEXT) {
279         outMax = 0;             /* signifies that there is no maximum */
280     } else {
281         outMax = CFILE_STRING_CHARS_MAX;
282     }
283
284     for (i = 0; i < nStates; i++) {
285         if (stateDeltas[i].type == 'C') {
286             if (cfgFormat == CF_VERINFO) {
287                 fprintf(fpVers, "%s \"Base configuration %s",
288                         VERINFO_BUILD_STRING, stateDeltas[i].name);
289             } else if (cfgFormat == CF_TEXT) {
290                 fprintf(fpVers, "Base configuration %s\n",
291                         stateDeltas[i].name);
292             } else {
293                 fprintf(fpVers, "%sBase configuration %s", cml_string,
294                         stateDeltas[i].name);
295             }
296             c = stateDeltas[i].name;
297             break;
298         }
299     }
300
301     for (i = 0; i < nStates; i++) {
302         if (stateDeltas[i].type == 'I' || stateDeltas[i].type == 'N') {
303             outCount += strlen(stateDeltas[i].name) + 2;
304             if (outMax && outCount > outMax) {
305                 break;
306             }
307             if (cfgFormat == CF_TEXT) {
308                 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
309                         stateDeltas[i].name);
310             } else {
311                 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
312                         stateDeltas[i].name);
313             }
314         }
315     }
316
317     for (i = 0; i < nStates; i++) {
318         if (stateDeltas[i].type == 'O') {
319             outCount += strlen(stateDeltas[i].name) + 2;
320             if (outMax && outCount > outMax) {
321                 break;
322             }
323             if (cfgFormat == CF_TEXT) {
324                 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
325                         stateDeltas[i].name);
326             } else {
327                 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
328                         stateDeltas[i].name);
329             }
330         }
331     }
332
333     if (outMax && outCount > outMax) {
334         fprintf(fpVers, ";[LIST TRUNCATED]");
335     }
336
337     if (cfgFormat == CF_VERINFO) {
338         fprintf(fpVers, "\"\n");
339     } else if (cfgFormat == CF_DEFAULT) {
340         fprintf(fpVers, "\";\n");
341
342         if (c)
343             c += 3;
344         s = (char *)strchr(c, ' ');
345         if (s)
346             *s = '\0';
347         fprintf(fpVers, "%s%s\";\n", AFS_STRING, c ? c : "Unknown");
348     }
349 }