w32: Adjust mkdefsinc.c for Windows
[gnupg.git] / doc / mkdefsinc.c
1 /* mkdefsinc.c - Tool to create defs.inc
2  * Copyright (C) 2015 g10 Code GmbH
3  *
4  * This file is free software; as a special exception the author gives
5  * unlimited permission to copy and/or distribute it, with or without
6  * modifications, as long as this notice is preserved.
7  *
8  * This file is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
10  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  */
12
13 /* This tool needs to be build with command line supplied -D options
14    for the various directory variables.  See ../am/cmacros.am.  It is
15    easier to do this in build file than to use fragile make rules and
16    a template file.  */
17
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <time.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #define PGM "mkdefsinc"
29
30 /* We include config.h after all include files because the config.h
31    values are not valid for the build platform but we need some values
32    nevertheless.  */
33 #include "config.h"
34 /* When building for Windows some -D macros are not available.  We
35    provide replacements here.  */
36 #ifdef HAVE_W32_SYSTEM
37 # define GNUPG_BINDIR        "INSTDIR/bin"
38 # define GNUPG_LIBEXECDIR    "INSTDIR/bin"
39 # define GNUPG_LIBDIR        "INSTDIR/lib/" PACKAGE_NAME
40 # define GNUPG_DATADIR       "INSTDIR/share/" PACKAGE_NAME
41 # define GNUPG_SYSCONFDIR    "APPDATA/GNU/etc/" PACKAGE_NAME
42 # define GNUPG_LOCALSTATEDIR "APPDATA/GNU"
43 #endif /*HAVE_W32_SYSTEM*/
44
45
46 static int verbose;
47
48
49 /* The usual free wrapper.  */
50 static void
51 xfree (void *a)
52 {
53   if (a)
54     free (a);
55 }
56
57
58 static char *
59 xmalloc (size_t n)
60 {
61   char *p;
62
63   p = malloc (n);
64   if (!p)
65     {
66       fputs (PGM ": out of core\n", stderr);
67       exit (1);
68     }
69   return p;
70 }
71
72
73 static char *
74 xstrdup (const char *string)
75 {
76   char *p;
77
78   p = xmalloc (strlen (string)+1);
79   strcpy (p, string);
80   return p;
81 }
82
83
84 /* Return a malloced string with the last modification date of the
85    FILES.  Returns NULL on error.  */
86 static char *
87 get_date_from_files (char **files)
88 {
89   const char *file;
90   const char *usedfile = NULL;
91   struct stat sb;
92   struct tm *tp;
93   int errors = 0;
94   time_t stamp = 0;
95   char *result;
96
97   for (; (file = *files); files++)
98     {
99       if (!*file || !strcmp (file, ".") || !strcmp (file, ".."))
100         continue;
101       if (stat (file, &sb))
102         {
103           fprintf (stderr, PGM ": stat failed for '%s': %s\n",
104                    file, strerror (errno));
105           errors = 1;
106           continue;
107         }
108       if (sb.st_mtime > stamp)
109         {
110           stamp = sb.st_mtime;
111           usedfile = file;
112         }
113     }
114   if (errors)
115     exit (1);
116
117   if (usedfile)
118     fprintf (stderr, PGM ": taking date from '%s'\n", usedfile);
119
120   tp = gmtime (&stamp);
121   if (!tp)
122     return NULL;
123   result = xmalloc (4+1+2+1+2+1);
124   snprintf (result, 4+1+2+1+2+1, "%04d-%02d-%02d",
125             tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday);
126   return result;
127 }
128
129
130
131 int
132 main (int argc, char **argv)
133 {
134   int last_argc = -1;
135   char *opt_date = NULL;
136   int monthoff;
137   char *p, *pend;
138   size_t n;
139
140   /* Option parsing.  */
141   if (argc)
142     {
143       argc--; argv++;
144     }
145   while (argc && last_argc != argc )
146     {
147       last_argc = argc;
148       if (!strcmp (*argv, "--"))
149         {
150           argc--; argv++;
151           break;
152         }
153       else if (!strcmp (*argv, "--help"))
154         {
155           fputs ("Usage: " PGM " [OPTION] [FILES]\n"
156                  "Create defs.inc file.\nOptions:\n"
157                  "  -C DIR         Change to DIR before doing anything\n"
158                  "  --date STRING  Take publication date from STRING\n"
159                  "  --verbose      Enable extra informational output\n"
160                  "  --help         Display this help and exit\n"
161                  , stdout);
162           exit (0);
163         }
164       else if (!strcmp (*argv, "--verbose"))
165         {
166           verbose = 1;
167           argc--; argv++;
168         }
169       else if (!strcmp (*argv, "-C"))
170         {
171           argc--; argv++;
172           if (argc)
173             {
174               if (chdir (*argv))
175                 {
176                   fprintf (stderr, PGM ": chdir to '%s' failed: %s\n",
177                            *argv, strerror (errno));
178                   exit (1);
179                 }
180               argc--; argv++;
181             }
182         }
183       else if (!strcmp (*argv, "--date"))
184         {
185           argc--; argv++;
186           if (argc)
187             {
188               opt_date = xstrdup (*argv);
189               argc--; argv++;
190             }
191         }
192       else if (!strncmp (*argv, "--", 2))
193         {
194           fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
195           exit (1);
196         }
197     }
198
199   if (opt_date && *opt_date)
200     {
201       time_t stamp;
202       struct tm *tp;
203
204       if (*opt_date == '2' && strlen (opt_date) >= 10
205           && opt_date[4] == '-' && opt_date[7] == '-')
206         {
207           opt_date[10] = 0;
208         }
209       else if ((stamp = strtoul (opt_date, NULL, 10)) > 0
210                && (tp = gmtime (&stamp)))
211         {
212           p = xmalloc (4+1+2+1+2+1);
213           snprintf (p, 4+1+2+1+2+1, "%04d-%02d-%02d",
214                     tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday);
215           xfree (opt_date);
216           opt_date = p;
217         }
218       else
219         {
220           fprintf (stderr, PGM ": bad date '%s'\n", opt_date);
221           exit (1);
222         }
223     }
224   else
225     {
226       xfree (opt_date);
227       opt_date = argc? get_date_from_files (argv) : NULL;
228     }
229   if (!opt_date)
230     {
231       opt_date = xstrdup ("unknown");
232       monthoff = 0;
233     }
234   else
235     {
236       const char *month = "?";
237
238       switch (atoi (opt_date+5))
239         {
240         case  1: month = "January"; break;
241         case  2: month = "February"; break;
242         case  3: month = "March"; break;
243         case  4: month = "April"; break;
244         case  5: month = "May"; break;
245         case  6: month = "June"; break;
246         case  7: month = "July"; break;
247         case  8: month = "August"; break;
248         case  9: month = "September"; break;
249         case 10: month = "October"; break;
250         case 11: month = "November"; break;
251         case 12: month = "December"; break;
252         }
253       n = strlen (opt_date) + strlen (month) + 2 + 1;
254       p = xmalloc (n);
255       snprintf (p, n, "%d %n%s %d",
256                 atoi (opt_date+8), &monthoff, month, atoi (opt_date));
257       xfree (opt_date);
258       opt_date = p;
259     }
260
261
262   fputs ("@c defs.inc                         -*- texinfo -*-\n"
263          "@c Common and build specific constants for the manuals.\n"
264          "@c This file has been created by " PGM ".\n", stdout);
265
266   fputs ("\n@c Directories\n\n", stdout);
267
268   fputs ("@set BINDIR         " GNUPG_BINDIR        "\n"
269          "@set LIBEXECDIR     " GNUPG_LIBEXECDIR    "\n"
270          "@set LIBDIR         " GNUPG_LIBDIR        "\n"
271          "@set DATADIR        " GNUPG_DATADIR       "\n"
272          "@set SYSCONFDIR     " GNUPG_SYSCONFDIR    "\n"
273          "@set LOCALSTATEDIR  " GNUPG_LOCALSTATEDIR "\n"
274          "@set LOCALCACHEDIR  " GNUPG_LOCALSTATEDIR
275          /*                  */ "/cache/" PACKAGE_NAME "\n"
276          "@set LOCALRUNDIR    " GNUPG_LOCALSTATEDIR
277          /*                  */ "/run/"  PACKAGE_NAME "\n"
278          , stdout);
279
280   p = xstrdup (GNUPG_SYSCONFDIR);
281   pend = strrchr (p, '/');
282   fputs ("@set SYSCONFSKELDIR ", stdout);
283   if (pend)
284     {
285       *pend = 0;
286       fputs (p, stdout);
287     }
288   fputs ("/skel/." PACKAGE_NAME "\n", stdout);
289   xfree (p);
290
291   fputs ("\n@c Version information a la version.texi\n\n", stdout);
292
293   printf ("@set UPDATED %s\n", opt_date);
294   printf ("@set UPDATED-MONTH %s\n", opt_date + monthoff);
295   printf ("@set EDITION %s\n", PACKAGE_VERSION);
296   printf ("@set VERSION %s\n", PACKAGE_VERSION);
297
298   fputs ("\n@c Algorithm defaults\n\n", stdout);
299
300   /* Fixme: Use a config.h macro here:  */
301   fputs ("@set GPGSYMENCALGO AES-128\n", stdout);
302
303
304   fputs ("\n"
305          "@c Loc" "al Variables:\n"
306          "@c buffer-read-only: t\n"
307          "@c End:\n", stdout);
308
309   if (ferror (stdout))
310     {
311       fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
312       return 1;
313     }
314
315   return 0;
316 }