Fix warnings in tviced
[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     CF_XML
63 } cfgFormat = CF_DEFAULT;
64
65 char *programName;
66
67 void PrintStamps(void);
68
69 void
70 Usage(void)
71 {
72     printf
73         ("Usage: %s [-d directory] [-o output file name] [-c component] [-v | -t | -x]\n",
74          programName);
75     printf("%s creates the AFS_component_version_number.c file.\n",
76            programName);
77     printf("Options:\n");
78     printf("-d directory - path of the CML directory, default is %s.\n",
79            CMLDIR_DFLT);
80     printf("-o file name - alternate output file name.\n");
81     printf
82         ("-c component - if not \"afs\" prefix for cml_version_number variable.\n");
83     printf("-v generate NT versioninfo style declarations.\n");
84     printf("-t generate text file style information.\n");
85     printf("-x generate XML revision information.\n");
86     exit(1);
87 }
88
89 int
90 main(int argc, char **argv)
91 {
92     char stampsFile[1024];
93     char stateFile[1024];
94     char s[1024];
95     int i;
96     char *baseDir;
97     int argDir = 0;
98     char *outputFile = NULL;
99     char outputFileBuf[sizeof(VERS_FILE) + 2];
100     struct stat sbuf;
101     time_t versTime;
102     int reBuild = 0;
103     int code;
104     char *cml_prefix = NULL;
105
106     /* initialize cmldir buffer and set default starting directory */
107     for (i = 0; i < DEPTH_MAX; i++) {
108         strcat(cmldir, "../");
109     }
110     strcat(cmldir, "src/CML");
111
112     baseDir = strstr(cmldir, CMLDIR_DFLT);
113
114     programName = argv[0];
115
116     for (i = 1; i < argc; i++) {
117         if (!strcmp("-d", argv[i])) {
118             i++;
119             if (i >= argc || *argv[i] == '-') {
120                 printf("Missing directory name for -d option.\n");
121                 Usage();
122             }
123             baseDir = argv[i];
124             argDir = 1;
125         } else if (!strcmp("-o", argv[i])) {
126             i++;
127             if (i >= argc || *argv[i] == '-') {
128                 printf("Missing output file name for -o option.\n");
129                 Usage();
130             }
131             outputFile = argv[i];
132         } else if (!strcmp("-c", argv[i])) {
133             i++;
134             if (i >= argc || *argv[i] == '-') {
135                 printf("Missing component for -c option.\n");
136                 Usage();
137             }
138             cml_prefix = argv[i];
139         } else if (!strcmp("-v", argv[i])) {
140             if (cfgFormat == CF_DEFAULT || cfgFormat == CF_VERINFO) {
141                 cfgFormat = CF_VERINFO;
142             } else {
143                 printf("Specify only one alternative output format\n");
144                 Usage();
145             }
146         } else if (!strcmp("-t", argv[i])) {
147             if (cfgFormat == CF_DEFAULT || cfgFormat == CF_TEXT) {
148                 cfgFormat = CF_TEXT;
149             } else {
150                 printf("Specify only one alternative output format\n");
151                 Usage();
152             }
153         } else if (!strcmp("-x", argv[i])) {
154             if (cfgFormat == CF_DEFAULT || cfgFormat == CF_XML) {
155                 cfgFormat = CF_XML;
156             } else {
157                 printf("Specify only one alternative output format\n");
158                 Usage();
159             }
160         } else {
161             printf("%s: Unknown argument.\n", argv[i]);
162             Usage();
163         }
164     }
165
166     /* set outputFile if not specified */
167
168     if (outputFile == NULL) {
169         strcpy(outputFileBuf, VERS_FILE);
170         if (cfgFormat == CF_VERINFO) {
171             strcat(outputFileBuf, ".h");
172         } else if (cfgFormat == CF_TEXT) {
173             strcat(outputFileBuf, ".txt");
174         } else if (cfgFormat == CF_XML) {
175             strcat(outputFileBuf, ".xml");
176         } else {
177             strcat(outputFileBuf, ".c");
178         }
179         outputFile = outputFileBuf;
180     }
181
182     /* Determine if we need to create the output file. */
183
184     if ((code = stat(outputFile, &sbuf)) < 0) {
185         reBuild = 1;
186         versTime = (time_t) 0;  /* indicates no output file. */
187     } else {
188         versTime = sbuf.st_mtime;
189     }
190
191     sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
192     code = stat(stampsFile, &sbuf);
193
194     while (code < 0 && errno == ENOENT && !argDir && baseDir > cmldir) {
195         /* Try path at next level of depth. */
196         baseDir -= sizeof("../") - 1;
197         sprintf(stampsFile, "%s/%s", baseDir, STAMPS);
198         code = stat(stampsFile, &sbuf);
199     }
200     if (code == 0 && versTime <= sbuf.st_mtime) {
201         reBuild = 1;
202     }
203
204     sprintf(stateFile, "%s/%s", baseDir, STATE);
205
206     if (!reBuild) {
207         code = stat(stateFile, &sbuf);
208         /* dont' check alternate base dir, since it would be reset above */
209         if (code == 0 && versTime <= sbuf.st_mtime)
210             reBuild = 1;
211     }
212
213     if (!reBuild) {
214         printf("Not rebuilding %s since it is up to date.\n", outputFile);
215         exit(0);
216     }
217
218     if (cml_prefix) {
219         cml_string =
220             (char *)malloc(strlen("char ") + strlen(cml_prefix) + strlen(CML_STRING) +
221                    1);
222         if (!cml_string) {
223             printf("No space to use prefix in cml string, ignoring it.\n");
224             cml_string = CML_VER_DECL;
225         } else {
226             (void)sprintf(cml_string, "%s%s%s", "char ", cml_prefix,
227                           CML_STRING);
228         }
229     }
230
231     fpState = fopen(stateFile, "r");
232     fpStamps = fopen(stampsFile, "r");
233     fpVers = fopen(outputFile, "w");
234
235     if (fpStamps == NULL || fpState == NULL || fpVers == NULL) {
236         if (fpVers) {
237             if (cfgFormat == CF_VERINFO) {
238                 fprintf(fpVers,
239                         "%s \"No configuration information available\"\n",
240                         VERINFO_BUILD_STRING);
241             } else if (cfgFormat == CF_TEXT) {
242                 fprintf(fpVers, "No configuration information available.\n");
243             } else {
244                 fprintf(fpVers,
245                         "%sNo configuration information available\";\n",
246                         cml_string);
247                 fprintf(fpVers, "%safs??\";\n", AFS_STRING);
248             }
249             fclose(fpVers);
250         } else {
251             fprintf(stderr, "Can't write version information to %s.\n",
252                     outputFile);
253         }
254         fprintf(stderr,
255                 "No configuration information available, continuing...\n");
256         exit(1);
257     }
258
259
260     nStates = 0;
261     while (fgets(s, sizeof(s), fpState)) {
262         if (*s == 'I' || *s == 'N' || *s == 'C' || *s == 'O') {
263             stateDeltas[nStates].type = *s;
264             s[strlen(s) - 1] = '\0';
265             (void)strcpy(stateDeltas[nStates].name, s + 2);
266             nStates++;
267         }
268
269     }
270     fclose(fpState);
271
272     PrintStamps();
273     fclose(fpVers);
274
275     return 0;
276 }
277
278
279 void
280 PrintStamps(void)
281 {
282     char *s;
283     char *c = NULL;
284     int i;
285     size_t outMax, outCount = 0;
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                         stateDeltas[i].name);
311             } else {
312                 fprintf(fpVers, "%sBase configuration %s", cml_string,
313                         stateDeltas[i].name);
314             }
315             c = stateDeltas[i].name;
316             break;
317         }
318     }
319
320     for (i = 0; i < nStates; i++) {
321         if (stateDeltas[i].type == 'I' || stateDeltas[i].type == 'N') {
322             outCount += strlen(stateDeltas[i].name) + 2;
323             if (outMax && outCount > outMax) {
324                 break;
325             }
326             if (cfgFormat == CF_TEXT) {
327                 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
328                         stateDeltas[i].name);
329             } else if (cfgFormat == CF_XML) {
330                 fprintf(fpVers, 
331                         "<revremark>\n"
332                         ";%c%s"
333                          "</revremark>\n",
334                         stateDeltas[i].type,
335                         stateDeltas[i].name);
336             } else {
337                 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
338                         stateDeltas[i].name);
339             }
340         }
341     }
342
343     for (i = 0; i < nStates; i++) {
344         if (stateDeltas[i].type == 'O') {
345             outCount += strlen(stateDeltas[i].name) + 2;
346             if (outMax && outCount > outMax) {
347                 break;
348             }
349             if (cfgFormat == CF_TEXT) {
350                 fprintf(fpVers, "%c%s\n", stateDeltas[i].type,
351                         stateDeltas[i].name);
352             } else if (cfgFormat == CF_XML) {
353                 fprintf(fpVers, 
354                         "<revremark>\n"
355                         ";%c%s"
356                          "</revremark>\n",
357                         stateDeltas[i].type,
358                         stateDeltas[i].name);
359             } else {
360                 fprintf(fpVers, ";%c%s", stateDeltas[i].type,
361                         stateDeltas[i].name);
362             }
363         }
364     }
365
366     if (outMax && outCount > outMax) {
367         fprintf(fpVers, ";[LIST TRUNCATED]");
368     }
369
370     if (cfgFormat == CF_VERINFO) {
371         fprintf(fpVers, "\"\n");
372     } else if (cfgFormat == CF_DEFAULT) {
373         fprintf(fpVers, "\";\n");
374
375         if (c)
376             c += 3;
377         s = (char *)strchr(c, ' ');
378         if (s)
379             *s = '\0';
380         fprintf(fpVers, "%s%s\";\n", AFS_STRING, c ? c : "Unknown");
381     } else if (cfgFormat == CF_XML) {
382         fprintf(fpVers, "</revision>\n");
383     }
384 }