#include "config.h"
#include "system.h"
#include "mkdeps.h"
struct deps
{
const char **targetv;
unsigned int ntargets;
unsigned int targets_size;
const char **depv;
unsigned int ndeps;
unsigned int deps_size;
const char **vpathv;
size_t *vpathlv;
unsigned int nvpaths;
unsigned int vpaths_size;
};
static const char *munge (const char *);
static const char *
munge (const char *filename)
{
int len;
const char *p, *q;
char *dst, *buffer;
for (p = filename, len = 0; *p; p++, len++)
{
switch (*p)
{
case ' ':
case '\t':
for (q = p - 1; filename <= q && *q == '\\'; q--)
len++;
len++;
break;
case '$':
len++;
break;
}
}
buffer = xmalloc (len + 1);
for (p = filename, dst = buffer; *p; p++, dst++)
{
switch (*p)
{
case ' ':
case '\t':
for (q = p - 1; filename <= q && *q == '\\'; q--)
*dst++ = '\\';
*dst++ = '\\';
break;
case '$':
*dst++ = '$';
break;
default:
;
}
*dst = *p;
}
*dst = '\0';
return buffer;
}
static const char *
apply_vpath (struct deps *d, const char *t)
{
if (d->vpathv)
{
unsigned int i;
for (i = 0; i < d->nvpaths; i++)
{
if (!strncmp (d->vpathv[i], t, d->vpathlv[i]))
{
const char *p = t + d->vpathlv[i];
if (!IS_DIR_SEPARATOR (*p))
goto not_this_one;
if (p[1] == '.' && p[2] == '.' && IS_DIR_SEPARATOR (p[3]))
goto not_this_one;
t = t + d->vpathlv[i] + 1;
break;
}
not_this_one:;
}
}
while (t[0] == '.' && IS_DIR_SEPARATOR (t[1]))
t += 2;
return t;
}
struct deps *
deps_init (void)
{
return xcalloc (sizeof (struct deps), 1);
}
void
deps_free (struct deps *d)
{
unsigned int i;
if (d->targetv)
{
for (i = 0; i < d->ntargets; i++)
free ((void *) d->targetv[i]);
free (d->targetv);
}
if (d->depv)
{
for (i = 0; i < d->ndeps; i++)
free ((void *) d->depv[i]);
free (d->depv);
}
if (d->vpathv)
{
for (i = 0; i < d->nvpaths; i++)
free ((void *) d->vpathv[i]);
free (d->vpathv);
free (d->vpathlv);
}
free (d);
}
void
deps_add_target (struct deps *d, const char *t, int quote)
{
if (d->ntargets == d->targets_size)
{
d->targets_size = d->targets_size * 2 + 4;
d->targetv = xrealloc (d->targetv,
d->targets_size * sizeof (const char *));
}
t = apply_vpath (d, t);
if (quote)
t = munge (t);
else
t = xstrdup (t);
d->targetv[d->ntargets++] = t;
}
void
deps_add_default_target (struct deps *d, const char *tgt)
{
if (d->ntargets)
return;
if (tgt[0] == '\0')
deps_add_target (d, "-", 1);
else
{
#ifndef TARGET_OBJECT_SUFFIX
# define TARGET_OBJECT_SUFFIX ".o"
#endif
const char *start = lbasename (tgt);
char *o = alloca (strlen (start) + strlen (TARGET_OBJECT_SUFFIX) + 1);
char *suffix;
strcpy (o, start);
suffix = strrchr (o, '.');
if (!suffix)
suffix = o + strlen (o);
strcpy (suffix, TARGET_OBJECT_SUFFIX);
deps_add_target (d, o, 1);
}
}
void
deps_add_dep (struct deps *d, const char *t)
{
t = munge (apply_vpath (d, t));
if (d->ndeps == d->deps_size)
{
d->deps_size = d->deps_size * 2 + 8;
d->depv = xrealloc (d->depv, d->deps_size * sizeof (const char *));
}
d->depv[d->ndeps++] = t;
}
void
deps_add_vpath (struct deps *d, const char *vpath)
{
const char *elem, *p;
char *copy;
size_t len;
for (elem = vpath; *elem; elem = p)
{
for (p = elem; *p && *p != ':'; p++);
len = p - elem;
copy = xmalloc (len + 1);
memcpy (copy, elem, len);
copy[len] = '\0';
if (*p == ':')
p++;
if (d->nvpaths == d->vpaths_size)
{
d->vpaths_size = d->vpaths_size * 2 + 8;
d->vpathv = xrealloc (d->vpathv,
d->vpaths_size * sizeof (const char *));
d->vpathlv = xrealloc (d->vpathlv, d->vpaths_size * sizeof (size_t));
}
d->vpathv[d->nvpaths] = copy;
d->vpathlv[d->nvpaths] = len;
d->nvpaths++;
}
}
void
deps_write (const struct deps *d, FILE *fp, unsigned int colmax)
{
unsigned int size, i, column;
column = 0;
if (colmax && colmax < 34)
colmax = 34;
for (i = 0; i < d->ntargets; i++)
{
size = strlen (d->targetv[i]);
column += size;
if (colmax && column > colmax)
{
fputs (" \\\n ", fp);
column = 1 + size;
}
if (i)
{
putc (' ', fp);
column++;
}
fputs (d->targetv[i], fp);
}
putc (':', fp);
putc (' ', fp);
column += 2;
for (i = 0; i < d->ndeps; i++)
{
size = strlen (d->depv[i]);
column += size;
if (colmax && column > colmax)
{
fputs (" \\\n ", fp);
column = 1 + size;
}
if (i)
{
putc (' ', fp);
column++;
}
fputs (d->depv[i], fp);
}
putc ('\n', fp);
}
void
deps_phony_targets (const struct deps *d, FILE *fp)
{
unsigned int i;
for (i = 1; i < d->ndeps; i++)
{
putc ('\n', fp);
fputs (d->depv[i], fp);
putc (':', fp);
putc ('\n', fp);
}
}
int
deps_save (struct deps *deps, FILE *f)
{
unsigned int i;
if (fwrite (&deps->ndeps, sizeof (deps->ndeps), 1, f) != 1)
return -1;
for (i = 0; i < deps->ndeps; i++)
{
size_t num_to_write = strlen (deps->depv[i]);
if (fwrite (&num_to_write, sizeof (size_t), 1, f) != 1)
return -1;
if (fwrite (deps->depv[i], num_to_write, 1, f) != 1)
return -1;
}
return 0;
}
int
deps_restore (struct deps *deps, FILE *fd, const char *self)
{
unsigned int i, count;
size_t num_to_read;
size_t buf_size = 512;
char *buf = xmalloc (buf_size);
if (fread (&count, 1, sizeof (count), fd) != sizeof (count))
return -1;
for (i = 0; i < count; i++)
{
if (fread (&num_to_read, 1, sizeof (size_t), fd) != sizeof (size_t))
return -1;
if (buf_size < num_to_read + 1)
{
buf_size = num_to_read + 1 + 127;
buf = xrealloc (buf, buf_size);
}
if (fread (buf, 1, num_to_read, fd) != num_to_read)
return -1;
buf[num_to_read] = '\0';
if (self != NULL && strcmp (buf, self) != 0)
deps_add_dep (deps, buf);
}
free (buf);
return 0;
}