#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
#endif
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#include <limits.h>
#ifdef HAVE_UTIME_H
# include <utime.h>
#endif
#ifdef HAVE_SYS_UTIME_H
# include <sys/utime.h>
#endif
#include <errno.h>
#ifdef NeXT
# include <libc.h>
#endif
#include "wget.h"
#include "utils.h"
#include "fnmatch.h"
#ifndef errno
extern int errno;
#endif
static void
memfatal (const char *s)
{
extern int save_log_p;
save_log_p = 0;
logprintf (LOG_ALWAYS, _("%s: %s: Not enough memory.\n"), exec_name, s);
exit (1);
}
void *
xmalloc (size_t size)
{
void *res;
res = malloc (size);
if (!res)
memfatal ("malloc");
return res;
}
void *
xrealloc (void *obj, size_t size)
{
void *res;
if (obj)
res = realloc (obj, size);
else
res = malloc (size);
if (!res)
memfatal ("realloc");
return res;
}
char *
xstrdup (const char *s)
{
#ifndef HAVE_STRDUP
int l = strlen (s);
char *s1 = malloc (l + 1);
if (!s1)
memfatal ("strdup");
memcpy (s1, s, l + 1);
return s1;
#else
char *s1 = strdup (s);
if (!s1)
memfatal ("strdup");
return s1;
#endif
}
char *
strdupdelim (const char *beg, const char *end)
{
char *res = (char *)xmalloc (end - beg + 1);
memcpy (res, beg, end - beg);
res[end - beg] = '\0';
return res;
}
char **
sepstring (const char *s)
{
char **res;
const char *p;
int i = 0;
if (!s || !*s)
return NULL;
res = NULL;
p = s;
while (*s)
{
if (*s == ',')
{
res = (char **)xrealloc (res, (i + 2) * sizeof (char *));
res[i] = strdupdelim (p, s);
res[++i] = NULL;
++s;
while (ISSPACE (*s))
++s;
p = s;
}
else
++s;
}
res = (char **)xrealloc (res, (i + 2) * sizeof (char *));
res[i] = strdupdelim (p, s);
res[i + 1] = NULL;
return res;
}
char *
time_str (time_t *tm)
{
static char tms[15];
struct tm *ptm;
time_t tim;
*tms = '\0';
tim = time (tm);
if (tim == -1)
return tms;
ptm = localtime (&tim);
sprintf (tms, "%02d:%02d:%02d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
return tms;
}
const char *
uerrmsg (uerr_t errnum)
{
switch (errnum)
{
case URLUNKNOWN:
return _("Unknown/unsupported protocol");
break;
case URLBADPORT:
return _("Invalid port specification");
break;
case URLBADHOST:
return _("Invalid host name");
break;
default:
abort ();
return NULL;
}
}
#ifndef WINDOWS
char *
pwd_cuserid (char *where)
{
struct passwd *pwd;
if (!(pwd = getpwuid (getuid ())) || !pwd->pw_name)
return NULL;
if (where)
{
strcpy (where, pwd->pw_name);
return where;
}
else
return pwd->pw_name;
}
void
fork_to_background (void)
{
pid_t pid;
int changedp = 0;
if (!opt.lfilename)
{
opt.lfilename = unique_name (DEFAULT_LOGFILE);
changedp = 1;
}
pid = fork ();
if (pid < 0)
{
perror ("fork");
exit (1);
}
else if (pid != 0)
{
printf (_("Continuing in background.\n"));
if (changedp)
printf (_("Output will be written to `%s'.\n"), opt.lfilename);
exit (0);
}
}
#endif
void
path_simplify (char *path)
{
register int i, start, ddot;
char stub_char;
if (!*path)
return;
stub_char = '/';
i = 0;
ddot = 0;
while (1)
{
if (path[i] == '.' && path[i + 1] == '/')
i += 2;
else if (path[i] == '.' && path[i + 1] == '.' && path[i + 2] == '/')
{
i += 3;
ddot = 1;
}
else
break;
}
if (i)
strcpy (path, path + i - ddot);
if ((path[0] == '.' && path[1] == '\0')
|| (path[0] == '.' && path[1] == '.' && path[2] == '\0'))
{
path[0] = stub_char;
path[1] = '\0';
return;
}
i = 0;
while (1)
{
if (!path[i])
break;
while (path[i] && path[i] != '/')
i++;
start = i++;
if (!path[start])
break;
while (path[i] == '/')
i++;
if ((start + 1) != i)
{
strcpy (path + start + 1, path + i);
i = start + 1;
}
if (start && !path[i])
{
zero_last:
path[--i] = '\0';
break;
}
if (path[i] == '.')
{
if (!path[i + 1])
goto zero_last;
if (path[i + 1] == '/')
{
strcpy (path + i, path + i + 1);
i = (start < 0) ? 0 : start;
continue;
}
if (path[i + 1] == '.' &&
(path[i + 2] == '/' || !path[i + 2]))
{
while (--start > -1 && path[start] != '/');
strcpy (path + start + 1, path + i + 2);
i = (start < 0) ? 0 : start;
continue;
}
}
}
if (!*path)
{
*path = stub_char;
path[1] = '\0';
}
}
void
touch (const char *file, time_t tm)
{
#ifdef HAVE_STRUCT_UTIMBUF
struct utimbuf times;
times.actime = times.modtime = tm;
#else
time_t times[2];
times[0] = times[1] = tm;
#endif
if (utime (file, ×) == -1)
logprintf (LOG_NOTQUIET, "utime: %s\n", strerror (errno));
}
int
remove_link (const char *file)
{
int err = 0;
struct stat st;
if (lstat (file, &st) == 0 && S_ISLNK (st.st_mode))
{
DEBUGP (("Unlinking %s (symlink).\n", file));
err = unlink (file);
if (err != 0)
logprintf (LOG_VERBOSE, _("Failed to unlink symlink `%s': %s\n"),
file, strerror (errno));
}
return err;
}
int
file_exists_p (const char *filename)
{
#ifdef HAVE_ACCESS
return access (filename, F_OK) >= 0;
#else
struct stat buf;
return stat (filename, &buf) >= 0;
#endif
}
int
file_non_directory_p (const char *path)
{
struct stat buf;
if (lstat (path, &buf) != 0)
return 0;
return S_ISDIR (buf.st_mode) ? 0 : 1;
}
static char *
unique_name_1 (const char *fileprefix, int count)
{
char *filename;
if (count)
{
filename = (char *)xmalloc (strlen (fileprefix) + numdigit (count) + 2);
sprintf (filename, "%s.%d", fileprefix, count);
}
else
filename = xstrdup (fileprefix);
if (!file_exists_p (filename))
return filename;
else
{
free (filename);
return NULL;
}
}
char *
unique_name (const char *prefix)
{
char *file = NULL;
int count = 0;
while (!file)
file = unique_name_1 (prefix, count++);
return file;
}
int
make_directory (const char *directory)
{
int quit = 0;
int i;
char *dir;
STRDUP_ALLOCA (dir, directory);
for (i = (*dir == '/'); 1; ++i)
{
for (; dir[i] && dir[i] != '/'; i++)
;
if (!dir[i])
quit = 1;
dir[i] = '\0';
if (!file_exists_p (dir))
{
if (mkdir (dir, 0777) < 0)
return -1;
}
if (quit)
break;
else
dir[i] = '/';
}
return 0;
}
static int in_acclist PARAMS ((const char *const *, const char *, int));
int
acceptable (const char *s)
{
int l = strlen (s);
while (l && s[l] != '/')
--l;
if (s[l] == '/')
s += (l + 1);
if (opt.accepts)
{
if (opt.rejects)
return (in_acclist ((const char *const *)opt.accepts, s, 1)
&& !in_acclist ((const char *const *)opt.rejects, s, 1));
else
return in_acclist ((const char *const *)opt.accepts, s, 1);
}
else if (opt.rejects)
return !in_acclist ((const char *const *)opt.rejects, s, 1);
return 1;
}
int
frontcmp (const char *s1, const char *s2)
{
for (; *s1 && *s2 && (*s1 == *s2); ++s1, ++s2);
return !*s1;
}
static char *
proclist (char **strlist, const char *s, enum accd flags)
{
char **x;
for (x = strlist; *x; x++)
if (has_wildcards_p (*x))
{
if (fnmatch (*x, s, FNM_PATHNAME) == 0)
break;
}
else
{
char *p = *x + ((flags & ALLABS) && (**x == '/'));
if (frontcmp (p, s))
break;
}
return *x;
}
int
accdir (const char *directory, enum accd flags)
{
if (flags & ALLABS && *directory == '/')
++directory;
if (opt.includes)
{
if (!proclist (opt.includes, directory, flags))
return 0;
}
if (opt.excludes)
{
if (proclist (opt.excludes, directory, flags))
return 0;
}
return 1;
}
static int
match_backwards (const char *string, const char *pattern)
{
int i, j;
for (i = strlen (string), j = strlen (pattern); i >= 0 && j >= 0; i--, j--)
if (string[i] != pattern[j])
break;
if (j == -1)
return 1;
else
return 0;
}
static int
in_acclist (const char *const *accepts, const char *s, int backward)
{
for (; *accepts; accepts++)
{
if (has_wildcards_p (*accepts))
{
if (fnmatch (*accepts, s, 0) == 0)
return 1;
}
else
{
if (backward)
{
if (match_backwards (s, *accepts))
return 1;
}
else
{
if (!strcmp (s, *accepts))
return 1;
}
}
}
return 0;
}
char *
suffix (const char *str)
{
int i;
for (i = strlen (str); i && str[i] != '/' && str[i] != '.'; i--);
if (str[i++] == '.')
return xstrdup (str + i);
else
return NULL;
}
char *
read_whole_line (FILE *fp)
{
char *line;
int i, bufsize, c;
i = 0;
bufsize = 40;
line = (char *)xmalloc (bufsize);
while ((c = getc (fp)) != EOF && c != '\n')
{
if (i > bufsize - 1)
line = (char *)xrealloc (line, (bufsize <<= 1));
line[i++] = c;
}
if (c == EOF && !i)
{
free (line);
return NULL;
}
if (i == bufsize)
line = (char *)xrealloc (line, i + 1);
line[i] = '\0';
return line;
}
void
load_file (FILE *fp, char **buf, long *nread)
{
long bufsize;
bufsize = 512;
*nread = 0;
*buf = NULL;
while (!feof (fp) && !ferror (fp))
{
*buf = (char *)xrealloc (*buf, bufsize + *nread);
*nread += fread (*buf + *nread, sizeof (char), bufsize, fp);
bufsize <<= 1;
}
}
void
free_vec (char **vec)
{
if (vec)
{
char **p = vec;
while (*p)
free (*p++);
free (vec);
}
}
char **
merge_vecs (char **v1, char **v2)
{
int i, j;
if (!v1)
return v2;
if (!v2)
return v1;
if (!*v2)
{
free (v2);
return v1;
}
for (i = 0; v1[i]; i++);
for (j = 0; v2[j]; j++);
v1 = (char **)xrealloc (v1, (i + j + 1) * sizeof (char **));
memcpy (v1 + i, v2, (j + 1) * sizeof (char *));
free (v2);
return v1;
}
slist *
add_slist (slist *l, const char *s, int flags)
{
slist *t, *old, *beg;
int cmp;
if (flags & NOSORT)
{
if (!l)
{
t = (slist *)xmalloc (sizeof (slist));
t->string = xstrdup (s);
t->next = NULL;
return t;
}
beg = l;
while (l->next)
l = l->next;
t = (slist *)xmalloc (sizeof (slist));
l->next = t;
t->string = xstrdup (s);
t->next = NULL;
return beg;
}
if (!l || (cmp = strcmp (l->string, s)) > 0)
{
t = (slist *)xmalloc (sizeof (slist));
t->string = xstrdup (s);
t->next = l;
return t;
}
beg = l;
if (cmp == 0)
return beg;
while (l->next)
{
old = l;
l = l->next;
cmp = strcmp (s, l->string);
if (cmp == 0)
return beg;
else if (cmp > 0)
continue;
t = (slist *)xmalloc (sizeof (slist));
old->next = t;
t->next = l;
t->string = xstrdup (s);
return beg;
}
t = (slist *)xmalloc (sizeof (slist));
t->string = xstrdup (s);
l->next = t;
t->next = NULL;
return beg;
}
int
in_slist (slist *l, const char *s)
{
int cmp;
while (l)
{
cmp = strcmp (l->string, s);
if (cmp == 0)
return 1;
else if (cmp > 0)
return 0;
l = l->next;
}
return 0;
}
void
free_slist (slist *l)
{
slist *n;
while (l)
{
n = l->next;
free (l->string);
free (l);
l = n;
}
}
char *
legible (long l)
{
static char outbuf[20];
char inbuf[20];
int i, i1, mod;
char *outptr, *inptr;
long_to_string (inbuf, l);
outptr = outbuf;
inptr = inbuf;
if (*inptr == '-')
{
*outptr++ = '-';
++inptr;
}
mod = strlen (inptr) % 3;
for (i = 0; i < mod; i++)
*outptr++ = inptr[i];
for (i1 = i, i = 0; inptr[i1]; i++, i1++)
{
if (i % 3 == 0 && i1 != 0)
*outptr++ = ',';
*outptr++ = inptr[i1];
}
*outptr = '\0';
return outbuf;
}
int
numdigit (long a)
{
int res = 1;
while ((a /= 10) != 0)
++res;
return res;
}
void
long_to_string (char *buffer, long number)
{
char *p;
int i, l;
if (number < 0)
{
*buffer++ = '-';
number = -number;
}
p = buffer;
do
{
*p++ = number % 10 + '0';
number /= 10;
}
while (number);
l = p - buffer - 1;
for (i = l/2; i >= 0; i--)
{
char c = buffer[i];
buffer[i] = buffer[l - i];
buffer[l - i] = c;
}
buffer[l + 1] = '\0';
}