#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#define PGM "mkheader"
#define LINESIZE 1024
static const char *host_os;
static char *host_triplet;
static char *srcdir;
static const char *hdr_version;
static const char *hdr_version_number;
static int have_stdint_h;
static int have_w32_system;
static int have_w64_system;
static char *replacement_for_off_type;
static int use_posix_threads;
static int stdint_h_included;
static void
xfree (void *a)
{
if (a)
free (a);
}
static char *
xstrdup (const char *string)
{
char *p;
p = malloc (strlen (string)+1);
if (!p)
{
fputs (PGM ": out of core\n", stderr);
exit (1);
}
strcpy (p, string);
return p;
}
static char *
canon_host_triplet (const char *triplet)
{
struct {
const char *name;
const char *alias;
} tbl[] = {
{"i486-pc-linux-gnu", "i686-pc-linux-gnu" },
{"i586-pc-linux-gnu" },
{"i486-pc-gnu", "i686-pc-gnu"},
{"i586-pc-gnu"},
{"i486-pc-kfreebsd-gnu", "i686-pc-kfreebsd-gnu"},
{"i586-pc-kfreebsd-gnu"},
{"x86_64-pc-linux-gnuhardened1", "x86_64-pc-linux-gnu" },
{"powerpc-unknown-linux-gnuspe", "powerpc-unknown-linux-gnu" },
{"arm-unknown-linux-gnueabihf", "arm-unknown-linux-gnueabi" },
{"armv7-unknown-linux-gnueabihf" },
{"armv5-unknown-linux-musleabi" },
{"armv6-unknown-linux-musleabihf" },
{ NULL }
};
int i;
const char *lastalias = NULL;
for (i=0; tbl[i].name; i++)
{
if (tbl[i].alias)
lastalias = tbl[i].alias;
if (!strcmp (tbl[i].name, triplet))
{
if (!lastalias)
break;
return xstrdup (lastalias);
}
}
return xstrdup (triplet);
}
static int
parse_config_h (const char *fname)
{
FILE *fp;
char line[LINESIZE];
int lnr = 0;
char *p1;
fp = fopen (fname, "r");
if (!fp)
{
fprintf (stderr, "%s:%d: can't open file: %s",
fname, lnr, strerror (errno));
return 1;
}
while (fgets (line, LINESIZE, fp))
{
size_t n = strlen (line);
lnr++;
if (!n || line[n-1] != '\n')
{
fprintf (stderr,
"%s:%d: trailing linefeed missing, line too long or "
"embedded nul character\n", fname, lnr);
break;
}
line[--n] = 0;
if (strncmp (line, "#define ", 8))
continue;
p1 = strtok (line + 8, " \t");
if (!*p1)
continue;
if (!strcmp (p1, "HAVE_STDINT_H"))
have_stdint_h = 1;
else if (!strcmp (p1, "HAVE_W32_SYSTEM"))
have_w32_system = 1;
else if (!strcmp (p1, "HAVE_W64_SYSTEM"))
have_w64_system = 1;
else if (!strcmp (p1, "REPLACEMENT_FOR_OFF_T"))
{
p1 = strtok (NULL, "\"");
if (!*p1)
continue;
xfree (replacement_for_off_type);
replacement_for_off_type = xstrdup (p1);
}
else if (!strcmp (p1, "USE_POSIX_THREADS"))
use_posix_threads = 1;
}
if (ferror (fp))
{
fprintf (stderr, "%s:%d: error reading file: %s\n",
fname, lnr, strerror (errno));
return 1;
}
fclose (fp);
return 0;
}
static void
write_str (char *line)
{
if (fputs (line, stdout) == EOF)
{
fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
exit (1);
}
}
static void
write_line (char *line)
{
if (puts (line) == EOF)
{
fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
exit (1);
}
}
static void
write_sources_or_codes (char *line)
{
static int in_intro;
char *p1, *p2;
if (!line)
{
in_intro = 1;
return;
}
if (!*line)
return;
if (in_intro)
{
if (!strchr ("0123456789", *line))
return;
in_intro = 0;
}
p1 = strtok (line, " \t");
p2 = p1? strtok (NULL, " \t") : NULL;
if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
{
write_str (" ");
write_str (p2);
write_str (" = ");
write_str (p1);
write_str (",\n");
}
}
static void
write_errnos_in (char *line)
{
static int state;
char *p1, *p2;
if (!line)
{
state = 0;
return;
}
if (!*line)
return;
if (!state && strchr ("0123456789", *line))
state = 1;
else if (state == 1 && !strchr ("0123456789", *line))
state = 2;
if (state != 1)
return;
p1 = strtok (line, " \t");
p2 = p1? strtok (NULL, " \t") : NULL;
if (p1 && p2 && strchr ("0123456789", *p1) && *p2)
{
write_str (" GPG_ERR_");
write_str (p2);
write_str (" = GPG_ERR_SYSTEM_ERROR | ");
write_str (p1);
write_str (",\n");
}
}
static char *
mk_include_name (const char *name, const char *repl)
{
FILE *fp;
char *incfname, *p;
const char *s;
incfname = malloc (strlen (srcdir) + strlen (name)
+ (repl?strlen (repl):0) + 1);
if (!incfname)
{
fputs (PGM ": out of core\n", stderr);
exit (1);
}
if (*name == '.' && name[1] == '/')
*incfname = 0;
else
strcpy (incfname, srcdir);
p = incfname + strlen (incfname);
for (s=name; *s; s++)
{
if (*s == '&' && repl)
{
while (*repl)
*p++ = *repl++;
repl = NULL;
}
else
*p++ = *s;
}
*p = 0;
return incfname;
}
static void
include_file (const char *fname, int lnr, const char *name, void (*outf)(char*))
{
FILE *fp;
char *incfname;
int inclnr;
char line[LINESIZE];
int repl_flag;
repl_flag = !!strchr (name, '&');
incfname = mk_include_name (name, repl_flag? host_triplet : NULL);
fp = fopen (incfname, "r");
if (!fp && repl_flag)
{
free (incfname);
incfname = mk_include_name (name, host_os);
fp = fopen (incfname, "r");
}
if (!fp)
{
fprintf (stderr, "%s:%d: error including `%s': %s\n",
fname, lnr, incfname, strerror (errno));
exit (1);
}
if (repl_flag)
fprintf (stderr,"%s:%d: note: including '%s'\n",
fname, lnr, incfname);
inclnr = 0;
while (fgets (line, LINESIZE, fp))
{
size_t n = strlen (line);
inclnr++;
if (!n || line[n-1] != '\n')
{
fprintf (stderr,
"%s:%d: trailing linefeed missing, line too long or "
"embedded nul character\n", incfname, inclnr);
fprintf (stderr,"%s:%d: note: file '%s' included from here\n",
fname, lnr, incfname);
exit (1);
}
line[--n] = 0;
while (line[n] == ' ' || line[n] == '\t' || line[n] == '\r')
{
line[n] = 0;
if (!n)
break;
n--;
}
if (line[0] == '#' && line[1] == '#')
{
if (!strncmp (line+2, "EOF##", 5))
break;
}
else
outf (line);
}
if (ferror (fp))
{
fprintf (stderr, "%s:%d: error reading `%s': %s\n",
fname, lnr, incfname, strerror (errno));
exit (1);
}
fclose (fp);
free (incfname);
}
static int
try_include_file (const char *fname, int lnr, const char *name,
void (*outf)(char*))
{
int rc;
char *incfname;
int repl_flag;
repl_flag = !!strchr (name, '&');
incfname = mk_include_name (name, repl_flag? host_triplet : NULL);
rc = access (incfname, R_OK);
if (rc && repl_flag)
{
free (incfname);
incfname = mk_include_name (name, host_os);
rc = access (incfname, R_OK);
}
if (!rc)
include_file (fname, lnr, name, outf);
free (incfname);
return rc;
}
static int
write_special (const char *fname, int lnr, const char *tag)
{
if (!strcmp (tag, "version"))
{
putchar ('\"');
fputs (hdr_version, stdout);
putchar ('\"');
}
else if (!strcmp (tag, "version-number"))
{
fputs (hdr_version_number, stdout);
}
else if (!strcmp (tag, "define:gpgrt_off_t"))
{
if (!replacement_for_off_type)
{
fprintf (stderr, "%s:%d: replacement for off_t not defined\n",
fname, lnr);
exit (1);
}
else
{
if (!strcmp (replacement_for_off_type, "int64_t")
&& !stdint_h_included && have_stdint_h)
{
fputs ("#include <stdint.h>\n\n", stdout);
stdint_h_included = 1;
}
printf ("typedef %s gpgrt_off_t;\n", replacement_for_off_type);
}
}
else if (!strcmp (tag, "define:gpgrt_ssize_t"))
{
if (have_w64_system)
{
if (!stdint_h_included && have_stdint_h)
{
fputs ("# include <stdint.h>\n", stdout);
stdint_h_included = 1;
}
fputs ("typedef int64_t gpgrt_ssize_t;\n", stdout);
}
else if (have_w32_system)
{
fputs ("typedef long gpgrt_ssize_t;\n", stdout);
}
else
{
fputs ("#include <sys/types.h>\n"
"typedef ssize_t gpgrt_ssize_t;\n", stdout);
}
}
else if (!strcmp (tag, "api_ssize_t"))
{
if (have_w32_system)
fputs ("gpgrt_ssize_t", stdout);
else
fputs ("ssize_t", stdout);
}
else if (!strcmp (tag, "include:err-sources"))
{
write_sources_or_codes (NULL);
include_file (fname, lnr, "err-sources.h.in", write_sources_or_codes);
}
else if (!strcmp (tag, "include:err-codes"))
{
write_sources_or_codes (NULL);
include_file (fname, lnr, "err-codes.h.in", write_sources_or_codes);
}
else if (!strcmp (tag, "include:errnos"))
{
include_file (fname, lnr, "errnos.in", write_errnos_in);
}
else if (!strcmp (tag, "include:os-add"))
{
if (!strcmp (host_os, "mingw32"))
{
include_file (fname, lnr, "w32-add.h", write_line);
}
else if (!strcmp (host_os, "mingw32ce"))
{
include_file (fname, lnr, "w32-add.h", write_line);
include_file (fname, lnr, "w32ce-add.h", write_line);
}
}
else if (!strcmp (tag, "include:lock-obj"))
{
if (try_include_file (fname, lnr, "./lock-obj-pub.native.h", write_line))
include_file (fname, lnr, "syscfg/lock-obj-pub.&.h", write_line);
}
else
return 0;
return 1;
}
int
main (int argc, char **argv)
{
FILE *fp;
char line[LINESIZE];
int lnr = 0;
const char *fname, *s;
char *p1, *p2;
const char *config_h;
const char *host_triplet_raw;
if (argc)
{
argc--; argv++;
}
if (argc != 6)
{
fputs ("usage: " PGM
" host_os host_triplet template.h config.h"
" version version_number\n",
stderr);
return 1;
}
host_os = argv[0];
host_triplet_raw = argv[1];
fname = argv[2];
config_h = argv[3];
hdr_version = argv[4];
hdr_version_number = argv[5];
host_triplet = canon_host_triplet (host_triplet_raw);
srcdir = malloc (strlen (fname) + 2 + 1);
if (!srcdir)
{
fputs (PGM ": out of core\n", stderr);
return 1;
}
strcpy (srcdir, fname);
p1 = strrchr (srcdir, '/');
if (p1)
p1[1] = 0;
else
strcpy (srcdir, "./");
if (parse_config_h (config_h))
return 1;
fp = fopen (fname, "r");
if (!fp)
{
fprintf (stderr, "%s:%d: can't open file: %s",
fname, lnr, strerror (errno));
return 1;
}
while (fgets (line, LINESIZE, fp))
{
size_t n = strlen (line);
lnr++;
if (!n || line[n-1] != '\n')
{
fprintf (stderr,
"%s:%d: trailing linefeed missing, line too long or "
"embedded nul character\n", fname, lnr);
break;
}
line[--n] = 0;
p1 = strchr (line, '@');
p2 = p1? strchr (p1+1, '@') : NULL;
if (!p1 || !p2 || p2-p1 == 1)
{
puts (line);
continue;
}
*p1++ = 0;
*p2++ = 0;
fputs (line, stdout);
if (!strcmp (p1, "configure_input"))
{
s = strrchr (fname, '/');
printf ("Do not edit. Generated from %s for:\n%*s",
s? s+1 : fname, (int)(p1 - line) + 13, "");
if (!strcmp (host_triplet, host_triplet_raw))
printf ("%s", host_triplet);
else
printf ("%s (%s)", host_triplet, host_triplet_raw);
if (!use_posix_threads && !have_w32_system && !have_w64_system)
fputs (" NO-THREADS", stdout);
fputs (p2, stdout);
}
else if (!write_special (fname, lnr, p1))
{
putchar ('@');
fputs (p1, stdout);
putchar ('@');
fputs (p2, stdout);
}
else if (*p2)
{
fputs (p2, stdout);
}
putchar ('\n');
}
if (ferror (fp))
{
fprintf (stderr, "%s:%d: error reading file: %s\n",
fname, lnr, strerror (errno));
return 1;
}
fputs ("/*\n"
"Loc" "al Variables:\n"
"buffer-read-only: t\n"
"End:\n"
"*/\n", stdout);
if (ferror (stdout))
{
fprintf (stderr, PGM ": error writing to stdout: %s\n", strerror (errno));
return 1;
}
fclose (fp);
xfree (host_triplet);
return 0;
}