예제 #1
0
static gboolean
parse_textual_date (SoupDate *date, const char *date_string)
{
	/* If it starts with a word, it must be a weekday, which we skip */
	if (g_ascii_isalpha (*date_string)) {
		while (g_ascii_isalpha (*date_string))
			date_string++;
		if (*date_string == ',')
			date_string++;
		while (g_ascii_isspace (*date_string))
			date_string++;
	}

	/* If there's now another word, this must be an asctime-date */
	if (g_ascii_isalpha (*date_string)) {
		/* (Sun) Nov  6 08:49:37 1994 */
		if (!parse_month (date, &date_string) ||
		    !parse_day (date, &date_string) ||
		    !parse_time (date, &date_string) ||
		    !parse_year (date, &date_string))
			return FALSE;

		/* There shouldn't be a timezone, but check anyway */
		parse_timezone (date, &date_string);
	} else {
		/* Non-asctime date, so some variation of
		 * (Sun,) 06 Nov 1994 08:49:37 GMT
		 */
		if (!parse_day (date, &date_string) ||
		    !parse_month (date, &date_string) ||
		    !parse_year (date, &date_string) ||
		    !parse_time (date, &date_string))
			return FALSE;

		/* This time there *should* be a timezone, but we
		 * survive if there isn't.
		 */
		parse_timezone (date, &date_string);
	}
	return TRUE;
}
static void
parse_days_string(int *days, const char *daystring)
{
	int len;
	int i=0;
	//char *err = "invalid days specified, should be Sun,Mon,Tue... format";

	len = strlen(daystring);
	if (len < 3)
		print_error("invalid days specified, should be Sun,Mon,Tue... format");	
	while(i<len)
	{
		if (parse_day(days, i, i+3, daystring) == 0)
			print_error("invalid days specified, should be Sun,Mon,Tue... format");
		i += 4;
	}
}
예제 #3
0
static void
parse_days_string(int *days, const char *daystring)
{
	int len;
	int i=0;
	char *err = "invalid days `%s' specified, should be Sun,Mon,Tue... format";

	len = strlen(daystring);
	if (len < 3)
		exit_error(PARAMETER_PROBLEM, err, daystring);	
	while(i<len)
	{
		if (parse_day(days, i, i+3, daystring) == 0)
			exit_error(PARAMETER_PROBLEM, err, daystring);
		i += 4;
	}
}
예제 #4
0
// Parse global prefs, overriding whatever is currently in the structure.
//
// If host_venue is nonempty and we find an element of the form
// <venue name="X">
//   ...
// </venue>
// where X==host_venue, then parse that and ignore the rest.
// Otherwise ignore <venue> elements.
//
// The start tag may or may not have already been parsed
//
int GLOBAL_PREFS::parse_override(
    XML_PARSER& xp, const char* host_venue, bool& found_venue, GLOBAL_PREFS_MASK& mask
) {
    char buf2[256], attrs[256];
    bool in_venue = false, in_correct_venue=false;
    double dtemp;
    int itemp;

    found_venue = false;
    mask.clear();

    while (!xp.get_tag(attrs, sizeof(attrs))) {
        if (!xp.is_tag) continue;
        if (xp.match_tag("global_preferences")) continue;
        if (xp.match_tag("/global_preferences")) {
            return 0;
        }
        if (in_venue) {
            if (xp.match_tag("/venue")) {
                if (in_correct_venue) {
                    return 0;
                } else {
                    in_venue = false;
                    continue;
                }
            } else {
                if (!in_correct_venue) continue;
            }
        } else {
            if (strstr(xp.parsed_tag, "venue")) {
                in_venue = true;
                parse_attr(attrs, "name", buf2, sizeof(buf2));
                if (!strcmp(buf2, host_venue)) {
                    defaults();
                    clear_bools();
                    mask.clear();
                    in_correct_venue = true;
                    found_venue = true;
                } else {
                    in_correct_venue = false;
                }
                continue;
            }
        }
        if (xp.parse_str("source_project", source_project, sizeof(source_project))) continue;
        if (xp.parse_str("source_scheduler", source_scheduler, sizeof(source_scheduler))) {
            continue;
        }
        if (xp.parse_double("mod_time", mod_time)) {
            double now = dtime();
            if (mod_time > now) {
                mod_time = now;
            }
            continue;
        }
        if (xp.parse_double("battery_charge_min_pct", battery_charge_min_pct)) {
            mask.battery_charge_min_pct = true;
            continue;
        }
        if (xp.parse_double("battery_max_temperature", battery_max_temperature)) {
            mask.battery_max_temperature = true;
            continue;
        }
        if (xp.parse_bool("run_on_batteries", run_on_batteries)) {
            mask.run_on_batteries = true;
            continue;
        }
        if (xp.parse_bool("run_if_user_active", run_if_user_active)) {
            mask.run_if_user_active = true;
            continue;
        }
        if (xp.parse_bool("run_gpu_if_user_active", run_gpu_if_user_active)) {
            mask.run_gpu_if_user_active = true;
            continue;
        }
        if (xp.parse_double("idle_time_to_run", idle_time_to_run)) {
            mask.idle_time_to_run = true;
            continue;
        }
        if (xp.parse_double("suspend_if_no_recent_input", suspend_if_no_recent_input)) {
            mask.suspend_if_no_recent_input = true;
            continue;
        }
        if (xp.parse_double("suspend_cpu_usage", suspend_cpu_usage)) {
            mask.suspend_cpu_usage = true;
            continue;
        }
        if (xp.parse_double("start_hour", cpu_times.start_hour)) {
            mask.start_hour = true;
            continue;
        }
        if (xp.parse_double("end_hour", cpu_times.end_hour)) {
            mask.end_hour = true;
            continue;
        }
        if (xp.parse_double("net_start_hour", net_times.start_hour)) {
            mask.net_start_hour = true;
            continue;
        }
        if (xp.parse_double("net_end_hour", net_times.end_hour)) {
            mask.net_end_hour = true;
            continue;
        }
        if (xp.match_tag("day_prefs")) {
            parse_day(xp);
            continue;
        }
        if (xp.parse_bool("leave_apps_in_memory", leave_apps_in_memory)) {
            mask.leave_apps_in_memory = true;
            continue;
        }
        if (xp.parse_bool("confirm_before_connecting", confirm_before_connecting)) {
            mask.confirm_before_connecting = true;
            continue;
        }
        if (xp.parse_bool("hangup_if_dialed", hangup_if_dialed)) {
            mask.hangup_if_dialed = true;
            continue;
        }
        if (xp.parse_bool("dont_verify_images", dont_verify_images)) {
            mask.dont_verify_images = true;
            continue;
        }
        if (xp.parse_double("work_buf_min_days", work_buf_min_days)) {
            if (work_buf_min_days < 0) work_buf_min_days = 0;
            mask.work_buf_min_days = true;
            continue;
        }
        if (xp.parse_double("work_buf_additional_days", work_buf_additional_days)) {
            if (work_buf_additional_days < 0) work_buf_additional_days = 0;
            mask.work_buf_additional_days = true;
            continue;
        }
        if (xp.parse_double("max_ncpus_pct", max_ncpus_pct)) {
            if (max_ncpus_pct < 0) max_ncpus_pct = 0;
            if (max_ncpus_pct > 100) max_ncpus_pct = 100;
            mask.max_ncpus_pct = true;
            continue;
        }
        if (xp.parse_int("max_cpus", max_ncpus)) {
            if (max_ncpus < 0) max_ncpus = 0;
            mask.max_ncpus = true;
            continue;
        }
        if (xp.parse_double("disk_interval", disk_interval)) {
            if (disk_interval<0) disk_interval = 0;
            mask.disk_interval = true;
            continue;
        }
        if (xp.parse_double("cpu_scheduling_period_minutes", cpu_scheduling_period_minutes)) {
            if (cpu_scheduling_period_minutes < 0.0001) cpu_scheduling_period_minutes = 60;
            mask.cpu_scheduling_period_minutes = true;
            continue;
        }
        if (xp.parse_double("disk_max_used_gb", disk_max_used_gb)) {
            mask.disk_max_used_gb = true;
            continue;
        }
        if (xp.parse_double("disk_max_used_pct", disk_max_used_pct)) {
            mask.disk_max_used_pct = true;
            continue;
        }
        if (xp.parse_double("disk_min_free_gb", disk_min_free_gb)) {
            mask.disk_min_free_gb = true;
            continue;
        }
        if (xp.parse_double("vm_max_used_pct", dtemp)) {
            vm_max_used_frac = dtemp/100;
            mask.vm_max_used_frac = true;
            continue;
        }
        if (xp.parse_double("ram_max_used_busy_pct", dtemp)) {
            if (!dtemp) dtemp = 100;
            ram_max_used_busy_frac = dtemp/100;
            mask.ram_max_used_busy_frac = true;
            continue;
        }
        if (xp.parse_double("ram_max_used_idle_pct", dtemp)) {
            if (!dtemp) dtemp = 100;
            ram_max_used_idle_frac = dtemp/100;
            mask.ram_max_used_idle_frac = true;
            continue;
        }
        if (xp.parse_double("max_bytes_sec_up", max_bytes_sec_up)) {
            if (max_bytes_sec_up < 0) max_bytes_sec_up = 0;
            mask.max_bytes_sec_up = true;
            continue;
        }
        if (xp.parse_double("max_bytes_sec_down", max_bytes_sec_down)) {
            if (max_bytes_sec_down < 0) max_bytes_sec_down = 0;
            mask.max_bytes_sec_down = true;
            continue;
        }
        if (xp.parse_double("cpu_usage_limit", dtemp)) {
            if (dtemp > 0 && dtemp <= 100) {
                cpu_usage_limit = dtemp;
                mask.cpu_usage_limit = true;
            }
            continue;
        }
        if (xp.parse_double("daily_xfer_limit_mb", dtemp)) {
            if (dtemp >= 0) {
                daily_xfer_limit_mb = dtemp;
                mask.daily_xfer_limit_mb = true;
            }
            continue;
        }
        if (xp.parse_int("daily_xfer_period_days", itemp)) {
            if (itemp >= 0) {
                daily_xfer_period_days = itemp;
                mask.daily_xfer_period_days = true;
            }
            continue;
        }
        if (xp.parse_bool("network_wifi_only", network_wifi_only)) {
            continue;
        }
        if (xp.parse_bool("host_specific", host_specific)) {
            continue;
        }
        // false means don't print anything
        xp.skip_unexpected(false, "GLOBAL_PREFS::parse_override");
    }
    return ERR_XML_PARSE;
}
예제 #5
0
static void
parse_rule_line                 (ParsingData    *data)
{
  GArray *rule_array;
  RuleData rule;
  char *name;
  TimeCode time_code;

  /* All 10 fields must be present. */
  if (data->num_fields != 10) {
        fprintf (stderr, "%s:%i: Invalid Rule line - %i fields.\n%s\n",
                 data->filename, data->line_number, data->num_fields,
                 data->line);
        exit (1);
  }

  name = data->fields[RULE_NAME];

  /* Create the GArray and add it to the hash table if it doesn't already
     exist. */
  rule_array = g_hash_table_lookup (data->rule_data, name);
  if (!rule_array) {
    rule_array = g_array_new (FALSE, FALSE, sizeof (RuleData));
    g_hash_table_insert (data->rule_data, g_strdup (name), rule_array);
  }

  rule.from_year = parse_year (data, data->fields[RULE_FROM], FALSE, 0);
  if (rule.from_year == YEAR_MAXIMUM) {
    fprintf (stderr, "%s:%i: Invalid Rule FROM value: '%s'\n",
             data->filename, data->line_number, data->fields[RULE_FROM]);
    exit (1);
  }

  rule.to_year = parse_year (data, data->fields[RULE_TO], TRUE,
                             rule.from_year);
  if (rule.to_year == YEAR_MINIMUM) {
    fprintf (stderr, "%s:%i: Invalid Rule TO value: %s\n",
             data->filename, data->line_number, data->fields[RULE_TO]);
    exit (1);
  }

  /* We also want to know the maximum year used in any TO/FROM value, so we
     know where to expand all the infinite Rule data to. */
  if (rule.to_year != YEAR_MAXIMUM)
    data->max_until_year = MAX (data->max_until_year, rule.to_year);
  else if (rule.from_year != YEAR_MINIMUM)
    data->max_until_year = MAX (data->max_until_year, rule.from_year);

  if (!strcmp (data->fields[RULE_TYPE], "-"))
    rule.type = NULL;
  else {
    printf ("Type: %s\n", data->fields[RULE_TYPE]);
    rule.type = g_strdup (data->fields[RULE_TYPE]);
  }

  rule.in_month = parse_month (data, data->fields[RULE_IN]);
  rule.on_day_code = parse_day (data, data->fields[RULE_ON],
                                &rule.on_day_number, &rule.on_day_weekday);
  rule.at_time_seconds = parse_time (data, data->fields[RULE_AT],
                                     &rule.at_time_code);
  rule.save_seconds = parse_time (data, data->fields[RULE_SAVE], &time_code);

  if (!strcmp (data->fields[RULE_LETTER_S], "-")) {
    rule.letter_s = NULL;
  } else {
    rule.letter_s = g_strdup (data->fields[RULE_LETTER_S]);
  }

  rule.is_shallow_copy = FALSE;

  g_array_append_val (rule_array, rule);
}
예제 #6
0
static gboolean
parse_zone_common               (ParsingData    *data,
                                 int             offset)
{
  ZoneData *zone;
  ZoneLineData zone_line;
  TimeCode time_code;

  zone_line.stdoff_seconds = parse_time (data,
                                         data->fields[ZONE_GMTOFF + offset],
                                         &time_code);
  zone_line.save_seconds = parse_rules_save (data,
                                             data->fields[ZONE_RULES_SAVE + offset],
                                             &zone_line.rules);

  if (!VzicPureOutput) {
    /* We round the UTC offsets to the nearest minute, to be compatible with
       Outlook. This also works with -ve numbers, I think.
       -56 % 60 = -59. -61 % 60 = -1. */
    if (zone_line.stdoff_seconds >= 0)
      zone_line.stdoff_seconds += 30;
    else
      zone_line.stdoff_seconds -= 29;
    zone_line.stdoff_seconds -= zone_line.stdoff_seconds % 60;

    if (zone_line.save_seconds >= 0)
      zone_line.save_seconds += 30;
    else
      zone_line.save_seconds -= 29;
    zone_line.save_seconds -= zone_line.save_seconds % 60;
  }

  zone_line.format = g_strdup (data->fields[ZONE_FORMAT + offset]);

  if (data->num_fields - offset >= 6) {
    zone_line.until_set = TRUE;
    zone_line.until_year = parse_year (data,
                                       data->fields[ZONE_UNTIL_YEAR + offset],
                                       FALSE, 0);
    zone_line.until_month = parse_month (data,
                                         data->fields[ZONE_UNTIL_MONTH + offset]);
    zone_line.until_day_code = parse_day (data,
                                          data->fields[ZONE_UNTIL_DAY + offset],
                                          &zone_line.until_day_number,
                                          &zone_line.until_day_weekday);
    zone_line.until_time_seconds = parse_time (data,
                                               data->fields[ZONE_UNTIL_TIME + offset],
                                               &zone_line.until_time_code);

    /* We also want to know the maximum year used in any UNTIL value, so we
       know where to expand all the infinite Rule data to. */
    if (zone_line.until_year != YEAR_MAXIMUM
        && zone_line.until_year != YEAR_MINIMUM)
      data->max_until_year = MAX (data->max_until_year, zone_line.until_year);

  } else {
    zone_line.until_set = FALSE;
  }

  /* Append it to the last Zone, since that is the one we are currently
     reading. */
  zone = &g_array_index (data->zone_data, ZoneData, data->zone_data->len - 1);
  g_array_append_val (zone->zone_line_data, zone_line);

  return zone_line.until_set;
}
예제 #7
0
파일: parse.c 프로젝트: rkd77/elinks-tv
struct ftp_file_info *
parse_ftp_winnt_response(struct ftp_file_info *info, unsigned char *src, int len)
{
	struct tm mtime;
	unsigned char *end = src + len;

	/* Extracting name is a bit of black magic and we have to do it
	 * before `strtok' inserted extra \0 characters in the line
	 * string. For the moment let us just suppose that the name starts at
	 * column 39 of the listing. This way we could also recognize
	 * filenames that begin with a series of space characters (but who
	 * really wants to use such filenames anyway?). */
	if (len <= 39) return NULL;

	info->name.source = src + 39;
	info->name.length = end - src - 39;


	/* First column: mm-dd-yy. Should number parsing of the month fail,
	 * january will be assumed. */

	memset(&mtime, 0, sizeof(mtime));
	mtime.tm_isdst = -1;

	mtime.tm_mon = (int) parse_ftp_number(&src, end, 1, 12);
	if (src + 2 >= end || *src != '-')
		return NULL;

	src++;

	mtime.tm_mday = parse_day((const unsigned char **) &src, end);
	if (src + 2 >= end || *src != '-')
		return NULL;

	src++;

	mtime.tm_year = parse_year((const unsigned char **) &src, end);
	if (src >= end || mtime.tm_year == -1)
		return NULL;

	skip_space_end(src, end);
	if (src >= end) return NULL;


	/* Second column: hh:mm[AP]M, listing does not contain value for
	 * seconds */

	if (!parse_time((const unsigned char **) &src, &mtime, end))
		return NULL;

	/* Store the time-stamp. */
	info->mtime = mktime(&mtime);

	skip_nonspace_end(src, end);
	skip_space_end(src, end);
	if (src >= end) return NULL;


	/* Third column: Either file length, or <DIR>. We also set the
	 * permissions (guessed as 0644 for plain files and 0755 for directories
	 * as the listing does not give us a clue) and filetype here. */

	if (*src == '<') {
		info->type = FTP_FILE_DIRECTORY;
		info->permissions = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

	} else if (isdigit(*src)) {
		info->type = FTP_FILE_PLAINFILE;
		info->size = parse_ftp_number(&src, end, 0, OFFT_MAX);
		info->permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

	} else {
		info->type = FTP_FILE_UNKNOWN;
	}

	return info;
}
예제 #8
0
파일: parse.c 프로젝트: rkd77/elinks-tv
static struct ftp_file_info *
parse_ftp_unix_response(struct ftp_file_info *info, unsigned char *src, int len)
{
	unsigned char *end = src + len;
	unsigned char *pos;
	struct tm mtime;
	enum ftp_unix fact;

	/* Decide the file type. */
	{
		int type = (int)*src++;

		switch (type) {
		case FTP_FILE_PLAINFILE:
		case FTP_FILE_DIRECTORY:
		case FTP_FILE_SYMLINK:
			info->type = type;
			break;

		default:
			info->type = FTP_FILE_UNKNOWN;
		}
	}

	memset(&mtime, 0, sizeof(mtime));
	mtime.tm_isdst = -1;

	/* Following is only needed to handle NetWare listings which are not
	 * (yet) handled. So disabled for now. --Zas */
	/* skip_space_end(src, end); */

	fact = FTP_UNIX_PERMISSIONS;

	for (pos = src; src < end; src = pos) {
		skip_nonspace_end(pos, end);

		switch (fact) {
		case FTP_UNIX_PERMISSIONS:
			/* We wanna know permissions as well! And I decided to
			 * completely ignore the NetWare perms, they are very
			 * rare and of some nonstandart format.  If you want
			 * them, though, I'll accept patch enabling them.
			 * --pasky */
			if (pos - src == 9)	/* 9 is length of "rwxrwxrwx". */
				info->permissions = parse_ftp_unix_permissions(src, 9);
			fact = FTP_UNIX_SIZE;
			break;

		case FTP_UNIX_SIZE:
			/* Search for the size and month name combo: */
			if (info->size != FTP_SIZE_UNKNOWN
			    && pos - src == 3) {
				int month = parse_month((const unsigned char **) &src, pos);

				if (month != -1) {
					fact = FTP_UNIX_DAY;
					mtime.tm_mon = month;
					break;
				}
			}

			if (!isdigit(*src)) {
				info->size = FTP_SIZE_UNKNOWN;
				break;
			}

			info->size = parse_ftp_number(&src, pos, 0, OFFT_MAX);
			break;

		case FTP_UNIX_DAY:
			mtime.tm_mday = parse_day((const unsigned char **) &src, pos);
			fact = FTP_UNIX_TIME;
			break;

		case FTP_UNIX_TIME:
			/* This ought to be either the time, or the
			 * year. Let's be flexible! */
			fact = FTP_UNIX_NAME;

			/* We must deal with digits.  */
			if (!isdigit (*src))
				break;

			/* If we have a number x, it's a year. If we have x:y,
			 * it's hours and minutes. */
			if (!memchr(src, ':', pos - src)) {
				mtime.tm_year = parse_year((const unsigned char **) &src, pos);
				break;
			}

			if (!parse_time((const unsigned char **) &src, &mtime, pos)) {
				mtime.tm_hour = mtime.tm_min = mtime.tm_sec = 0;
			}
			break;

		case FTP_UNIX_NAME:
			/* Since the file name may contain spaces use @end as the
			 * token ending and not @pos. */

			info->name.source = src;
			info->name.length = end - src;

			/* 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. */

#define check_trailing_char(string, trailchar) \
	((string)->length > 0 \
	 && (string)->source[(string)->length - 1] == (trailchar))

			switch (info->type) {
			case FTP_FILE_DIRECTORY:
				/* Check for trailing `/' */
				if (check_trailing_char(&info->name, '/'))
					info->name.length--;
				break;

			case FTP_FILE_SYMLINK:
				/* If the file is a symbolic link, it should
				 * have a ` -> ' somewhere. */
				while (pos && pos + 3 < end) {
					if (!memcmp(pos, " -> ", 4)) {
						info->symlink.source = pos + 4;
						info->symlink.length = end - pos - 4;
						info->name.length = pos - src;
						break;
					}

					pos = (unsigned char *)memchr(pos + 1, ' ', end - pos);
				}

				if (!info->symlink.source)
					return NULL;

				/* Check for trailing `@' on link and trailing
				 * `/' on the link target if it's a directory */
				if (check_trailing_char(&info->name, '@'))
					info->name.length--;

				if (check_trailing_char(&info->symlink, '/'))
					info->symlink.length--;
				break;

			case FTP_FILE_PLAINFILE:
				/* Check for trailing `*' on files which are
				 * executable. */
				if ((info->permissions & 0111)
				    && check_trailing_char(&info->name, '*'))
					info->name.length--;

			default:
				break;
			}

			if (mtime.tm_year == 0) {
				/* Get the current time.  */
				time_t timenow = time(NULL);
				struct tm *now = localtime(&timenow);

				mtime.tm_year = now->tm_year;

				/* Some listings will not specify the year if it
				 * is "obvious" that the file was from the
				 * previous year. E.g. if today is 97-01-12, and
				 * you see a file of Dec 15th, its year is 1996,
				 * not 1997. Thanks to Vladimir Volovich for
				 * mentioning this! */
				if (mtime.tm_mon > now->tm_mon)
					mtime.tm_year--;
			}

			info->mtime = mktime(&mtime); /* store the time-stamp */
			info->local_time_zone = 1;

			return info;
		}

		skip_space_end(pos, end);
	}

	return NULL;
}
예제 #9
0
struct ftp_file_info *parse_ftp_winnt_response( struct ftp_file_info *info, unsigned char *src, int len )
{
  int eax;
  int ecx;
  int edx;
  struct tm mtime;
  unsigned char *end;
  if ( len > 39 )
  {
    info->name.source = &src[39];
    info->name.length = len - 39;
    memset( &mtime.tm_sec, 0, 44 );
    mtime.tm_isdst = -1;
    if ( src < src + len && src[0] - 48 >= 9 )
    {
      end[0] = src + len;
      do
      {
      }
      while ( src[1] + 1 < end[0] && src[0] - 48 >= 9 );
      info[0] = info[0];
      src++;
      if ( ebp_100 < 1 && ( ccdep1 < ccdep2 || eax <= 12 ) )
      {
        if ( edx < 1 )
        {
          if ( ccdep2 <= ccdep1 )
          {
            if ( eax < 1 )
            {
            }
          }
        }
      }
    }
    else
      src = src;
    if ( src[1] + 2 < src + len )
    {
      mtime.tm_mon = -1;
      if ( src[1] == '-' )
      {
        src = src[1] + 1;
        parse_day( &src, src + len );
        if ( src[2] < src + len )
        {
          mtime.tm_mday = parse_day( &src, src + len );
          if ( src[0] == '-' )
          {
            src++;
            mtime.tm_year = parse_year( &src, src + len );
            if ( src < src + len && mtime.tm_year != -1 )
            {
              do
              {
                if ( src[0] != ' ' )
                {
                  if ( parse_time( &src, &mtime, src + len ) )
                  {
                    info->mtime = mktime( &mtime.tm_sec );
                    src[0] = src;
                    while ( src < src + len && src[1] != ' ' )
                    {
                      src++;
                    }
                    return &src[1];
                  }
                }
                else
                {
                  src = src[1] + 1;
                }
              }
              while ( src[1] + 1 < src + len );
            }
          }
        }
      }
    }
  }
  info[0].type = 0;
}