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