- number of tokens left until the filename.
-
- Use the month-name token as the "anchor" (the place where the
- position wrt the file name is "known"). When a month name is
- encountered, `next' is set to 5. Also, the preceding
- characters are parsed to get the file size.
-
- This tactic is quite dubious when it comes to
- internationalization issues (non-English month names), but it
- works for now. */
- while ((tok = strtok (NULL, " ")) != NULL)
- {
- --next;
- if (next < 0) /* a month name was not encountered */
- {
- for (i = 0; i < 12; i++)
- if (!strcmp (tok, months[i]))
- break;
- /* If we got a month, it means the token before it is the
- size, and the filename is three tokens away. */
- if (i != 12)
- {
- wgint size;
-
- /* Back up to the beginning of the previous token
- and parse it with str_to_wgint. */
- char *t = tok - 2;
- while (t > line && ISDIGIT (*t))
- --t;
- if (t == line)
- {
- /* Something has gone wrong during parsing. */
- error = 1;
- break;
- }
- errno = 0;
- size = str_to_wgint (t, NULL, 10);
- if (size == WGINT_MAX && errno == ERANGE)
- /* Out of range -- ignore the size. #### Should
- we refuse to start the download. */
- cur.size = 0;
- else
- cur.size = size;
-
- month = i;
- next = 5;
- DEBUGP (("month: %s; ", months[month]));
- }
- }
- else if (next == 4) /* days */
- {
- if (tok[1]) /* two-digit... */
- day = 10 * (*tok - '0') + tok[1] - '0';
- else /* ...or one-digit */
- day = *tok - '0';
- DEBUGP (("day: %d; ", day));
- }
- else if (next == 3)
- {
- /* This ought to be either the time, or the year. Let's
- be flexible!
-
- If we have a number x, it's a year. If we have x:y,
- it's hours and minutes. If we have x:y:z, z are
- seconds. */
- year = 0;
- min = hour = sec = 0;
- /* We must deal with digits. */
- if (ISDIGIT (*tok))
- {
- /* Suppose it's year. */
- for (; ISDIGIT (*tok); tok++)
- year = (*tok - '0') + 10 * year;
- if (*tok == ':')
- {
- /* This means these were hours! */
- hour = year;
- year = 0;
- ++tok;
- /* Get the minutes... */
- for (; ISDIGIT (*tok); tok++)
- min = (*tok - '0') + 10 * min;
- if (*tok == ':')
- {
- /* ...and the seconds. */
- ++tok;
- for (; ISDIGIT (*tok); tok++)
- sec = (*tok - '0') + 10 * sec;
- }
- }
- }
- if (year)
- DEBUGP (("year: %d (no tm); ", year));
- else
- DEBUGP (("time: %02d:%02d:%02d (no yr); ", hour, min, sec));
- }
- else if (next == 2) /* The file name */
- {
- int fnlen;
- char *p;
-
- /* Since the file name may contain a SPC, it is possible
- for strtok to handle it wrong. */
- fnlen = strlen (tok);
- if (fnlen < len - (tok - line))
- {
- /* So we have a SPC in the file name. Restore the
- original. */
- tok[fnlen] = ' ';
- /* If the file is a symbolic link, it should have a
- ` -> ' somewhere. */
- if (cur.type == FT_SYMLINK)
- {
- p = strstr (tok, " -> ");
- if (!p)
- {
- error = 1;
- break;
- }
- cur.linkto = xstrdup (p + 4);
- DEBUGP (("link to: %s\n", cur.linkto));
- /* And separate it from the file name. */
- *p = '\0';
- }
- }
- /* If we have the filename, add it to the list of files or
- directories. */
- /* "." and ".." are an exception! */
- if (!strcmp (tok, ".") || !strcmp (tok, ".."))
- {
- DEBUGP (("\nIgnoring `.' and `..'; "));
- ignore = 1;
- break;
- }
- /* Some FTP sites choose to have ls -F as their default
- LIST output, which marks the symlinks with a trailing
- `@', directory names with a trailing `/' and
- executables with a trailing `*'. This is no problem
- unless encountering a symbolic link ending with `@',
- or an executable ending with `*' on a server without
- default -F output. I believe these cases are very
- rare. */
- fnlen = strlen (tok); /* re-calculate `fnlen' */
- cur.name = xmalloc (fnlen + 1);
- memcpy (cur.name, tok, fnlen + 1);
- if (fnlen)
- {
- if (cur.type == FT_DIRECTORY && cur.name[fnlen - 1] == '/')
- {
- cur.name[fnlen - 1] = '\0';
- DEBUGP (("trailing `/' on dir.\n"));
- }
- else if (cur.type == FT_SYMLINK && cur.name[fnlen - 1] == '@')
- {
- cur.name[fnlen - 1] = '\0';
- DEBUGP (("trailing `@' on link.\n"));
- }
- else if (cur.type == FT_PLAINFILE
- && (cur.perms & 0111)
- && cur.name[fnlen - 1] == '*')
- {
- cur.name[fnlen - 1] = '\0';
- DEBUGP (("trailing `*' on exec.\n"));
- }
- } /* if (fnlen) */
- else
- error = 1;
- break;
- }
- else
- abort ();
- } /* while */
+ number of tokens left until the filename.
+
+ Use the month-name token as the "anchor" (the place where the
+ position wrt the file name is "known"). When a month name is
+ encountered, `next' is set to 5. Also, the preceding
+ characters are parsed to get the file size.
+
+ This tactic is quite dubious when it comes to
+ internationalization issues (non-English month names), but it
+ works for now. */
+ tok = line;
+ while (ptok = tok,
+ (tok = strtok (NULL, " ")) != NULL)
+ {
+ --next;
+ if (next < 0) /* a month name was not encountered */
+ {
+ for (i = 0; i < 12; i++)
+ if (!strcasecmp (tok, months[i]))
+ break;
+ /* If we got a month, it means the token before it is the
+ size, and the filename is three tokens away. */
+ if (i != 12)
+ {
+ wgint size;
+
+ /* Parse the previous token with str_to_wgint. */
+ if (ptok == line)
+ {
+ /* Something has gone wrong during parsing. */
+ error = 1;
+ break;
+ }
+ errno = 0;
+ size = str_to_wgint (ptok, NULL, 10);
+ if (size == WGINT_MAX && errno == ERANGE)
+ /* Out of range -- ignore the size. #### Should
+ we refuse to start the download. */
+ cur.size = 0;
+ else
+ cur.size = size;
+ DEBUGP (("size: %s; ", number_to_static_string(cur.size)));
+
+ month = i;
+ next = 5;
+ DEBUGP (("month: %s; ", months[month]));
+ }
+ }
+ else if (next == 4) /* days */
+ {
+ if (tok[1]) /* two-digit... */
+ day = 10 * (*tok - '0') + tok[1] - '0';
+ else /* ...or one-digit */
+ day = *tok - '0';
+ DEBUGP (("day: %d; ", day));
+ }
+ else if (next == 3)
+ {
+ /* This ought to be either the time, or the year. Let's
+ be flexible!
+
+ If we have a number x, it's a year. If we have x:y,
+ it's hours and minutes. If we have x:y:z, z are
+ seconds. */
+ year = 0;
+ min = hour = sec = 0;
+ /* We must deal with digits. */
+ if (c_isdigit (*tok))
+ {
+ /* Suppose it's year. */
+ for (; c_isdigit (*tok); tok++)
+ year = (*tok - '0') + 10 * year;
+ if (*tok == ':')
+ {
+ /* This means these were hours! */
+ hour = year;
+ year = 0;
+ ptype = TT_HOUR_MIN;
+ ++tok;
+ /* Get the minutes... */
+ for (; c_isdigit (*tok); tok++)
+ min = (*tok - '0') + 10 * min;
+ if (*tok == ':')
+ {
+ /* ...and the seconds. */
+ ++tok;
+ for (; c_isdigit (*tok); tok++)
+ sec = (*tok - '0') + 10 * sec;
+ }
+ }
+ }
+ if (year)
+ DEBUGP (("year: %d (no tm); ", year));
+ else
+ DEBUGP (("time: %02d:%02d:%02d (no yr); ", hour, min, sec));
+ }
+ else if (next == 2) /* The file name */
+ {
+ int fnlen;
+ char *p;
+
+ /* Since the file name may contain a SPC, it is possible
+ for strtok to handle it wrong. */
+ fnlen = strlen (tok);
+ if (fnlen < len - (tok - line))
+ {
+ /* So we have a SPC in the file name. Restore the
+ original. */
+ tok[fnlen] = ' ';
+ /* If the file is a symbolic link, it should have a
+ ` -> ' somewhere. */
+ if (cur.type == FT_SYMLINK)
+ {
+ p = strstr (tok, " -> ");
+ if (!p)
+ {
+ error = 1;
+ break;
+ }
+ cur.linkto = xstrdup (p + 4);
+ DEBUGP (("link to: %s\n", cur.linkto));
+ /* And separate it from the file name. */
+ *p = '\0';
+ }
+ }
+ /* If we have the filename, add it to the list of files or
+ directories. */
+ /* "." and ".." are an exception! */
+ if (!strcmp (tok, ".") || !strcmp (tok, ".."))
+ {
+ DEBUGP (("\nIgnoring `.' and `..'; "));
+ ignore = 1;
+ break;
+ }
+ /* Some FTP sites choose to have ls -F as their default
+ LIST output, which marks the symlinks with a trailing
+ `@', directory names with a trailing `/' and
+ executables with a trailing `*'. This is no problem
+ unless encountering a symbolic link ending with `@',
+ or an executable ending with `*' on a server without
+ default -F output. I believe these cases are very
+ rare. */
+ fnlen = strlen (tok); /* re-calculate `fnlen' */
+ cur.name = xmalloc (fnlen + 1);
+ memcpy (cur.name, tok, fnlen + 1);
+ if (fnlen)
+ {
+ if (cur.type == FT_DIRECTORY && cur.name[fnlen - 1] == '/')
+ {
+ cur.name[fnlen - 1] = '\0';
+ DEBUGP (("trailing `/' on dir.\n"));
+ }
+ else if (cur.type == FT_SYMLINK && cur.name[fnlen - 1] == '@')
+ {
+ cur.name[fnlen - 1] = '\0';
+ DEBUGP (("trailing `@' on link.\n"));
+ }
+ else if (cur.type == FT_PLAINFILE
+ && (cur.perms & 0111)
+ && cur.name[fnlen - 1] == '*')
+ {
+ cur.name[fnlen - 1] = '\0';
+ DEBUGP (("trailing `*' on exec.\n"));
+ }
+ } /* if (fnlen) */
+ else
+ error = 1;
+ break;
+ }
+ else
+ abort ();
+ } /* while */