📄 utils.c
字号:
/* Various utility functions. Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.This file is part of GNU Wget.GNU Wget is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 3 of the License, or(at your option) any later version.GNU Wget is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with Wget. If not, see <http://www.gnu.org/licenses/>.Additional permission under GNU GPL version 3 section 7If you modify this program, or any covered work, by linking orcombining it with the OpenSSL project's OpenSSL library (or amodified version of that library), containing parts covered by theterms of the OpenSSL or SSLeay licenses, the Free Software Foundationgrants you additional permission to convey the resulting work.Corresponding Source for a non-source form of such a combinationshall include the source code for the parts of OpenSSL used as wellas that of the covered work. */#include <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#ifdef HAVE_SYS_TIME_H# include <sys/time.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#ifdef HAVE_MMAP# include <sys/mman.h>#endif#ifdef HAVE_PROCESS_H# include <process.h> /* getpid() */#endif#ifdef HAVE_UTIME_H# include <utime.h>#endif#ifdef HAVE_SYS_UTIME_H# include <sys/utime.h>#endif#include <errno.h>#include <fcntl.h>#include <assert.h>#include <stdarg.h>#include <locale.h>/* For TIOCGWINSZ and friends: */#ifdef HAVE_SYS_IOCTL_H# include <sys/ioctl.h>#endif#ifdef HAVE_TERMIOS_H# include <termios.h>#endif/* Needed for Unix version of run_with_timeout. */#include <signal.h>#include <setjmp.h>#ifndef HAVE_SIGSETJMP/* If sigsetjmp is a macro, configure won't pick it up. */# ifdef sigsetjmp# define HAVE_SIGSETJMP# endif#endif#if defined HAVE_SIGSETJMP || defined HAVE_SIGBLOCK# define USE_SIGNAL_TIMEOUT#endif#include "wget.h"#include "utils.h"#include "hash.h"#ifdef TESTING#include "test.h"#endif /* Utility function: like xstrdup(), but also lowercases S. */char *xstrdup_lower (const char *s){ char *copy = xstrdup (s); char *p = copy; for (; *p; p++) *p = TOLOWER (*p); return copy;}/* Copy the string formed by two pointers (one on the beginning, other on the char after the last char) to a new, malloc-ed location. 0-terminate it. */char *strdupdelim (const char *beg, const char *end){ char *res = xmalloc (end - beg + 1); memcpy (res, beg, end - beg); res[end - beg] = '\0'; return res;}/* Parse a string containing comma-separated elements, and return a vector of char pointers with the elements. Spaces following the commas are ignored. */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 = xrealloc (res, (i + 2) * sizeof (char *)); res[i] = strdupdelim (p, s); res[++i] = NULL; ++s; /* Skip the blanks following the ','. */ while (ISSPACE (*s)) ++s; p = s; } else ++s; } res = xrealloc (res, (i + 2) * sizeof (char *)); res[i] = strdupdelim (p, s); res[i + 1] = NULL; return res;}/* Like sprintf, but prints into a string of sufficient size freshly allocated with malloc, which is returned. If unable to print due to invalid format, returns NULL. Inability to allocate needed memory results in abort, as with xmalloc. This is in spirit similar to the GNU/BSD extension asprintf, but somewhat easier to use. Internally the function either calls vasprintf or loops around vsnprintf until the correct size is found. Since Wget also ships a fallback implementation of vsnprintf, this should be portable. */char *aprintf (const char *fmt, ...){#if defined HAVE_VASPRINTF && !defined DEBUG_MALLOC /* Use vasprintf. */ int ret; va_list args; char *str; va_start (args, fmt); ret = vasprintf (&str, fmt, args); va_end (args); if (ret < 0 && errno == ENOMEM) abort (); /* for consistency with xmalloc/xrealloc */ else if (ret < 0) return NULL; return str;#else /* not HAVE_VASPRINTF */ /* vasprintf is unavailable. snprintf into a small buffer and resize it as necessary. */ int size = 32; char *str = xmalloc (size); /* #### This code will infloop and eventually abort in xrealloc if passed a FMT that causes snprintf to consistently return -1. */ while (1) { int n; va_list args; va_start (args, fmt); n = vsnprintf (str, size, fmt, args); va_end (args); /* If the printing worked, return the string. */ if (n > -1 && n < size) return str; /* Else try again with a larger buffer. */ if (n > -1) /* C99 */ size = n + 1; /* precisely what is needed */ else size <<= 1; /* twice the old size */ str = xrealloc (str, size); }#endif /* not HAVE_VASPRINTF */}/* Concatenate the NULL-terminated list of string arguments into freshly allocated space. */char *concat_strings (const char *str0, ...){ va_list args; int saved_lengths[5]; /* inspired by Apache's apr_pstrcat */ char *ret, *p; const char *next_str; int total_length = 0; int argcount; /* Calculate the length of and allocate the resulting string. */ argcount = 0; va_start (args, str0); for (next_str = str0; next_str != NULL; next_str = va_arg (args, char *)) { int len = strlen (next_str); if (argcount < countof (saved_lengths)) saved_lengths[argcount++] = len; total_length += len; } va_end (args); p = ret = xmalloc (total_length + 1); /* Copy the strings into the allocated space. */ argcount = 0; va_start (args, str0); for (next_str = str0; next_str != NULL; next_str = va_arg (args, char *)) { int len; if (argcount < countof (saved_lengths)) len = saved_lengths[argcount++]; else len = strlen (next_str); memcpy (p, next_str, len); p += len; } va_end (args); *p = '\0'; return ret;}/* Format the provided time according to the specified format. The format is a string with format elements supported by strftime. */static char *fmttime (time_t t, const char *fmt){ static char output[32]; struct tm *tm = localtime(&t); if (!tm) abort (); if (!strftime(output, sizeof(output), fmt, tm)) abort (); return output;}/* Return pointer to a static char[] buffer in which zero-terminated string-representation of TM (in form hh:mm:ss) is printed. If TM is NULL, the current time will be used. */char *time_str (time_t t){ return fmttime(t, "%H:%M:%S");}/* Like the above, but include the date: YYYY-MM-DD hh:mm:ss. */char *datetime_str (time_t t){ return fmttime(t, "%Y-%m-%d %H:%M:%S");}/* The Windows versions of the following two functions are defined in mswindows.c. On MSDOS this function should never be called. */#if !defined(WINDOWS) && !defined(MSDOS)voidfork_to_background (void){ pid_t pid; /* Whether we arrange our own version of opt.lfilename here. */ bool logfile_changed = false; if (!opt.lfilename) { /* We must create the file immediately to avoid either a race condition (which arises from using unique_name and failing to use fopen_excl) or lying to the user about the log file name (which arises from using unique_name, printing the name, and using fopen_excl later on.) */ FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename); if (new_log_fp) { logfile_changed = true; fclose (new_log_fp); } } pid = fork (); if (pid < 0) { /* parent, error */ perror ("fork"); exit (1); } else if (pid != 0) { /* parent, no error */ printf (_("Continuing in background, pid %d.\n"), (int) pid); if (logfile_changed) printf (_("Output will be written to `%s'.\n"), opt.lfilename); exit (0); /* #### should we use _exit()? */ } /* child: give up the privileges and keep running. */ setsid (); freopen ("/dev/null", "r", stdin); freopen ("/dev/null", "w", stdout); freopen ("/dev/null", "w", stderr);}#endif /* !WINDOWS && !MSDOS *//* "Touch" FILE, i.e. make its mtime ("modified time") equal the time specified with TM. The atime ("access time") is set to the current time. */voidtouch (const char *file, time_t tm){#ifdef HAVE_STRUCT_UTIMBUF struct utimbuf times;#else struct { time_t actime; time_t modtime; } times;#endif times.modtime = tm; times.actime = time (NULL); if (utime (file, ×) == -1) logprintf (LOG_NOTQUIET, "utime(%s): %s\n", file, strerror (errno));}/* Checks if FILE is a symbolic link, and removes it if it is. Does nothing under MS-Windows. */intremove_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;}/* Does FILENAME exist? This is quite a lousy implementation, since it supplies no error codes -- only a yes-or-no answer. Thus it will return that a file does not exist if, e.g., the directory is unreadable. I don't mind it too much currently, though. The proper way should, of course, be to have a third, error state, other than true/false, but that would introduce uncalled-for additional complexity to the callers. */boolfile_exists_p (const char *filename){#ifdef HAVE_ACCESS return access (filename, F_OK) >= 0;#else struct_stat buf; return stat (filename, &buf) >= 0;#endif}/* Returns 0 if PATH is a directory, 1 otherwise (any kind of file). Returns 0 on error. */boolfile_non_directory_p (const char *path){ struct_stat buf; /* Use lstat() rather than stat() so that symbolic links pointing to directories can be identified correctly. */ if (lstat (path, &buf) != 0) return false; return S_ISDIR (buf.st_mode) ? false : true;}/* Return the size of file named by FILENAME, or -1 if it cannot be opened or seeked into. */wgintfile_size (const char *filename){#if defined(HAVE_FSEEKO) && defined(HAVE_FTELLO) wgint size; /* We use fseek rather than stat to determine the file size because that way we can also verify that the file is readable without explicitly checking for permissions. Inspired by the POST patch by Arnaud Wylie. */ FILE *fp = fopen (filename, "rb"); if (!fp) return -1; fseeko (fp, 0, SEEK_END); size = ftello (fp); fclose (fp); return size;#else struct_stat st; if (stat (filename, &st) < 0) return -1; return st.st_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -