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