X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=src%2Futils.c;h=01cc422ee1d33898920ab1882985be861a9d047a;hb=d5be8ecca466601bda9b81c28a79077fbda6ccde;hp=fa9e1028f9a565409d7b905d222f40cde347ef3a;hpb=2cfb2d2ef6c8043787d05aae46bcf369235c7d9f;p=wget diff --git a/src/utils.c b/src/utils.c index fa9e1028..01cc422e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1,20 +1,21 @@ /* Various functions of utilitarian nature. - Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc. + Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001 + Free Software Foundation, Inc. -This file is part of Wget. +This file is part of GNU Wget. -This program is free software; you can redistribute it and/or modify +GNU Wget is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. -This program is distributed in the hope that it will be useful, +GNU Wget is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software +along with Wget; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include @@ -403,59 +404,11 @@ datetime_str (time_t *tm) ptm->tm_hour, ptm->tm_min, ptm->tm_sec); return output; } - -/* Returns an error message for ERRNUM. #### This requires more work. - This function, as well as the whole error system, is very - ill-conceived. */ -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 (); - /* $@#@#$ compiler. */ - return NULL; - } -} /* The Windows versions of the following two functions are defined in mswindows.c. */ -/* A cuserid() immitation using getpwuid(), to avoid hassling with - utmp. Besides, not all systems have cuesrid(). Under Windows, it - is defined in mswindows.c. - - If WHERE is non-NULL, the username will be stored there. - Otherwise, it will be returned as a static buffer (as returned by - getpwuid()). In the latter case, the buffer should be copied - before calling getpwuid() or pwd_cuserid() again. */ #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) { @@ -487,6 +440,14 @@ fork_to_background (void) } #endif /* not WINDOWS */ +char * +ps (char *orig) +{ + char *r = xstrdup (orig); + path_simplify (r); + return r; +} + /* Canonicalize PATH, and return a new path. The new path differs from PATH in that: Multple `/'s are collapsed to a single `/'. @@ -502,7 +463,8 @@ fork_to_background (void) Always use '/' as stub_char. Don't check for local things using canon_stat. Change the original string instead of strdup-ing. - React correctly when beginning with `./' and `../'. */ + React correctly when beginning with `./' and `../'. + Don't zip out trailing slashes. */ void path_simplify (char *path) { @@ -568,20 +530,15 @@ path_simplify (char *path) i = start + 1; } - /* Check for trailing `/'. */ - if (start && !path[i]) - { - zero_last: - path[--i] = '\0'; - break; - } - /* Check for `../', `./' or trailing `.' by itself. */ if (path[i] == '.') { /* Handle trailing `.' by itself. */ if (!path[i + 1]) - goto zero_last; + { + path[--i] = '\0'; + break; + } /* Handle `./'. */ if (path[i + 1] == '/') @@ -602,12 +559,6 @@ path_simplify (char *path) } } /* path == '.' */ } /* while */ - - if (!*path) - { - *path = stub_char; - path[1] = '\0'; - } } /* "Touch" FILE, i.e. make its atime and mtime equal to the time @@ -751,6 +702,30 @@ make_directory (const char *directory) } return 0; } + +/* Merge BASE with FILE. BASE can be a directory or a file name, FILE + should be a file name. For example, file_merge("/foo/bar", "baz") + will return "/foo/baz". file_merge("/foo/bar/", "baz") will return + "foo/bar/baz". + + In other words, it's a simpler and gentler version of uri_merge_1. */ + +char * +file_merge (const char *base, const char *file) +{ + char *result; + const char *cut = (const char *)strrchr (base, '/'); + + if (!cut) + cut = base + strlen (base); + + result = (char *)xmalloc (cut - base + 1 + strlen (file) + 1); + memcpy (result, base, cut - base); + result[cut - base] = '/'; + strcpy (result + (cut - base) + 1, file); + + return result; +} static int in_acclist PARAMS ((const char *const *, const char *, int)); @@ -1230,7 +1205,7 @@ string_set_add (struct hash_table *ht, const char *s) /* First check whether the set element already exists. If it does, do nothing so that we don't have to free() the old element and then strdup() a new one. */ - if (hash_table_exists (ht, s)) + if (hash_table_contains (ht, s)) return; /* We use "1" as value. It provides us a useful and clear arbitrary @@ -1240,12 +1215,12 @@ string_set_add (struct hash_table *ht, const char *s) hash_table_put (ht, xstrdup (s), "1"); } -/* Synonym for hash_table_exists... */ +/* Synonym for hash_table_contains... */ int -string_set_exists (struct hash_table *ht, const char *s) +string_set_contains (struct hash_table *ht, const char *s) { - return hash_table_exists (ht, s); + return hash_table_contains (ht, s); } static int @@ -1279,7 +1254,7 @@ free_keys_and_values (struct hash_table *ht) } -/* Engine for legible and legible_long_long; this function works on +/* Engine for legible and legible_very_long; this function works on strings. */ static char * @@ -1340,7 +1315,7 @@ legible (long l) bytes are sufficient. Using more might be a good idea. This function does not go through the hoops that long_to_string - goes to because it doesn't need to be fast. (It's called perhaps + goes to because it doesn't aspire to be fast. (It's called perhaps once in a Wget run.) */ static void @@ -1382,62 +1357,278 @@ int numdigit (long a) { int res = 1; + if (a < 0) + { + a = -a; + ++res; + } while ((a /= 10) != 0) ++res; return res; } -/* Print NUMBER to BUFFER. This is equivalent to sprintf(buffer, - "%ld", number), only much faster. +#define ONE_DIGIT(figure) *p++ = n / (figure) + '0' +#define ONE_DIGIT_ADVANCE(figure) (ONE_DIGIT (figure), n %= (figure)) + +#define DIGITS_1(figure) ONE_DIGIT (figure) +#define DIGITS_2(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_1 ((figure) / 10) +#define DIGITS_3(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_2 ((figure) / 10) +#define DIGITS_4(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_3 ((figure) / 10) +#define DIGITS_5(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_4 ((figure) / 10) +#define DIGITS_6(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_5 ((figure) / 10) +#define DIGITS_7(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_6 ((figure) / 10) +#define DIGITS_8(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_7 ((figure) / 10) +#define DIGITS_9(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_8 ((figure) / 10) +#define DIGITS_10(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_9 ((figure) / 10) + +/* DIGITS_<11-20> are only used on machines with 64-bit longs. */ + +#define DIGITS_11(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_10 ((figure) / 10) +#define DIGITS_12(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_11 ((figure) / 10) +#define DIGITS_13(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_12 ((figure) / 10) +#define DIGITS_14(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_13 ((figure) / 10) +#define DIGITS_15(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_14 ((figure) / 10) +#define DIGITS_16(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_15 ((figure) / 10) +#define DIGITS_17(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_16 ((figure) / 10) +#define DIGITS_18(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_17 ((figure) / 10) +#define DIGITS_19(figure) ONE_DIGIT_ADVANCE (figure); DIGITS_18 ((figure) / 10) + +/* Print NUMBER to BUFFER in base 10. This is completely equivalent + to `sprintf(buffer, "%ld", number)', only much faster. + + The speedup may make a difference in programs that frequently + convert numbers to strings. Some implementations of sprintf, + particularly the one in GNU libc, have been known to be extremely + slow compared to this function. + + BUFFER should accept as many bytes as you expect the number to take + up. On machines with 64-bit longs the maximum needed size is 24 + bytes. That includes the worst-case digits, the optional `-' sign, + and the trailing \0. */ - BUFFER should accept 24 bytes. This should suffice for the longest - numbers on 64-bit machines, including the `-' sign and the trailing - \0. */ void long_to_string (char *buffer, long number) { -#if (SIZEOF_LONG != 4) && (SIZEOF_LONG != 8) - /* Huh? */ - sprintf (buffer, "%ld", number); -#else /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */ char *p = buffer; - int force = 0; + long n = number; + +#if (SIZEOF_LONG != 4) && (SIZEOF_LONG != 8) + /* We are running in a strange or misconfigured environment. Let + sprintf cope with it. */ + sprintf (buffer, "%ld", n); +#else /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */ - if (number < 0) + if (n < 0) { *p++ = '-'; - number = -number; + n = -n; } -#define FROB(figure) do { \ - if (force || number >= figure) \ - *p++ = number / figure + '0', number %= figure, force = 1; \ - } while (0) -#if SIZEOF_LONG == 8 - FROB (1000000000000000000L); - FROB (100000000000000000L); - FROB (10000000000000000L); - FROB (1000000000000000L); - FROB (100000000000000L); - FROB (10000000000000L); - FROB (1000000000000L); - FROB (100000000000L); - FROB (10000000000L); -#endif /* SIZEOF_LONG == 8 */ - FROB (1000000000); - FROB (100000000); - FROB (10000000); - FROB (1000000); - FROB (100000); - FROB (10000); - FROB (1000); - FROB (100); - FROB (10); -#undef FROB - *p++ = number + '0'; + if (n < 10) { DIGITS_1 (1); } + else if (n < 100) { DIGITS_2 (10); } + else if (n < 1000) { DIGITS_3 (100); } + else if (n < 10000) { DIGITS_4 (1000); } + else if (n < 100000) { DIGITS_5 (10000); } + else if (n < 1000000) { DIGITS_6 (100000); } + else if (n < 10000000) { DIGITS_7 (1000000); } + else if (n < 100000000) { DIGITS_8 (10000000); } + else if (n < 1000000000) { DIGITS_9 (100000000); } +#if SIZEOF_LONG == 4 + /* ``if (1)'' serves only to preserve editor indentation. */ + else if (1) { DIGITS_10 (1000000000); } +#else /* SIZEOF_LONG != 4 */ + else if (n < 10000000000L) { DIGITS_10 (1000000000L); } + else if (n < 100000000000L) { DIGITS_11 (10000000000L); } + else if (n < 1000000000000L) { DIGITS_12 (100000000000L); } + else if (n < 10000000000000L) { DIGITS_13 (1000000000000L); } + else if (n < 100000000000000L) { DIGITS_14 (10000000000000L); } + else if (n < 1000000000000000L) { DIGITS_15 (100000000000000L); } + else if (n < 10000000000000000L) { DIGITS_16 (1000000000000000L); } + else if (n < 100000000000000000L) { DIGITS_17 (10000000000000000L); } + else if (n < 1000000000000000000L) { DIGITS_18 (100000000000000000L); } + else { DIGITS_19 (1000000000000000000L); } +#endif /* SIZEOF_LONG != 4 */ + *p = '\0'; #endif /* (SIZEOF_LONG == 4) || (SIZEOF_LONG == 8) */ } + +#undef ONE_DIGIT +#undef ONE_DIGIT_ADVANCE + +#undef DIGITS_1 +#undef DIGITS_2 +#undef DIGITS_3 +#undef DIGITS_4 +#undef DIGITS_5 +#undef DIGITS_6 +#undef DIGITS_7 +#undef DIGITS_8 +#undef DIGITS_9 +#undef DIGITS_10 +#undef DIGITS_11 +#undef DIGITS_12 +#undef DIGITS_13 +#undef DIGITS_14 +#undef DIGITS_15 +#undef DIGITS_16 +#undef DIGITS_17 +#undef DIGITS_18 +#undef DIGITS_19 + +/* Support for timers. */ + +#undef TIMER_WINDOWS +#undef TIMER_GETTIMEOFDAY +#undef TIMER_TIME + +/* Depending on the OS and availability of gettimeofday(), one and + only one of the above constants will be defined. Virtually all + modern Unix systems will define TIMER_GETTIMEOFDAY; Windows will + use TIMER_WINDOWS. TIMER_TIME is a catch-all method for + non-Windows systems without gettimeofday. + + #### Perhaps we should also support ftime(), which exists on old + BSD 4.2-influenced systems? (It also existed under MS DOS Borland + C, if memory serves me.) */ + +#ifdef WINDOWS +# define TIMER_WINDOWS +#else /* not WINDOWS */ +# ifdef HAVE_GETTIMEOFDAY +# define TIMER_GETTIMEOFDAY +# else +# define TIMER_TIME +# endif +#endif /* not WINDOWS */ + +struct wget_timer { +#ifdef TIMER_GETTIMEOFDAY + long secs; + long usecs; +#endif + +#ifdef TIMER_TIME + time_t secs; +#endif + +#ifdef TIMER_WINDOWS + ULARGE_INTEGER wintime; +#endif +}; + +/* Allocate a timer. It is not legal to do anything with a freshly + allocated timer, except call wtimer_reset() or wtimer_delete(). */ + +struct wget_timer * +wtimer_allocate (void) +{ + struct wget_timer *wt = + (struct wget_timer *)xmalloc (sizeof (struct wget_timer)); + return wt; +} + +/* Allocate a new timer and reset it. Return the new timer. */ + +struct wget_timer * +wtimer_new (void) +{ + struct wget_timer *wt = wtimer_allocate (); + wtimer_reset (wt); + return wt; +} + +/* Free the resources associated with the timer. Its further use is + prohibited. */ + +void +wtimer_delete (struct wget_timer *wt) +{ + xfree (wt); +} + +/* Reset timer WT. This establishes the starting point from which + wtimer_elapsed() will return the number of elapsed + milliseconds. It is allowed to reset a previously used timer. */ + +void +wtimer_reset (struct wget_timer *wt) +{ +#ifdef TIMER_GETTIMEOFDAY + struct timeval t; + gettimeofday (&t, NULL); + wt->secs = t.tv_sec; + wt->usecs = t.tv_usec; +#endif + +#ifdef TIMER_TIME + wt->secs = time (NULL); +#endif + +#ifdef TIMER_WINDOWS + FILETIME ft; + SYSTEMTIME st; + GetSystemTime (&st); + SystemTimeToFileTime (&st, &ft); + wt->wintime.HighPart = ft.dwHighDateTime; + wt->wintime.LowPart = ft.dwLowDateTime; +#endif +} + +/* Return the number of milliseconds elapsed since the timer was last + reset. It is allowed to call this function more than once to get + increasingly higher elapsed values. */ + +long +wtimer_elapsed (struct wget_timer *wt) +{ +#ifdef TIMER_GETTIMEOFDAY + struct timeval t; + gettimeofday (&t, NULL); + return (t.tv_sec - wt->secs) * 1000 + (t.tv_usec - wt->usecs) / 1000; +#endif + +#ifdef TIMER_TIME + time_t now = time (NULL); + return 1000 * (now - wt->secs); +#endif + +#ifdef WINDOWS + FILETIME ft; + SYSTEMTIME st; + ULARGE_INTEGER uli; + GetSystemTime (&st); + SystemTimeToFileTime (&st, &ft); + uli.HighPart = ft.dwHighDateTime; + uli.LowPart = ft.dwLowDateTime; + return (long)((uli.QuadPart - wt->wintime.QuadPart) / 10000); +#endif +} + +/* Return the assessed granularity of the timer implementation. This + is important for certain code that tries to deal with "zero" time + intervals. */ + +long +wtimer_granularity (void) +{ +#ifdef TIMER_GETTIMEOFDAY + /* Granularity of gettimeofday is hugely architecture-dependent. + However, it appears that on modern machines it is better than + 1ms. */ + return 1; +#endif + +#ifdef TIMER_TIME + /* This is clear. */ + return 1000; +#endif + +#ifdef TIMER_WINDOWS + /* ? */ + return 1; +#endif +} /* This should probably be at a better place, but it doesn't really fit into html-parse.c. */