c4f776f31cc4e1171f63430dee1ef73f41c4205e
[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
35
36 static int verbose;
37
38
39 /* The usual free wrapper.  */
40 static void
41 xfree (void *a)
42 {
43   if (a)
44     free (a);
45 }
46
47
48 static char *
49 xmalloc (size_t n)
50 {
51   char *p;
52
53   p = malloc (n);
54   if (!p)
55     {
56       fputs (PGM ": out of core\n", stderr);
57       exit (1);
58     }
59   return p;
60 }
61
62
63 static char *
64 xstrdup (const char *string)
65 {
66   char *p;
67
68   p = xmalloc (strlen (string)+1);
69   strcpy (p, string);
70   return p;
71 }
72
73
74 /* Return a malloced string with the last modification date of the
75    FILES.  Returns NULL on error.  */
76 static char *
77 get_date_from_files (char **files)
78 {
79   const char *file;
80   const char *usedfile = NULL;
81   struct stat sb;
82   struct tm *tp;
83   int errors = 0;
84   time_t stamp = 0;
85   char *result;
86
87   for (; (file = *files); files++)
88     {
89       if (!*file || !strcmp (file, ".") || !strcmp (file, ".."))
90         continue;
91       if (stat (file, &sb))
92         {
93           fprintf (stderr, PGM ": stat failed for '%s': %s\n",
94                    file, strerror (errno));
95           errors = 1;
96           continue;
97         }
98       if (sb.st_mtime > stamp)
99         {
100           stamp = sb.st_mtime;
101           usedfile = file;
102         }
103     }
104   if (errors)
105     exit (1);
106
107   if (usedfile)
108     fprintf (stderr, PGM ": taking date from '%s'\n", usedfile);
109
110   tp = gmtime (&stamp);
111   if (!tp)
112     return NULL;
113   result = xmalloc (4+1+2+1+2+1);
114   snprintf (result, 4+1+2+1+2+1, "%04d-%02d-%02d",
115             tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday);
116   return result;
117 }
118
119
120
121 int
122 main (int argc, char **argv)
123 {
124   int last_argc = -1;
125   char *opt_date = NULL;
126   int monthoff;
127   char *p, *pend;
128   size_t n;
129
130   /* Option parsing.  */
131   if (argc)
132     {
133       argc--; argv++;
134     }
135   while (argc && last_argc != argc )
136     {
137       last_argc = argc;
138       if (!strcmp (*argv, "--"))
139         {
140           argc--; argv++;
141           break;
142         }
143       else if (!strcmp (*argv, "--help"))
144         {
145           fputs ("Usage: " PGM " [OPTION] [FILES]\n"
146                  "Create defs.inc file.\nOptions:\n"
147                  "  -C DIR         Change to DIR before doing anything\n"
148                  "  --date STRING  Take publication date from STRING\n"
149                  "  --verbose      Enable extra informational output\n"
150                  "  --help         Display this help and exit\n"
151                  , stdout);
152           exit (0);
153         }
154       else if (!strcmp (*argv, "--verbose"))
155         {
156           verbose = 1;
157           argc--; argv++;
158         }
159       else if (!strcmp (*argv, "-C"))
160         {
161           argc--; argv++;
162           if (argc)
163             {
164               if (chdir (*argv))
165                 {
166                   fprintf (stderr, PGM ": chdir to '%s' failed: %s\n",
167                            *argv, strerror (errno));
168                   exit (1);
169                 }
170               argc--; argv++;
171             }
172         }
173       else if (!strcmp (*argv, "--date"))
174         {
175           argc--; argv++;
176           if (argc)
177             {
178               opt_date = xstrdup (*argv);
179               argc--; argv++;
180             }
181         }
182       else if (!strncmp (*argv, "--", 2))
183         {
184           fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
185           exit (1);
186         }
187     }
188
189   if (opt_date && *opt_date)
190     {
191       time_t stamp;
192       struct tm *tp;
193
194       if (*opt_date == '2' && strlen (opt_date) >= 10
195           && opt_date[4] == '-' && opt_date[7] == '-')
196         {
197           opt_date[10] = 0;
198         }
199       else if ((stamp = strtoul (opt_date, NULL, 10)) > 0
200                && (tp = gmtime (&stamp)))
201         {
202           p = xmalloc (4+1+2+1+2+1);
203           snprintf (p, 4+1+2+1+2+1, "%04d-%02d-%02d",
204                     tp->tm_year + 1900, tp->tm_mon+1, tp->tm_mday);
205           xfree (opt_date);
206           opt_date = p;
207         }
208       else
209         {
210           fprintf (stderr, PGM ": bad date '%s'\n", opt_date);
211           exit (1);
212         }
213     }
214   else
215     {
216       xfree (opt_date);
217       opt_date = argc? get_date_from_files (argv) : NULL;
218     }
219   if (!opt_date)
220     {
221       opt_date = xstrdup ("unknown");
222       monthoff = 0;
223     }
224   else
225     {
226       const char *month = "?";
227
228       switch (atoi (opt_date+5))
229         {
230         case  1: month = "January"; break;
231         case  2: month = "February"; break;
232         case  3: month = "March"; break;
233         case  4: month = "April"; break;
234         case  5: month = "May"; break;
235         case  6: month = "June"; break;
236         case  7: month = "July"; break;
237         case  8: month = "August"; break;
238         case  9: month = "September"; break;
239         case 10: month = "October"; break;
240         case 11: month = "November"; break;
241         case 12: month = "December"; break;
242         }
243       n = strlen (opt_date) + strlen (month) + 2 + 1;
244       p = xmalloc (n);
245       snprintf (p, n, "%d %n%s %d",
246                 atoi (opt_date+8), &monthoff, month, atoi (opt_date));
247       xfree (opt_date);
248       opt_date = p;
249     }
250
251
252   fputs ("@c defs.inc                         -*- texinfo -*-\n"
253          "@c Common and build specific constants for the manuals.\n"
254          "@c This file has been created by " PGM ".\n", stdout);
255
256   fputs ("\n@c Directories\n\n", stdout);
257
258   fputs ("@set BINDIR         " GNUPG_BINDIR        "\n"
259          "@set LIBEXECDIR     " GNUPG_LIBEXECDIR    "\n"
260          "@set LIBDIR         " GNUPG_LIBDIR        "\n"
261          "@set DATADIR        " GNUPG_DATADIR       "\n"
262          "@set SYSCONFDIR     " GNUPG_SYSCONFDIR    "\n"
263          "@set LOCALSTATEDIR  " GNUPG_LOCALSTATEDIR "\n"
264          "@set LOCALCACHEDIR  " GNUPG_LOCALSTATEDIR
265          /*                  */ "/cache/" PACKAGE_NAME "\n"
266          "@set LOCALRUNDIR    " GNUPG_LOCALSTATEDIR
267          /*                  */ "/run/"  PACKAGE_NAME "\n"
268          , stdout);
269
270   p = xstrdup (GNUPG_SYSCONFDIR);
271   pend = strrchr (p, '/');
272   fputs ("@set SYSCONFSKELDIR ", stdout);
273   if (pend)
274     {
275       *pend = 0;
276       fputs (p, stdout);
277     }
278   fputs ("/skel/." PACKAGE_NAME "\n", stdout);
279   xfree (p);
280
281   fputs ("\n@c Version information a la version.texi\n\n", stdout);
282
283   printf ("@set UPDATED %s\n", opt_date);
284   printf ("@set UPDATED-MONTH %s\n", opt_date + monthoff);
285   printf ("@set EDITION %s\n", PACKAGE_VERSION);
286   printf ("@set VERSION %s\n", PACKAGE_VERSION);
287
288   fputs ("\n@c Algorithm defaults\n\n", stdout);
289
290   /* Fixme: Use a config.h macro here:  */
291   fputs ("@set GPGSYMENCALGO AES-128\n", stdout);
292
293
294   fputs ("\n"
295          "@c Loc" "al Variables:\n"
296          "@c buffer-read-only: t\n"
297          "@c End:\n", stdout);
298
299   if (ferror (stdout))
300     {
301       fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
302       return 1;
303     }
304
305   return 0;
306 }