:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / tools / buildno.c
1 /* $Id$
2  *
3  * buildno - Generate the build number for ReactOS
4  *
5  * Copyright (c) 1999,2000 Emanuele Aliberti
6  *
7  * License: GNU GPL
8  *
9  * It assumes the last release date is defined in
10  * <reactos/version.h> as a macro named
11  *
12  * KERNEL_RELEASE_DATE
13  *
14  * as a 32-bit unsigned long YYYYMMDD (UTC;
15  * MM=01-12; DD=01-31).
16  *
17  * The build number is the number of full days
18  * elapsed since the last release date (UTC).
19  *
20  * The build number is stored in the file
21  * <reactos/buildno.h> as a set of macros:
22  *
23  * KERNEL_VERSION_BUILD         base 10 number
24  * KERNEL_VERSION_BUILD_STR     C string
25  * KERNEL_VERSION_BUILD_RC      RC string
26  *
27  * REVISIONS
28  * ---------
29  * 2000-01-22 (ea)
30  *      Fixed bugs: tm_year is (current_year - 1900),
31  *      tm_month is 0-11 not 1-12 and code ignored TZ.
32  * 2000-12-10 (ea)
33  *      Added -p option to make it simply print the
34  *      version number, but skip buildno.h generation.
35  */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <time.h>
39 #include "../include/reactos/version.h"
40
41 #define FALSE 0
42 #define TRUE  1
43
44 /* File to (over)write */
45 #define BUILDNO_INCLUDE_FILE "../include/reactos/buildno.h"
46
47 static char * argv0 = "";
48
49 #ifdef DBG
50 void
51 tm_dump (const char *tag, struct tm * t)
52 {
53         printf ("%s->tm_sec   = %d\n", tag, t->tm_sec);
54         printf ("%s->tm_min   = %d\n", tag, t->tm_min);
55         printf ("%s->tm_hour  = %d\n", tag, t->tm_hour);
56         printf ("%s->tm_mday  = %d\n", tag, t->tm_mday);
57         printf ("%s->tm_mon   = %d\n", tag, t->tm_mon);
58         printf ("%s->tm_year  = %d\n", tag, t->tm_year);
59         printf ("%s->tm_wday  = %d\n", tag, t->tm_wday);
60         printf ("%s->tm_yday  = %d\n", tag, t->tm_yday);
61         printf ("%s->tm_isdst = %d\n\n", tag, t->tm_isdst);
62 }
63 #endif
64
65
66 int
67 elapsed_days (
68         time_t  t_today,
69         time_t  t_release_day
70         )
71 {
72         double  seconds = difftime (t_today, t_release_day);
73         double  days = seconds / (double) 86400.0;
74         char    buf [32];
75         char    * dot = buf;
76
77         sprintf (buf, "%f", days );
78
79         while ( *dot && *dot != '.') ++dot;
80         *dot = '\0';
81         
82         return atol (buf);
83 }
84
85 void
86 write_h (int build)
87 {
88   FILE  *h = NULL;
89   char* s;
90   char* s1;
91   int length;
92
93   s1 = s = malloc(256 * 1024);
94   
95   s = s + sprintf (s, "/* Do not edit - Machine generated */\n");
96         
97   s = s + sprintf (s, "#ifndef _INC_REACTOS_BUILDNO\n" );
98   s = s + sprintf (s, "#define _INC_REACTOS_BUILDNO\n" );
99   
100   s = s + sprintf (s, "#define KERNEL_VERSION_BUILD\t%d\n", build);
101   s = s + sprintf (s, "#define KERNEL_VERSION_BUILD_STR\t\"%d\"\n", build);
102   s = s + sprintf (s, "#define KERNEL_RELEASE_RC\t\"%d.%d.%d.%d\\0\"\n",
103                    KERNEL_VERSION_MAJOR, KERNEL_VERSION_MINOR,
104                    KERNEL_VERSION_PATCH_LEVEL, build);
105   s = s + sprintf (s, "#define KERNEL_RELEASE_STR\t\"%d.%d.%d.%d\"\n",
106                    KERNEL_VERSION_MAJOR,
107                    KERNEL_VERSION_MINOR,
108                    KERNEL_VERSION_PATCH_LEVEL,
109                    build);
110   s = s + sprintf (s, "#define KERNEL_VERSION_RC\t\"%d.%d.%d\\0\"\n",
111                    KERNEL_VERSION_MAJOR,
112                    KERNEL_VERSION_MINOR,
113                    KERNEL_VERSION_PATCH_LEVEL);
114   s = s + sprintf (s, "#define KERNEL_VERSION_STR\t\"%d.%d.%d\"\n", 
115                    KERNEL_VERSION_MAJOR,
116                    KERNEL_VERSION_MINOR,
117                    KERNEL_VERSION_PATCH_LEVEL);
118   s = s + sprintf (s, "#endif\n/* EOF */\n");
119
120   h = fopen (BUILDNO_INCLUDE_FILE, "r");
121   if (h != NULL)
122     {
123       fseek(h, 0, SEEK_END);
124       length = ftell(h);
125       if (length == strlen(s1))
126         {
127           char* orig;
128           
129           orig = malloc(length);
130           fseek(h, 0, SEEK_SET);
131           fread(orig, 1, length, h);
132           if (memcmp(s1, orig, length) == 0)
133             {
134               fclose(h);
135               return;
136             }
137         }
138       fclose(h);
139     }
140
141   h = fopen (BUILDNO_INCLUDE_FILE, "w");
142   if (!h) 
143     {
144       fprintf (stderr,
145                "%s: can not create file \"%s\"!\n",
146                argv0,
147                BUILDNO_INCLUDE_FILE);
148       return;
149     }
150   fwrite(s1, 1, strlen(s1), h);
151   fclose (h);
152 }
153
154 void
155 usage (void)
156 {
157         fprintf (
158                 stderr,
159                 "Usage: %s [-{p|q}]\n\n  -p  print version number and exit\n  -q  run in quiet mode\n",
160                 argv0
161                 );
162         exit (EXIT_SUCCESS);
163 }
164
165
166 int
167 main (int argc, char * argv [])
168 {
169         int             print_only = FALSE;
170         int             quiet = FALSE;
171
172         int             year = 0;
173         int             month = 0;
174         int             day = 0;
175         int             build = 0;
176
177         time_t          t0 = 0;
178         struct tm       t0_tm = {0};
179         time_t          t1 = 0;
180         struct tm       * t1_tm = NULL;
181
182         argv0 = argv[0];
183                 
184         switch (argc)
185         {
186                 case 1:
187                         break;
188                 case 2:
189                         if (argv[1][0] == '-')
190                         {
191                                 if (argv[1][1] == 'q')
192                                 {
193                                         quiet = TRUE;
194                                 }
195                                 else  if (argv[1][1] == 'p')
196                                 {
197                                         print_only = TRUE;
198                                 }
199                                 else
200                                 {
201                                         usage ();
202                                 }
203                         }
204                         else
205                         {
206                                 usage ();
207                         }
208                         break;
209                 default:
210                         usage ();
211         }
212         /*
213          * Set TZ information.
214          */
215         tzset ();
216         /*
217          * We are building TODAY!
218          */
219         time (& t0);
220         /*
221          * "Parse" the release date.
222          */
223         day = KERNEL_RELEASE_DATE % 100;
224         month = (       (       KERNEL_RELEASE_DATE
225                                 % 10000
226                                 )
227                                 - day
228                         )
229                         / 100;
230         year =
231                 (       KERNEL_RELEASE_DATE
232                         - (month * 100)
233                         - day
234                         )
235                         / 10000;
236         if (FALSE == quiet)
237         {
238                 printf ( "\n\
239 ReactOS Build Number Generator\n\n\
240 Last release: %4d-%02d-%02d\n",
241                         year,
242                         month,
243                         day
244                         );
245         }
246 #ifdef DBG
247         tm_dump ("t0", & t0_tm);
248 #endif
249         t0_tm.tm_year = (year - 1900);
250         t0_tm.tm_mon = --month; /* 0-11 */
251         t0_tm.tm_mday = day;
252         t0_tm.tm_hour = 0;
253         t0_tm.tm_min = 0;
254         t0_tm.tm_sec = 1;
255         t0_tm.tm_isdst = -1;
256         
257 #ifdef DBG
258         tm_dump ("t0", & t0_tm);
259 #endif
260
261         if (-1 == (t0 = mktime (& t0_tm)))
262         {
263                 fprintf (
264                         stderr,
265                         "%s: can not convert release date!\n",
266                         argv[0]
267                         );
268                 return EXIT_FAILURE;
269         }
270
271         time (& t1); /* current build time */
272         t1_tm = gmtime (& t1);
273
274 #ifdef DBG
275         tm_dump ("t1", t1_tm);
276 #endif
277         t1_tm->tm_year +=
278                 (t1_tm->tm_year < 70)
279                 ? 2000
280                 : 1900;
281 #ifdef DBG
282         tm_dump ("t1", t1_tm);
283 #endif
284         if (FALSE == quiet)
285         {
286                 printf ( 
287                         "Current date: %4d-%02d-%02d\n\n",
288                         t1_tm->tm_year,
289                         (t1_tm->tm_mon + 1),
290                         t1_tm->tm_mday
291                         );
292         }
293         /*
294          * Compute delta days.
295          */
296         build = elapsed_days (t1, t0);
297
298         if (FALSE == quiet)
299         {
300                 printf (
301                         "Build number: %d (elapsed days since last release)\n",
302                         build
303                         );
304                 printf (
305                         "ROS Version : %d.%d.%d.%d\n",
306                         KERNEL_VERSION_MAJOR,
307                         KERNEL_VERSION_MINOR,
308                         KERNEL_VERSION_PATCH_LEVEL,
309                         build
310                         );
311         }
312         /*
313          * (Over)write the include file, unless
314          * the user switched on -p.
315          */
316         if (FALSE == print_only)
317         {
318                 write_h (build);
319         }
320         else
321         {
322                 printf ("%s: no code generated", argv [0]);
323         }
324
325         return EXIT_SUCCESS;
326 }
327
328
329 /* EOF */