Updating to version 1.13. Libgcrypt depends on libgpg-error
[platform/upstream/libgpg-error.git] / src / mkheader.c
1 /* mkheader.c - Create a header file for libgpg-error
2  * Copyright (C) 2010 Free Software Foundation, Inc.
3  * Copyright (C) 2014 g10 Code GmbH
4  *
5  * This file is free software; as a special exception the author gives
6  * unlimited permission to copy and/or distribute it, with or without
7  * modifications, as long as this notice is preserved.
8  *
9  * This file is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
11  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  */
13
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20
21 #define PGM "mkheader"
22
23 #define LINESIZE 1024
24
25 static const char *host_os;
26 static const char *host_triplet;
27 static char *srcdir;
28 static const char *hdr_version;
29 static const char *hdr_version_number;
30
31
32 /* Write LINE to stdout.  The function is allowed to modify LINE.  */
33 static void
34 write_str (char *line)
35 {
36   if (fputs (line, stdout) == EOF)
37     {
38       fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
39       exit (1);
40     }
41 }
42
43 static void
44 write_line (char *line)
45 {
46   if (puts (line) == EOF)
47     {
48       fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
49       exit (1);
50     }
51 }
52
53
54 /* Write SOURCE or CODES line to stdout.  The function is allowed to
55    modify LINE.  Trailing white space is already removed.  Passing
56    NULL resets the internal state.  */
57 static void
58 write_sources_or_codes (char *line)
59 {
60   static int in_intro;
61   char *p1, *p2;
62
63   if (!line)
64     {
65       in_intro = 1;
66       return;
67     }
68
69   if (!*line)
70     return;
71
72   if (in_intro)
73     {
74       if (!strchr ("0123456789", *line))
75         return;
76       in_intro = 0;
77     }
78
79   p1 = strtok (line, " \t");
80   p2 = p1? strtok (NULL, " \t") : NULL;
81
82   if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
83     {
84       write_str ("    ");
85       write_str (p2);
86       write_str (" = ");
87       write_str (p1);
88       write_str (",\n");
89     }
90 }
91
92
93 /* Write system errnos to stdout.  The function is allowed to
94    modify LINE.  Trailing white space is already removed.  Passing
95    NULL resets the internal state.  */
96 static void
97 write_errnos_in (char *line)
98 {
99   static int state;
100   char *p1, *p2;
101
102   if (!line)
103     {
104       state = 0;
105       return;
106     }
107
108   if (!*line)
109     return;
110
111   if (!state && strchr ("0123456789", *line))
112     state = 1;
113   else if (state == 1 && !strchr ("0123456789", *line))
114     state = 2;
115
116   if (state != 1)
117     return;
118
119   p1 = strtok (line, " \t");
120   p2 = p1? strtok (NULL, " \t") : NULL;
121
122   if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
123     {
124       write_str ("    GPG_ERR_");
125       write_str (p2);
126       write_str (" = GPG_ERR_SYSTEM_ERROR | ");
127       write_str (p1);
128       write_str (",\n");
129     }
130 }
131
132
133 /* Create the full file name for NAME and return a newly allocated
134    string with it.  If name contains a '&' and REPL is not NULL
135    replace '&' with REPL. */
136 static char *
137 mk_include_name (const char *name, const char *repl)
138 {
139   FILE *fp;
140   char *incfname, *p;
141   const char *s;
142
143   incfname = malloc (strlen (srcdir) + strlen (name)
144                      + (repl?strlen (repl):0) + 1);
145   if (!incfname)
146     {
147       fputs (PGM ": out of core\n", stderr);
148       exit (1);
149     }
150
151   if (*name == '.' && name[1] == '/')
152     *incfname = 0;
153   else
154     strcpy (incfname, srcdir);
155   p = incfname + strlen (incfname);
156   for (s=name; *s; s++)
157     {
158       if (*s == '&' && repl)
159         {
160           while (*repl)
161             *p++ = *repl++;
162           repl = NULL;  /* Replace only once.  */
163         }
164       else
165         *p++ = *s;
166     }
167   *p = 0;
168   return incfname;
169 }
170
171
172 /* Include the file NAME from the source directory.  The included file
173    is not further expanded.  It may have comments indicated by a
174    double hash mark at the begin of a line.  OUTF is called for each
175    read line and passed a buffer with the content of line sans line
176    line endings.  If NAME is prefixed with "./" it is included from
177    the current directory and not from the source directory. */
178 static void
179 include_file (const char *fname, int lnr, const char *name, void (*outf)(char*))
180 {
181   FILE *fp;
182   char *incfname;
183   int inclnr;
184   char line[LINESIZE];
185   int repl_flag;
186
187   repl_flag = !!strchr (name, '&');
188   incfname = mk_include_name (name, repl_flag? host_triplet : NULL);
189   fp = fopen (incfname, "r");
190   if (!fp && repl_flag)
191     {
192       /* Try again using the OS string.  */
193       free (incfname);
194       incfname = mk_include_name (name, host_os);
195       fp = fopen (incfname, "r");
196     }
197   if (!fp)
198     {
199       fprintf (stderr, "%s:%d: error including `%s': %s\n",
200                fname, lnr, incfname, strerror (errno));
201       exit (1);
202     }
203
204   if (repl_flag)
205     fprintf (stderr,"%s:%d: note: including '%s'\n",
206              fname, lnr, incfname);
207
208   inclnr = 0;
209   while (fgets (line, LINESIZE, fp))
210     {
211       size_t n = strlen (line);
212
213       inclnr++;
214       if (!n || line[n-1] != '\n')
215         {
216           fprintf (stderr,
217                    "%s:%d: trailing linefeed missing, line too long or "
218                    "embedded nul character\n", incfname, inclnr);
219           fprintf (stderr,"%s:%d: note: file '%s' included from here\n",
220                    fname, lnr, incfname);
221           exit (1);
222         }
223       line[--n] = 0;
224       while (line[n] == ' ' || line[n] == '\t' || line[n] == '\r')
225         {
226           line[n] = 0;
227           if (!n)
228             break;
229           n--;
230         }
231
232       if (line[0] == '#' && line[1] == '#')
233         {
234           if (!strncmp (line+2, "EOF##", 5))
235             break; /* Forced EOF.  */
236         }
237       else
238         outf (line);
239     }
240   if (ferror (fp))
241     {
242       fprintf (stderr, "%s:%d: error reading `%s': %s\n",
243                fname, lnr, incfname, strerror (errno));
244       exit (1);
245     }
246   fclose (fp);
247   free (incfname);
248 }
249
250
251 /* Try to include the file NAME.  Returns true if it does not
252    exist. */
253 static int
254 try_include_file (const char *fname, int lnr, const char *name,
255                   void (*outf)(char*))
256 {
257   int rc;
258   char *incfname;
259   int repl_flag;
260
261   repl_flag = !!strchr (name, '&');
262   incfname = mk_include_name (name, repl_flag? host_triplet : NULL);
263   rc = access (incfname, R_OK);
264   if (rc && repl_flag)
265     {
266       free (incfname);
267       incfname = mk_include_name (name, host_os);
268       rc = access (incfname, R_OK);
269     }
270   if (!rc)
271     include_file (fname, lnr, name, outf);
272
273   free (incfname);
274   return rc;
275 }
276
277
278 static int
279 write_special (const char *fname, int lnr, const char *tag)
280 {
281   if (!strcmp (tag, "version"))
282     {
283       putchar ('\"');
284       fputs (hdr_version, stdout);
285       putchar ('\"');
286       putchar ('\n');
287     }
288   else if (!strcmp (tag, "version-number"))
289     {
290       fputs (hdr_version_number, stdout);
291       putchar ('\n');
292     }
293   else if (!strcmp (tag, "include:err-sources"))
294     {
295       write_sources_or_codes (NULL);
296       include_file (fname, lnr, "err-sources.h.in", write_sources_or_codes);
297     }
298   else if (!strcmp (tag, "include:err-codes"))
299     {
300       write_sources_or_codes (NULL);
301       include_file (fname, lnr, "err-codes.h.in", write_sources_or_codes);
302     }
303   else if (!strcmp (tag, "include:errnos"))
304     {
305       include_file (fname, lnr, "errnos.in", write_errnos_in);
306     }
307   else if (!strcmp (tag, "include:os-add"))
308     {
309       if (!strcmp (host_os, "mingw32"))
310         {
311           include_file (fname, lnr, "w32-add.h", write_line);
312         }
313       else if (!strcmp (host_os, "mingw32ce"))
314         {
315           include_file (fname, lnr, "w32-add.h", write_line);
316           include_file (fname, lnr, "w32ce-add.h", write_line);
317         }
318     }
319   else if (!strcmp (tag, "include:lock-obj"))
320     {
321       if (try_include_file (fname, lnr, "./lock-obj-pub.native.h", write_line))
322         include_file (fname, lnr, "syscfg/lock-obj-pub.&.h", write_line);
323     }
324   else
325     return 0; /* Unknown tag.  */
326
327   return 1; /* Tag processed.  */
328 }
329
330
331 int
332 main (int argc, char **argv)
333 {
334   FILE *fp;
335   char line[LINESIZE];
336   int lnr = 0;
337   const char *fname, *s;
338   char *p1, *p2;
339
340   if (argc)
341     {
342       argc--; argv++;
343     }
344
345   if (argc != 5)
346     {
347       fputs ("usage: " PGM
348              " host_os host_triplet template.h version version_number\n",
349              stderr);
350       return 1;
351     }
352   host_os = argv[0];
353   host_triplet = argv[1];
354   fname = argv[2];
355   hdr_version = argv[3];
356   hdr_version_number = argv[4];
357
358   srcdir = malloc (strlen (fname) + 2 + 1);
359   if (!srcdir)
360     {
361       fputs (PGM ": out of core\n", stderr);
362       return 1;
363     }
364   strcpy (srcdir, fname);
365   p1 = strrchr (srcdir, '/');
366   if (p1)
367     p1[1] = 0;
368   else
369     strcpy (srcdir, "./");
370
371   fp = fopen (fname, "r");
372   if (!fp)
373     {
374       fprintf (stderr, "%s:%d: can't open file: %s",
375                fname, lnr, strerror (errno));
376       return 1;
377     }
378
379   while (fgets (line, LINESIZE, fp))
380     {
381       size_t n = strlen (line);
382
383       lnr++;
384       if (!n || line[n-1] != '\n')
385         {
386           fprintf (stderr,
387                    "%s:%d: trailing linefeed missing, line too long or "
388                    "embedded nul character\n", fname, lnr);
389           break;
390         }
391       line[--n] = 0;
392
393       p1 = strchr (line, '@');
394       p2 = p1? strchr (p1+1, '@') : NULL;
395       if (!p1 || !p2 || p2-p1 == 1)
396         {
397           puts (line);
398           continue;
399         }
400       *p1++ = 0;
401       *p2++ = 0;
402       fputs (line, stdout);
403
404       if (!strcmp (p1, "configure_input"))
405         {
406           s = strrchr (fname, '/');
407           printf ("Do not edit.  Generated from %s for %s.",
408                   s? s+1 : fname, host_triplet);
409           fputs (p2, stdout);
410           putchar ('\n');
411         }
412       else if (!write_special (fname, lnr, p1))
413         {
414           putchar ('@');
415           fputs (p1, stdout);
416           putchar ('@');
417           fputs (p2, stdout);
418           putchar ('\n');
419         }
420     }
421
422   if (ferror (fp))
423     {
424       fprintf (stderr, "%s:%d: error reading file: %s\n",
425                fname, lnr, strerror (errno));
426       return 1;
427     }
428
429   fputs ("/*\n"
430          "Loc" "al Variables:\n"
431          "buffer-read-only: t\n"
432          "End:\n"
433          "*/\n", stdout);
434
435   if (ferror (stdout))
436     {
437       fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
438       return 1;
439     }
440
441   fclose (fp);
442
443   return 0;
444 }