Beispiel #1
0
struct timespec
dtotimespec (double sec)
{
  double min_representable = TYPE_MINIMUM (time_t);
  double max_representable =
    ((TYPE_MAXIMUM (time_t) * (double) TIMESPEC_RESOLUTION
      + (TIMESPEC_RESOLUTION - 1))
     / TIMESPEC_RESOLUTION);

  if (! (min_representable < sec))
    return make_timespec (TYPE_MINIMUM (time_t), 0);
  else if (! (sec < max_representable))
    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_RESOLUTION - 1);
  else
    {
      time_t s = sec;
      double frac = TIMESPEC_RESOLUTION * (sec - s);
      long ns = frac;
      ns += ns < frac;
      s += ns / TIMESPEC_RESOLUTION;
      ns %= TIMESPEC_RESOLUTION;

      if (ns < 0)
        {
          s--;
          ns += TIMESPEC_RESOLUTION;
        }

      return make_timespec (s, ns);
    }
}
Beispiel #2
0
struct timespec
dtotimespec (double sec)
{
  if (! (TYPE_MINIMUM (time_t) < sec))
    return make_timespec (TYPE_MINIMUM (time_t), 0);
  else if (! (sec < 1.0 + TYPE_MAXIMUM (time_t)))
    return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_RESOLUTION - 1);
  else
    {
      time_t s = sec;
      double frac = TIMESPEC_RESOLUTION * (sec - s);
      long ns = frac;
      ns += ns < frac;
      s += ns / TIMESPEC_RESOLUTION;
      ns %= TIMESPEC_RESOLUTION;

      if (ns < 0)
        {
          s--;
          ns += TIMESPEC_RESOLUTION;
        }

      return make_timespec (s, ns);
    }
}
Beispiel #3
0
/* Read incremental snapshot format 2 */
static void
read_incr_db_2 (void)
{
  struct obstack stk;
  char offbuf[INT_BUFSIZE_BOUND (off_t)];

  obstack_init (&stk);

  read_timespec (listed_incremental_stream, &newer_mtime_option);

  for (;;)
    {
      intmax_t i;
      struct timespec mtime;
      dev_t dev;
      ino_t ino;
      bool nfs;
      char *name;
      char *content;
      size_t s;

      if (! read_num (listed_incremental_stream, "nfs", 0, 1, &i))
	return; /* Normal return */

      nfs = i;

      read_timespec (listed_incremental_stream, &mtime);

      if (! read_num (listed_incremental_stream, "dev",
		      TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), &i))
	break;
      dev = i;

      if (! read_num (listed_incremental_stream, "ino",
		      TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), &i))
	break;
      ino = i;

      if (read_obstack (listed_incremental_stream, &stk, &s))
	break;

      name = obstack_finish (&stk);

      while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
	;
      if (getc (listed_incremental_stream) != 0)
	FATAL_ERROR ((0, 0, _("%s: byte %s: %s"),
		      quotearg_colon (listed_incremental_option),
		      offtostr (ftello (listed_incremental_stream), offbuf),
		      _("Missing record terminator")));

      content = obstack_finish (&stk);
      note_directory (name, mtime, dev, ino, nfs, false, content);
      obstack_free (&stk, content);
    }
  FATAL_ERROR ((0, 0, "%s: %s",
		quotearg_colon (listed_incremental_option),
		_("Unexpected EOF in snapshot file")));
}
Beispiel #4
0
/* Read incremental snapshot format 2 */
static void
read_incr_db_2 ()
{
  uintmax_t u;
  struct obstack stk;

  obstack_init (&stk);

  read_timespec (listed_incremental_stream, &newer_mtime_option);

  for (;;)
    {
      struct timespec mtime;
      dev_t dev;
      ino_t ino;
      bool nfs;
      char *name;
      char *content;
      size_t s;

      if (read_num (listed_incremental_stream, 1, &u))
	return; /* Normal return */

      nfs = u;

      read_timespec (listed_incremental_stream, &mtime);

      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
	break;
      dev = u;

      if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
	break;
      ino = u;

      if (read_obstack (listed_incremental_stream, &stk, &s))
	break;

      name = obstack_finish (&stk);

      while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
	;
      if (getc (listed_incremental_stream) != 0)
	FATAL_ERROR ((0, 0, "%s: %s",
		      quotearg_colon (listed_incremental_option),
		      _("Missing record terminator")));

      content = obstack_finish (&stk);
      note_directory (name, mtime, dev, ino, nfs, false, content);
      obstack_free (&stk, content);
    }
  FATAL_ERROR ((0, 0, "%s: %s",
		quotearg_colon (listed_incremental_option),
		_("Unexpected EOF in snapshot file")));
}
Beispiel #5
0
static void
read_timespec (FILE *fp, struct timespec *pval)
{
  int c = getc (fp);
  intmax_t i;
  uintmax_t u;

  if (c == '-')
    {
      read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
      c = 0;
      pval->tv_sec = i;
    }
  else
    {
      c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
      pval->tv_sec = u;
    }

  if (c || read_num (fp, BILLION - 1, &u))
    FATAL_ERROR ((0, 0, "%s: %s",
		  quotearg_colon (listed_incremental_option),
		  _("Unexpected EOF in snapshot file")));
  pval->tv_nsec = u;
}
Beispiel #6
0
struct atimer *
start_atimer (enum atimer_type type, struct timespec timestamp,
	      atimer_callback fn, void *client_data)
{
  struct atimer *t;
  sigset_t oldset;

  /* Round TIME up to the next full second if we don't have
     itimers.  */
#ifndef HAVE_SETITIMER
  if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t))
    timestamp = make_timespec (timestamp.tv_sec + 1, 0);
#endif /* not HAVE_SETITIMER */

  /* Get an atimer structure from the free-list, or allocate
     a new one.  */
  if (free_atimers)
    {
      t = free_atimers;
      free_atimers = t->next;
    }
  else
    t = xmalloc (sizeof *t);

  /* Fill the atimer structure.  */
  memset (t, 0, sizeof *t);
  t->type = type;
  t->fn = fn;
  t->client_data = client_data;

  block_atimers (&oldset);

  /* Compute the timer's expiration time.  */
  switch (type)
    {
    case ATIMER_ABSOLUTE:
      t->expiration = timestamp;
      break;

    case ATIMER_RELATIVE:
      t->expiration = timespec_add (current_timespec (), timestamp);
      break;

    case ATIMER_CONTINUOUS:
      t->expiration = timespec_add (current_timespec (), timestamp);
      t->interval = timestamp;
      break;
    }

  /* Insert the timer in the list of active atimers.  */
  schedule_atimer (t);
  unblock_atimers (&oldset);

  /* Arrange for a SIGALRM at the time the next atimer is ripe.  */
  set_alarm ();

  return t;
}
Beispiel #7
0
/* Output incremental data for the directory ENTRY to the file DATA.
   Return nonzero if successful, preserving errno on write failure.  */
static bool
write_directory_file_entry (void *entry, void *data)
{
  struct directory const *directory = entry;
  FILE *fp = data;

  if (DIR_IS_FOUND (directory))
    {
      char buf[SYSINT_BUFSIZE];
      char const *s;

      s = DIR_IS_NFS (directory) ? "1" : "0";
      fwrite (s, 2, 1, fp);
      s = sysinttostr (directory->mtime.tv_sec, TYPE_MINIMUM (time_t),
		       TYPE_MAXIMUM (time_t), buf);
      fwrite (s, strlen (s) + 1, 1, fp);
      s = imaxtostr (directory->mtime.tv_nsec, buf);
      fwrite (s, strlen (s) + 1, 1, fp);
      s = sysinttostr (directory->device_number,
		       TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), buf);
      fwrite (s, strlen (s) + 1, 1, fp);
      s = sysinttostr (directory->inode_number,
		       TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), buf);
      fwrite (s, strlen (s) + 1, 1, fp);

      fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
      if (directory->dump)
	{
	  const char *p;
	  struct dumpdir_iter *itr;

	  for (p = dumpdir_first (directory->dump, 0, &itr);
	       p;
	       p = dumpdir_next (itr))
	    fwrite (p, strlen (p) + 1, 1, fp);
	  free (itr);
	}
      fwrite ("\0\0", 2, 1, fp);
    }

  return ! ferror (fp);
}
Beispiel #8
0
struct timespec
timespec_add (struct timespec a, struct timespec b)
{
    time_t rs = a.tv_sec;
    time_t bs = b.tv_sec;
    int ns = a.tv_nsec + b.tv_nsec;
    int nsd = ns - TIMESPEC_RESOLUTION;
    int rns = ns;

    if (0 <= nsd)
    {
        rns = nsd;
        if (rs == TYPE_MAXIMUM (time_t))
        {
            if (0 <= bs)
                goto high_overflow;
            bs++;
        }
        else
            rs++;
    }

    if (INT_ADD_OVERFLOW (rs, bs))
    {
        if (rs < 0)
        {
            rs = TYPE_MINIMUM (time_t);
            rns = 0;
        }
        else
        {
high_overflow:
            rs = TYPE_MAXIMUM (time_t);
            rns = TIMESPEC_RESOLUTION - 1;
        }
    }
    else
        rs += bs;

    return make_timespec (rs, rns);
}
Beispiel #9
0
int
nanosleep (const struct timespec *requested_delay,
           struct timespec *remaining_delay)
# undef nanosleep
{
  /* nanosleep mishandles large sleeps due to internal overflow problems.
     The worst known case of this is Linux 2.6.9 with glibc 2.3.4, which
     can't sleep more than 24.85 days (2^31 milliseconds).  Similarly,
     cygwin 1.5.x, which can't sleep more than 49.7 days (2^32 milliseconds).
     Solve this by breaking the sleep up into smaller chunks.  */

  if (requested_delay->tv_nsec < 0 || BILLION <= requested_delay->tv_nsec)
    {
      errno = EINVAL;
      return -1;
    }

  {
    /* Verify that time_t is large enough.  */
    verify (TYPE_MAXIMUM (time_t) / 24 / 24 / 60 / 60);
    const time_t limit = 24 * 24 * 60 * 60;
    time_t seconds = requested_delay->tv_sec;
    struct timespec intermediate;
    intermediate.tv_nsec = 0;

    while (limit < seconds)
      {
        int result;
        intermediate.tv_sec = limit;
        result = nanosleep (&intermediate, remaining_delay);
        seconds -= limit;
        if (result)
          {
            if (remaining_delay)
              {
                remaining_delay->tv_sec += seconds;
                remaining_delay->tv_nsec += requested_delay->tv_nsec;
                if (BILLION <= requested_delay->tv_nsec)
                  {
                    remaining_delay->tv_sec++;
                    remaining_delay->tv_nsec -= BILLION;
                  }
              }
            return result;
          }
      }
    intermediate.tv_sec = seconds;
    intermediate.tv_nsec = requested_delay->tv_nsec;
    return nanosleep (&intermediate, remaining_delay);
  }
}
/* Hash some device info.  */
static size_t
dev_info_hash (void const *x, size_t table_size)
{
  struct fs_res const *p = x;

  /* Beware signed arithmetic gotchas.  */
  if (TYPE_SIGNED (dev_t) && SIZE_MAX < MAX (INT_MAX, TYPE_MAXIMUM (dev_t)))
    {
      uintmax_t dev = p->dev;
      return dev % table_size;
    }

  return p->dev % table_size;
}
Beispiel #11
0
static void
print_context_label (char const *mark,
		     struct file_data *inf,
		     char const *name,
		     char const *label)
{
  if (label)
    fprintf (outfile, "%s %s\n", mark, label);
  else
    {
      char buf[MAX (INT_STRLEN_BOUND (int) + 32,
		    INT_STRLEN_BOUND (time_t) + 11)];
      struct tm const *tm = localtime (&inf->stat.st_mtime);
      int nsec = get_stat_mtime_ns (&inf->stat);
      if (! (tm && nstrftime (buf, sizeof buf, time_format, tm, 0, nsec)))
	{
	  verify (TYPE_IS_INTEGER (time_t));
	  if (LONG_MIN <= TYPE_MINIMUM (time_t)
	      && TYPE_MAXIMUM (time_t) <= LONG_MAX)
	    {
	      long int sec = inf->stat.st_mtime;
	      sprintf (buf, "%ld.%.9d", sec, nsec);
	    }
	  else if (TYPE_MAXIMUM (time_t) <= INTMAX_MAX)
	    {
	      intmax_t sec = inf->stat.st_mtime;
	      sprintf (buf, "%"PRIdMAX".%.9d", sec, nsec);
	    }
	  else
	    {
	      uintmax_t sec = inf->stat.st_mtime;
	      sprintf (buf, "%"PRIuMAX".%.9d", sec, nsec);
	    }
	}
      fprintf (outfile, "%s %s\t%s\n", mark, name, buf);
    }
}
Beispiel #12
0
static int
my_usleep (const struct timespec *ts_delay)
{
  struct timeval tv_delay;
  tv_delay.tv_sec = ts_delay->tv_sec;
  tv_delay.tv_usec = (ts_delay->tv_nsec + 999) / 1000;
  if (tv_delay.tv_usec == 1000000)
    {
      if (tv_delay.tv_sec == TYPE_MAXIMUM (time_t))
        tv_delay.tv_usec = 1000000 - 1; /* close enough */
      else
        {
          tv_delay.tv_sec++;
          tv_delay.tv_usec = 0;
        }
    }
  return select (0, NULL, NULL, NULL, &tv_delay);
}
Beispiel #13
0
static bool
decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
  switch (_decode_time (ts, arg, keyword))
    {
    case decode_time_success:
      return true;
    case decode_time_bad_header:
      ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
	      keyword, arg));
      return false;
    case decode_time_range:
      out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
			   TYPE_MAXIMUM (time_t));
      return false;
    }
  return true;
}
Beispiel #14
0
static void
read_timespec (FILE *fp, struct timespec *pval)
{
  intmax_t s, ns;

  if (read_num (fp, "sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), &s)
      && read_num (fp, "nsec", 0, BILLION - 1, &ns))
    {
      pval->tv_sec = s;
      pval->tv_nsec = ns;
    }
  else
    {
      FATAL_ERROR ((0, 0, "%s: %s",
		    quotearg_colon (listed_incremental_option),
		    _("Unexpected EOF in snapshot file")));
    }
}
Beispiel #15
0
struct timespec
timespec_add (struct timespec a, struct timespec b)
{
  time_t rs = a.tv_sec;
  time_t bs = b.tv_sec;
  int ns = a.tv_nsec + b.tv_nsec;
  int nsd = ns - TIMESPEC_RESOLUTION;
  int rns = ns;
  time_t tmin = TYPE_MINIMUM (time_t);
  time_t tmax = TYPE_MAXIMUM (time_t);

  if (0 <= nsd)
    {
      rns = nsd;
      if (bs < tmax)
        bs++;
      else if (rs < 0)
        rs++;
      else
        goto high_overflow;
    }

  /* INT_ADD_WRAPV is not appropriate since time_t might be unsigned.
     In theory time_t might be narrower than int, so plain
     INT_ADD_OVERFLOW does not suffice.  */
  if (! INT_ADD_OVERFLOW (rs, bs) && tmin <= rs + bs && rs + bs <= tmax)
    rs += bs;
  else
    {
      if (rs < 0)
        {
          rs = tmin;
          rns = 0;
        }
      else
        {
        high_overflow:
          rs = tmax;
          rns = TIMESPEC_RESOLUTION - 1;
        }
    }

  return make_timespec (rs, rns);
}
struct timespec
timespec_sub (struct timespec a, struct timespec b)
{
  struct timespec r;
  time_t rs = a.tv_sec;
  time_t bs = b.tv_sec;
  int ns = a.tv_nsec - b.tv_nsec;
  int rns = ns;

  if (ns < 0)
    {
      rns = ns + 1000000000;
      if (rs == TYPE_MINIMUM (time_t))
        {
          if (bs <= 0)
            goto low_overflow;
          bs--;
        }
      else
        rs--;
    }

  if (INT_SUBTRACT_OVERFLOW (rs, bs))
    {
      if (rs < 0)
        {
        low_overflow:
          rs = TYPE_MINIMUM (time_t);
          rns = 0;
        }
      else
        {
          rs = TYPE_MAXIMUM (time_t);
          rns = 999999999;
        }
    }
  else
    rs -= bs;

  r.tv_sec = rs;
  r.tv_nsec = rns;
  return r;
}
Beispiel #17
0
static bool
decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
  char *arg_lim;
  struct timespec t = decode_timespec (arg, &arg_lim, true);

  if (! valid_timespec (t))
    {
      if (arg < arg_lim && !*arg_lim)
	out_of_range_header (keyword, arg, TYPE_MINIMUM (time_t),
			     TYPE_MAXIMUM (time_t));
      else
	ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
		keyword, arg));
      return false;
    }

  *ts = t;
  return true;
}
Beispiel #18
0
struct timespec
timespec_sub (struct timespec a, struct timespec b)
{
  time_t rs = a.tv_sec;
  time_t bs = b.tv_sec;
  int ns = a.tv_nsec - b.tv_nsec;
  int rns = ns;

  if (ns < 0)
    {
      rns = ns + TIMESPEC_RESOLUTION;
      if (rs == TYPE_MINIMUM (time_t))
        {
          if (bs <= 0)
            goto low_overflow;
          bs--;
        }
      else
        rs--;
    }

  if (INT_SUBTRACT_OVERFLOW (rs, bs))
    {
      if (rs < 0)
        {
        low_overflow:
          rs = TYPE_MINIMUM (time_t);
          rns = 0;
        }
      else
        {
          rs = TYPE_MAXIMUM (time_t);
          rns = TIMESPEC_RESOLUTION - 1;
        }
    }
  else
    rs -= bs;

  return make_timespec (rs, rns);
}
Beispiel #19
0
double calculate_percent(uintmax_t value, uintmax_t total) {
  double pct = -1;
  /* I don't understand the below, but it is taken from coreutils' df */
  /* Seems to be calculating pct, in the best possible way */
  if (value <= TYPE_MAXIMUM(uintmax_t) / 100
    && total != 0) {
    uintmax_t u100 = value * 100;
    pct = u100 / total + (u100 % total != 0);
  } else {
    /* Possible rounding errors - see coreutils' df for more explanation */
    double u = value;
    double t = total;
    if (t) {
      long int lipct = pct = u * 100 / t;
      double ipct = lipct;

      /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
      if (ipct - 1 < pct && pct <= ipct + 1)
        pct = ipct + (ipct < pct);
    }
  }
  return pct;
}
Beispiel #20
0
/* Read incremental snapshot formats 0 and 1 */
static void
read_incr_db_01 (int version, const char *initbuf)
{
  int n;
  uintmax_t u;
  time_t sec;
  long int nsec;
  char *buf = NULL;
  size_t bufsize = 0;
  char *ebuf;
  long lineno = 1;

  if (version == 1)
    {
      if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
	{
	  read_error (listed_incremental_option);
	  free (buf);
	  return;
	}
      ++lineno;
    }
  else
    {
      buf = strdup (initbuf);
      bufsize = strlen (buf) + 1;
    }

  sec = TYPE_MINIMUM (time_t);
  nsec = -1;
  errno = 0;
  u = strtoumax (buf, &ebuf, 10);
  if (!errno && TYPE_MAXIMUM (time_t) < u)
    errno = ERANGE;
  if (errno || buf == ebuf)
    ERROR ((0, errno, "%s:%ld: %s",
	    quotearg_colon (listed_incremental_option),
	    lineno,
	    _("Invalid time stamp")));
  else
    {
      sec = u;

      if (version == 1 && *ebuf)
	{
	  char const *buf_ns = ebuf + 1;
	  errno = 0;
	  u = strtoumax (buf_ns, &ebuf, 10);
	  if (!errno && BILLION <= u)
	    errno = ERANGE;
	  if (errno || buf_ns == ebuf)
	    {
	      ERROR ((0, errno, "%s:%ld: %s",
		      quotearg_colon (listed_incremental_option),
		      lineno,
		      _("Invalid time stamp")));
	      sec = TYPE_MINIMUM (time_t);
	    }
	  else
	    nsec = u;
	}
      else
	{
	  /* pre-1 incremental format does not contain nanoseconds */
	  nsec = 0;
	}
    }
  newer_mtime_option.tv_sec = sec;
  newer_mtime_option.tv_nsec = nsec;


  while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
    {
      dev_t dev;
      ino_t ino;
      bool nfs = buf[0] == '+';
      char *strp = buf + nfs;
      struct timespec mtime;

      lineno++;

      if (buf[n - 1] == '\n')
	buf[n - 1] = '\0';

      if (version == 1)
	{
	  errno = 0;
	  u = strtoumax (strp, &ebuf, 10);
	  if (!errno && TYPE_MAXIMUM (time_t) < u)
	    errno = ERANGE;
	  if (errno || strp == ebuf || *ebuf != ' ')
	    {
	      ERROR ((0, errno, "%s:%ld: %s",
		      quotearg_colon (listed_incremental_option), lineno,
		      _("Invalid modification time (seconds)")));
	      sec = (time_t) -1;
	    }
	  else
	    sec = u;
	  strp = ebuf;

	  errno = 0;
	  u = strtoumax (strp, &ebuf, 10);
	  if (!errno && BILLION <= u)
	    errno = ERANGE;
	  if (errno || strp == ebuf || *ebuf != ' ')
	    {
	      ERROR ((0, errno, "%s:%ld: %s",
		      quotearg_colon (listed_incremental_option), lineno,
		      _("Invalid modification time (nanoseconds)")));
	      nsec = -1;
	    }
	  else
	    nsec = u;
	  mtime.tv_sec = sec;
	  mtime.tv_nsec = nsec;
	  strp = ebuf;
	}
      else
	memset (&mtime, 0, sizeof mtime);

      errno = 0;
      u = strtoumax (strp, &ebuf, 10);
      if (!errno && TYPE_MAXIMUM (dev_t) < u)
	errno = ERANGE;
      if (errno || strp == ebuf || *ebuf != ' ')
	{
	  ERROR ((0, errno, "%s:%ld: %s",
		  quotearg_colon (listed_incremental_option), lineno,
		  _("Invalid device number")));
	  dev = (dev_t) -1;
	}
      else
	dev = u;
      strp = ebuf;

      errno = 0;
      u = strtoumax (strp, &ebuf, 10);
      if (!errno && TYPE_MAXIMUM (ino_t) < u)
	errno = ERANGE;
      if (errno || strp == ebuf || *ebuf != ' ')
	{
	  ERROR ((0, errno, "%s:%ld: %s",
		  quotearg_colon (listed_incremental_option), lineno,
		  _("Invalid inode number")));
	  ino = (ino_t) -1;
	}
      else
	ino = u;
      strp = ebuf;

      strp++;
      unquote_string (strp);
      note_directory (strp, mtime, dev, ino, nfs, false, NULL);
    }
  free (buf);
}
Beispiel #21
0
static enum profiler_cpu_running
setup_cpu_timer (Lisp_Object sampling_interval)
{
  struct sigaction action;
  struct itimerval timer;
  struct timespec interval;
  int billion = 1000000000;

  if (! RANGED_INTEGERP (1, sampling_interval,
			 (TYPE_MAXIMUM (time_t) < EMACS_INT_MAX / billion
			  ? ((EMACS_INT) TYPE_MAXIMUM (time_t) * billion
			     + (billion - 1))
			  : EMACS_INT_MAX)))
    return NOT_RUNNING;

  current_sampling_interval = XINT (sampling_interval);
  interval = make_timespec (current_sampling_interval / billion,
			    current_sampling_interval % billion);
  emacs_sigaction_init (&action, deliver_profiler_signal);
  sigaction (SIGPROF, &action, 0);

#ifdef HAVE_ITIMERSPEC
  if (! profiler_timer_ok)
    {
      /* System clocks to try, in decreasing order of desirability.  */
      static clockid_t const system_clock[] = {
#ifdef CLOCK_THREAD_CPUTIME_ID
	CLOCK_THREAD_CPUTIME_ID,
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
	CLOCK_PROCESS_CPUTIME_ID,
#endif
#ifdef CLOCK_MONOTONIC
	CLOCK_MONOTONIC,
#endif
	CLOCK_REALTIME
      };
      int i;
      struct sigevent sigev;
      sigev.sigev_value.sival_ptr = &profiler_timer;
      sigev.sigev_signo = SIGPROF;
      sigev.sigev_notify = SIGEV_SIGNAL;

      for (i = 0; i < ARRAYELTS (system_clock); i++)
	if (timer_create (system_clock[i], &sigev, &profiler_timer) == 0)
	  {
	    profiler_timer_ok = 1;
	    break;
	  }
    }

  if (profiler_timer_ok)
    {
      struct itimerspec ispec;
      ispec.it_value = ispec.it_interval = interval;
      if (timer_settime (profiler_timer, 0, &ispec, 0) == 0)
	return TIMER_SETTIME_RUNNING;
    }
#endif

#ifdef HAVE_SETITIMER
  timer.it_value = timer.it_interval = make_timeval (interval);
  if (setitimer (ITIMER_PROF, &timer, 0) == 0)
    return SETITIMER_RUNNING;
#endif

  return NOT_RUNNING;
}
Beispiel #22
0
   with any changes made to the read_num() calls in the parsing
   loop inside read_incr_db_2().

   (This function is invoked via the --show-snapshot-field-ranges
   command line option.) */

struct field_range
{
  char const *fieldname;
  intmax_t min_val;
  uintmax_t max_val;
};

static struct field_range const field_ranges[] = {
  { "nfs", 0, 1 },
  { "timestamp_sec", TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t) },
  { "timestamp_nsec", 0, BILLION - 1 },
  { "dev", TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t) },
  { "ino", TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t) },
  { NULL, 0, 0 }
};

void
show_snapshot_field_ranges (void)
{
  struct field_range const *p;
  char minbuf[SYSINT_BUFSIZE];
  char maxbuf[SYSINT_BUFSIZE];

  printf("This tar's snapshot file field ranges are\n");
  printf ("   (%-15s => [ %s, %s ]):\n\n", "field name", "min", "max");
Beispiel #23
0
static enum decode_time_status
_decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
  time_t s;
  unsigned long int ns = 0;
  char *p;
  char *arg_lim;
  bool negative = *arg == '-';

  errno = 0;

  if (ISDIGIT (arg[negative]))
    {
      if (negative)
	{
	  intmax_t i = strtoimax (arg, &arg_lim, 10);
	  if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
	    return decode_time_range;
	  s = i;
	}
      else
	{
	  uintmax_t i = strtoumax (arg, &arg_lim, 10);
	  if (TYPE_MAXIMUM (time_t) < i)
	    return decode_time_range;
	  s = i;
	}

      p = arg_lim;

      if (errno == ERANGE)
	return decode_time_range;

      if (*p == '.')
	{
	  int digits = 0;
	  bool trailing_nonzero = false;

	  while (ISDIGIT (*++p))
	    if (digits < LOG10_BILLION)
	      {
		ns = 10 * ns + (*p - '0');
		digits++;
	      }
	    else
	      trailing_nonzero |= *p != '0';

	  while (digits++ < LOG10_BILLION)
	    ns *= 10;

	  if (negative)
	    {
	      /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
		 I.e., truncate time stamps towards minus infinity while
		 converting them to internal form.  */
	      ns += trailing_nonzero;
	      if (ns != 0)
		{
		  if (s == TYPE_MINIMUM (time_t))
		    return decode_time_range;
		  s--;
		  ns = BILLION - ns;
		}
	    }
	}

      if (! *p)
	{
	  ts->tv_sec = s;
	  ts->tv_nsec = ns;
	  return decode_time_success;
	}
    }

  return decode_time_bad_header;
}
Beispiel #24
0
Lisp_Object
get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
  char *from, *to, *name, *p, *p1;
  int fd;
  ptrdiff_t minsize;
  int offset;
  EMACS_INT position;
  Lisp_Object file, tem;
  USE_SAFE_ALLOCA;

  if (INTEGERP (filepos))
    {
      file = Vdoc_file_name;
      position = XINT (filepos);
    }
  else if (CONSP (filepos))
    {
      file = XCAR (filepos);
      position = XINT (XCDR (filepos));
    }
  else
    return Qnil;

  if (position < 0)
    position = - position;

  if (!STRINGP (Vdoc_directory))
    return Qnil;

  if (!STRINGP (file))
    return Qnil;

  /* Put the file name in NAME as a C string.
     If it is relative, combine it with Vdoc_directory.  */

  tem = Ffile_name_absolute_p (file);
  file = ENCODE_FILE (file);
  if (NILP (tem))
    {
      Lisp_Object docdir = ENCODE_FILE (Vdoc_directory);
      minsize = SCHARS (docdir);
      /* sizeof ("../etc/") == 8 */
      if (minsize < 8)
	minsize = 8;
      name = SAFE_ALLOCA (minsize + SCHARS (file) + 8);
      strcpy (name, SSDATA (docdir));
      strcat (name, SSDATA (file));
    }
  else
    {
      name = SSDATA (file);
    }

  fd = emacs_open (name, O_RDONLY, 0);
  if (fd < 0)
    {
#ifndef CANNOT_DUMP
      if (!NILP (Vpurify_flag))
	{
	  /* Preparing to dump; DOC file is probably not installed.
	     So check in ../etc.  */
	  strcpy (name, "../etc/");
	  strcat (name, SSDATA (file));

	  fd = emacs_open (name, O_RDONLY, 0);
	}
#endif
      if (fd < 0)
	error ("Cannot open doc string file \"%s\"", name);
    }

  /* Seek only to beginning of disk block.  */
  /* Make sure we read at least 1024 bytes before `position'
     so we can check the leading text for consistency.  */
  offset = min (position, max (1024, position % (8 * 1024)));
  if (TYPE_MAXIMUM (off_t) < position
      || lseek (fd, position - offset, 0) < 0)
    {
      emacs_close (fd);
      error ("Position %"pI"d out of range in doc string file \"%s\"",
	     position, name);
    }

  SAFE_FREE ();

  /* Read the doc string into get_doc_string_buffer.
     P points beyond the data just read.  */

  p = get_doc_string_buffer;
  while (1)
    {
      ptrdiff_t space_left = (get_doc_string_buffer_size - 1
			      - (p - get_doc_string_buffer));
      int nread;

      /* Allocate or grow the buffer if we need to.  */
      if (space_left <= 0)
	{
	  ptrdiff_t in_buffer = p - get_doc_string_buffer;
	  get_doc_string_buffer =
	    xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
		     16 * 1024, -1, 1);
	  p = get_doc_string_buffer + in_buffer;
	  space_left = (get_doc_string_buffer_size - 1
			- (p - get_doc_string_buffer));
	}

      /* Read a disk block at a time.
         If we read the same block last time, maybe skip this?  */
      if (space_left > 1024 * 8)
	space_left = 1024 * 8;
      nread = emacs_read (fd, p, space_left);
      if (nread < 0)
	{
	  emacs_close (fd);
	  error ("Read error on documentation file");
	}
      p[nread] = 0;
      if (!nread)
	break;
      if (p == get_doc_string_buffer)
	p1 = strchr (p + offset, '\037');
      else
	p1 = strchr (p, '\037');
      if (p1)
	{
	  *p1 = 0;
	  p = p1;
	  break;
	}
      p += nread;
    }
  emacs_close (fd);

  /* Sanity checking.  */
  if (CONSP (filepos))
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != ' ')
	return Qnil;
      while (get_doc_string_buffer[offset - test] >= '0'
	     && get_doc_string_buffer[offset - test] <= '9')
	test++;
      if (get_doc_string_buffer[offset - test++] != '@'
	  || get_doc_string_buffer[offset - test] != '#')
	return Qnil;
    }
  else
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != '\n')
	return Qnil;
      while (get_doc_string_buffer[offset - test] > ' ')
	test++;
      if (get_doc_string_buffer[offset - test] != '\037')
	return Qnil;
    }

  /* Scan the text and perform quoting with ^A (char code 1).
     ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
  from = get_doc_string_buffer + offset;
  to = get_doc_string_buffer + offset;
  while (from != p)
    {
      if (*from == 1)
	{
	  int c;

	  from++;
	  c = *from++;
	  if (c == 1)
	    *to++ = c;
	  else if (c == '0')
	    *to++ = 0;
	  else if (c == '_')
	    *to++ = 037;
	  else
	    {
	      unsigned char uc = c;
	      error ("\
Invalid data in documentation file -- %c followed by code %03o",
		     1, uc);
	    }
	}
      else
	*to++ = *from++;
    }

  /* If DEFINITION, read from this buffer
     the same way we would read bytes from a file.  */
  if (definition)
    {
      read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
      return Fread (Qlambda);
    }

  if (unibyte)
    return make_unibyte_string (get_doc_string_buffer + offset,
				to - (get_doc_string_buffer + offset));
  else
    {
      /* The data determines whether the string is multibyte.  */
      ptrdiff_t nchars =
	multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
				  + offset),
				 to - (get_doc_string_buffer + offset));
      return make_string_from_bytes (get_doc_string_buffer + offset,
				     nchars,
				     to - (get_doc_string_buffer + offset));
    }
}
Beispiel #25
0
/* Read incremental snapshot formats 0 and 1 */
static void
read_incr_db_01 (int version, const char *initbuf)
{
  int n;
  uintmax_t u;
  char *buf = NULL;
  size_t bufsize = 0;
  char *ebuf;
  long lineno = 1;

  if (version == 1)
    {
      if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
	{
	  read_error (listed_incremental_option);
	  free (buf);
	  return;
	}
      ++lineno;
    }
  else
    {
      buf = strdup (initbuf);
      bufsize = strlen (buf) + 1;
    }

  newer_mtime_option = decode_timespec (buf, &ebuf, false);

  if (! valid_timespec (newer_mtime_option))
    ERROR ((0, errno, "%s:%ld: %s",
	    quotearg_colon (listed_incremental_option),
	    lineno,
	    _("Invalid time stamp")));
  else
    {
      if (version == 1 && *ebuf)
	{
	  char const *buf_ns = ebuf + 1;
	  errno = 0;
	  u = strtoumax (buf_ns, &ebuf, 10);
	  if (!errno && BILLION <= u)
	    errno = ERANGE;
	  if (errno || buf_ns == ebuf)
	    {
	      ERROR ((0, errno, "%s:%ld: %s",
		      quotearg_colon (listed_incremental_option),
		      lineno,
		      _("Invalid time stamp")));
	      newer_mtime_option.tv_sec = TYPE_MINIMUM (time_t);
	      newer_mtime_option.tv_nsec = -1;
	    }
	  else
	    newer_mtime_option.tv_nsec = u;
	}
    }

  while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
    {
      dev_t dev;
      ino_t ino;
      bool nfs = buf[0] == '+';
      char *strp = buf + nfs;
      struct timespec mtime;

      lineno++;

      if (buf[n - 1] == '\n')
	buf[n - 1] = '\0';

      if (version == 1)
	{
	  mtime = decode_timespec (strp, &ebuf, false);
	  strp = ebuf;
	  if (!valid_timespec (mtime) || *strp != ' ')
	    ERROR ((0, errno, "%s:%ld: %s",
		    quotearg_colon (listed_incremental_option), lineno,
		    _("Invalid modification time")));

	  errno = 0;
	  u = strtoumax (strp, &ebuf, 10);
	  if (!errno && BILLION <= u)
	    errno = ERANGE;
	  if (errno || strp == ebuf || *ebuf != ' ')
	    {
	      ERROR ((0, errno, "%s:%ld: %s",
		      quotearg_colon (listed_incremental_option), lineno,
		      _("Invalid modification time (nanoseconds)")));
	      mtime.tv_nsec = -1;
	    }
	  else
	    mtime.tv_nsec = u;
	  strp = ebuf;
	}
      else
	mtime.tv_sec = mtime.tv_nsec = 0;

      dev = strtosysint (strp, &ebuf,
			 TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t));
      strp = ebuf;
      if (errno || *strp != ' ')
	ERROR ((0, errno, "%s:%ld: %s",
		quotearg_colon (listed_incremental_option), lineno,
		_("Invalid device number")));

      ino = strtosysint (strp, &ebuf,
			 TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t));
      strp = ebuf;
      if (errno || *strp != ' ')
	ERROR ((0, errno, "%s:%ld: %s",
		quotearg_colon (listed_incremental_option), lineno,
		_("Invalid inode number")));

      strp++;
      unquote_string (strp);
      note_directory (strp, mtime, dev, ino, nfs, false, NULL);
    }
  free (buf);
}
Beispiel #26
0
static int
current_lock_owner (lock_info_type *owner, char *lfname)
{
  int ret;
  ptrdiff_t len;
  lock_info_type local_owner;
  intmax_t n;
  char *at, *dot, *colon;
  char readlink_buf[READLINK_BUFSIZE];
  char *lfinfo = emacs_readlink (lfname, readlink_buf);

  /* If nonexistent lock file, all is well; otherwise, got strange error. */
  if (!lfinfo)
    return errno == ENOENT ? 0 : -1;

  /* Even if the caller doesn't want the owner info, we still have to
     read it to determine return value.  */
  if (!owner)
    owner = &local_owner;

  /* Parse [email protected]:BOOT_TIME.  If can't parse, return -1.  */
  /* The USER is everything before the last @.  */
  at = strrchr (lfinfo, '@');
  dot = strrchr (lfinfo, '.');
  if (!at || !dot)
    {
      if (lfinfo != readlink_buf)
	xfree (lfinfo);
      return -1;
    }
  len = at - lfinfo;
  owner->user = xmalloc (len + 1);
  memcpy (owner->user, lfinfo, len);
  owner->user[len] = 0;

  /* The PID is everything from the last `.' to the `:'.  */
  errno = 0;
  n = strtoimax (dot + 1, NULL, 10);
  owner->pid =
    ((0 <= n && n <= TYPE_MAXIMUM (pid_t)
      && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
     ? n : 0);

  colon = strchr (dot + 1, ':');
  /* After the `:', if there is one, comes the boot time.  */
  n = 0;
  if (colon)
    {
      errno = 0;
      n = strtoimax (colon + 1, NULL, 10);
    }
  owner->boot_time =
    ((0 <= n && n <= TYPE_MAXIMUM (time_t)
      && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
     ? n : 0);

  /* The host is everything in between.  */
  len = dot - at - 1;
  owner->host = xmalloc (len + 1);
  memcpy (owner->host, at + 1, len);
  owner->host[len] = 0;

  /* We're done looking at the link info.  */
  if (lfinfo != readlink_buf)
    xfree (lfinfo);

  /* On current host?  */
  if (STRINGP (Fsystem_name ())
      && strcmp (owner->host, SSDATA (Fsystem_name ())) == 0)
    {
      if (owner->pid == getpid ())
        ret = 2; /* We own it.  */
      else if (owner->pid > 0
               && (kill (owner->pid, 0) >= 0 || errno == EPERM)
	       && (owner->boot_time == 0
		   || within_one_second (owner->boot_time, get_boot_time ())))
        ret = 1; /* An existing process on this machine owns it.  */
      /* The owner process is dead or has a strange pid (<=0), so try to
         zap the lockfile.  */
      else if (unlink (lfname) < 0)
        ret = -1;
      else
	ret = 0;
    }
  else
    { /* If we wanted to support the check for stale locks on remote machines,
         here's where we'd do it.  */
      ret = 1;
    }

  /* Avoid garbage.  */
  if (owner == &local_owner || ret <= 0)
    {
      FREE_LOCK_INFO (*owner);
    }
  return ret;
}
Beispiel #27
0
struct timespec
decode_timespec (char const *arg, char **arg_lim, bool parse_fraction)
{
  time_t s = TYPE_MINIMUM (time_t);
  int ns = -1;
  char const *p = arg;
  bool negative = *arg == '-';
  struct timespec r;

  if (! ISDIGIT (arg[negative]))
    errno = EINVAL;
  else
    {
      errno = 0;

      if (negative)
	{
	  intmax_t i = strtoimax (arg, arg_lim, 10);
	  if (TYPE_SIGNED (time_t) ? TYPE_MINIMUM (time_t) <= i : 0 <= i)
	    s = i;
	  else
	    errno = ERANGE;
	}
      else
	{
	  uintmax_t i = strtoumax (arg, arg_lim, 10);
	  if (i <= TYPE_MAXIMUM (time_t))
	    s = i;
	  else
	    errno = ERANGE;
	}

      p = *arg_lim;
      ns = 0;

      if (parse_fraction && *p == '.')
	{
	  int digits = 0;
	  bool trailing_nonzero = false;

	  while (ISDIGIT (*++p))
	    if (digits < LOG10_BILLION)
	      digits++, ns = 10 * ns + (*p - '0');
	    else
	      trailing_nonzero |= *p != '0';

	  while (digits < LOG10_BILLION)
	    digits++, ns *= 10;

	  if (negative)
	    {
	      /* Convert "-1.10000000000001" to s == -2, ns == 89999999.
		 I.e., truncate time stamps towards minus infinity while
		 converting them to internal form.  */
	      ns += trailing_nonzero;
	      if (ns != 0)
		{
		  if (s == TYPE_MINIMUM (time_t))
		    ns = -1;
		  else
		    {
		      s--;
		      ns = BILLION - ns;
		    }
		}
	    }
	}

      if (errno == ERANGE)
	ns = -1;
    }

  *arg_lim = (char *) p;
  r.tv_sec = s;
  r.tv_nsec = ns;
  return r;
}
Beispiel #28
0
#if __GNUC__ >= 2 && DO_PEDANTIC
# define verify_same_types(expr1,expr2)  \
    extern void _verify_func(__LINE__) (__typeof__ (expr1) *); \
    extern void _verify_func(__LINE__) (__typeof__ (expr2) *);
# define _verify_func(line) _verify_func2(line)
# define _verify_func2(line) verify_func_ ## line
#else
# define verify_same_types(expr1,expr2) extern void verify_func (int)
#endif

/* 7.18.1.1. Exact-width integer types */
/* 7.18.2.1. Limits of exact-width integer types */

int8_t a1[3] = { INT8_C (17), INT8_MIN, INT8_MAX };
verify (TYPE_MINIMUM (int8_t) == INT8_MIN);
verify (TYPE_MAXIMUM (int8_t) == INT8_MAX);
verify_same_types (INT8_MIN, (int8_t) 0 + 0);
verify_same_types (INT8_MAX, (int8_t) 0 + 0);

int16_t a2[3] = { INT16_C (17), INT16_MIN, INT16_MAX };
verify (TYPE_MINIMUM (int16_t) == INT16_MIN);
verify (TYPE_MAXIMUM (int16_t) == INT16_MAX);
verify_same_types (INT16_MIN, (int16_t) 0 + 0);
verify_same_types (INT16_MAX, (int16_t) 0 + 0);

int32_t a3[3] = { INT32_C (17), INT32_MIN, INT32_MAX };
verify (TYPE_MINIMUM (int32_t) == INT32_MIN);
verify (TYPE_MAXIMUM (int32_t) == INT32_MAX);
verify_same_types (INT32_MIN, (int32_t) 0 + 0);
verify_same_types (INT32_MAX, (int32_t) 0 + 0);
Beispiel #29
0
size_t
EGexecute (char const *buf, size_t size, size_t *match_size,
           char const *start_ptr)
{
  char const *buflim, *beg, *end, *match, *best_match, *mb_start;
  char eol = eolbyte;
  int backref;
  regoff_t start;
  size_t len, best_len;
  struct kwsmatch kwsm;
  size_t i, ret_val;
  mb_len_map_t *map = NULL;

  if (MB_CUR_MAX > 1)
    {
      if (match_icase)
        {
          /* mbtolower adds a NUL byte at the end.  That will provide
             space for the sentinel byte dfaexec may add.  */
          char *case_buf = mbtolower (buf, &size, &map);
          if (start_ptr)
            start_ptr = case_buf + (start_ptr - buf);
          buf = case_buf;
        }
    }

  mb_start = buf;
  buflim = buf + size;

  for (beg = end = buf; end < buflim; beg = end)
    {
      if (!start_ptr)
        {
          /* We don't care about an exact match.  */
          if (kwset)
            {
              /* Find a possible match using the KWset matcher. */
              size_t offset = kwsexec (kwset, beg, buflim - beg, &kwsm);
              if (offset == (size_t) -1)
                goto failure;
              beg += offset;
              /* Narrow down to the line containing the candidate, and
                 run it through DFA. */
              if ((end = memchr(beg, eol, buflim - beg)) != NULL)
                end++;
              else
                end = buflim;
              match = beg;
              while (beg > buf && beg[-1] != eol)
                --beg;
              if (kwsm.index < kwset_exact_matches)
                {
                  if (!MBS_SUPPORT)
                    goto success;

                  if (mb_start < beg)
                    mb_start = beg;
                  if (MB_CUR_MAX == 1
                      || !is_mb_middle (&mb_start, match, buflim,
                                        kwsm.size[0]))
                    goto success;
                }
              if (dfaexec (dfa, beg, (char *) end, 0, NULL, &backref) == NULL)
                continue;
            }
          else
            {
              /* No good fixed strings; start with DFA. */
              char const *next_beg = dfaexec (dfa, beg, (char *) buflim,
                                              0, NULL, &backref);
              /* If there's no match, or if we've matched the sentinel,
                 we're done.  */
              if (next_beg == NULL || next_beg == buflim)
                break;
              /* Narrow down to the line we've found. */
              beg = next_beg;
              if ((end = memchr(beg, eol, buflim - beg)) != NULL)
                end++;
              else
                end = buflim;
              while (beg > buf && beg[-1] != eol)
                --beg;
            }
          /* Successful, no backreferences encountered! */
          if (!backref)
            goto success;
        }
      else
        {
          /* We are looking for the leftmost (then longest) exact match.
             We will go through the outer loop only once.  */
          beg = start_ptr;
          end = buflim;
        }

      /* If the "line" is longer than the maximum regexp offset,
         die as if we've run out of memory.  */
      if (TYPE_MAXIMUM (regoff_t) < end - buf - 1)
        xalloc_die ();

      /* If we've made it to this point, this means DFA has seen
         a probable match, and we need to run it through Regex. */
      best_match = end;
      best_len = 0;
      for (i = 0; i < pcount; i++)
        {
          patterns[i].regexbuf.not_eol = 0;
          start = re_search (&(patterns[i].regexbuf),
                             buf, end - buf - 1,
                             beg - buf, end - beg - 1,
                             &(patterns[i].regs));
          if (start < -1)
            xalloc_die ();
          else if (0 <= start)
            {
              len = patterns[i].regs.end[0] - start;
              match = buf + start;
              if (match > best_match)
                continue;
              if (start_ptr && !match_words)
                goto assess_pattern_match;
              if ((!match_lines && !match_words)
                  || (match_lines && len == end - beg - 1))
                {
                  match = beg;
                  len = end - beg;
                  goto assess_pattern_match;
                }
              /* If -w, check if the match aligns with word boundaries.
                 We do this iteratively because:
                 (a) the line may contain more than one occurrence of the
                 pattern, and
                 (b) Several alternatives in the pattern might be valid at a
                 given point, and we may need to consider a shorter one to
                 find a word boundary.  */
              if (match_words)
                while (match <= best_match)
                  {
                    regoff_t shorter_len = 0;
                    if ((match == buf || !WCHAR ((unsigned char) match[-1]))
                        && (start + len == end - buf - 1
                            || !WCHAR ((unsigned char) match[len])))
                      goto assess_pattern_match;
                    if (len > 0)
                      {
                        /* Try a shorter length anchored at the same place. */
                        --len;
                        patterns[i].regexbuf.not_eol = 1;
                        shorter_len = re_match (&(patterns[i].regexbuf),
                                                buf, match + len - beg,
                                                match - buf,
                                                &(patterns[i].regs));
                        if (shorter_len < -1)
                          xalloc_die ();
                      }
                    if (0 < shorter_len)
                      len = shorter_len;
                    else
                      {
                        /* Try looking further on. */
                        if (match == end - 1)
                          break;
                        match++;
                        patterns[i].regexbuf.not_eol = 0;
                        start = re_search (&(patterns[i].regexbuf),
                                           buf, end - buf - 1,
                                           match - buf, end - match - 1,
                                           &(patterns[i].regs));
                        if (start < 0)
                          {
                            if (start < -1)
                              xalloc_die ();
                            break;
                          }
                        len = patterns[i].regs.end[0] - start;
                        match = buf + start;
                      }
                  } /* while (match <= best_match) */
              continue;
            assess_pattern_match:
              if (!start_ptr)
                {
                  /* Good enough for a non-exact match.
                     No need to look at further patterns, if any.  */
                  goto success;
                }
              if (match < best_match || (match == best_match && len > best_len))
                {
                  /* Best exact match:  leftmost, then longest.  */
                  best_match = match;
                  best_len = len;
                }
            } /* if re_search >= 0 */
        } /* for Regex patterns.  */
        if (best_match < end)
          {
            /* We have found an exact match.  We were just
               waiting for the best one (leftmost then longest).  */
            beg = best_match;
            len = best_len;
            goto success_in_len;
          }
    } /* for (beg = end ..) */

 failure:
  ret_val = -1;
  goto out;

 success:
  len = end - beg;
 success_in_len:;
  size_t off = beg - buf;
  mb_case_map_apply (map, &off, &len);
  *match_size = len;
  ret_val = off;
 out:
  return ret_val;
}
Beispiel #30
0
Lisp_Object
get_doc_string (Lisp_Object filepos, bool unibyte, bool definition)
{
  char *from, *to, *name, *p, *p1;
  int fd;
  int offset;
  EMACS_INT position;
  Lisp_Object file, tem, pos;
  ptrdiff_t count;
  USE_SAFE_ALLOCA;

  if (INTEGERP (filepos))
    {
      file = Vdoc_file_name;
      pos = filepos;
    }
  else if (CONSP (filepos))
    {
      file = XCAR (filepos);
      pos = XCDR (filepos);
    }
  else
    return Qnil;

  position = eabs (XINT (pos));

  if (!STRINGP (Vdoc_directory))
    return Qnil;

  if (!STRINGP (file))
    return Qnil;

  /* Put the file name in NAME as a C string.
     If it is relative, combine it with Vdoc_directory.  */

  tem = Ffile_name_absolute_p (file);
  file = ENCODE_FILE (file);
  Lisp_Object docdir
    = NILP (tem) ? ENCODE_FILE (Vdoc_directory) : empty_unibyte_string;
  ptrdiff_t docdir_sizemax = SBYTES (docdir) + 1;
#ifndef CANNOT_DUMP
  docdir_sizemax = max (docdir_sizemax, sizeof sibling_etc);
#endif
  name = SAFE_ALLOCA (docdir_sizemax + SBYTES (file));
  lispstpcpy (lispstpcpy (name, docdir), file);

  fd = emacs_open (name, O_RDONLY, 0);
  if (fd < 0)
    {
#ifndef CANNOT_DUMP
      if (!NILP (Vpurify_flag))
	{
	  /* Preparing to dump; DOC file is probably not installed.
	     So check in ../etc.  */
	  lispstpcpy (stpcpy (name, sibling_etc), file);

	  fd = emacs_open (name, O_RDONLY, 0);
	}
#endif
      if (fd < 0)
	{
	  if (errno == EMFILE || errno == ENFILE)
	    report_file_error ("Read error on documentation file", file);

	  SAFE_FREE ();
	  AUTO_STRING (cannot_open, "Cannot open doc string file \"");
	  AUTO_STRING (quote_nl, "\"\n");
	  return concat3 (cannot_open, file, quote_nl);
	}
    }
  count = SPECPDL_INDEX ();
  record_unwind_protect_int (close_file_unwind, fd);

  /* Seek only to beginning of disk block.  */
  /* Make sure we read at least 1024 bytes before `position'
     so we can check the leading text for consistency.  */
  offset = min (position, max (1024, position % (8 * 1024)));
  if (TYPE_MAXIMUM (off_t) < position
      || lseek (fd, position - offset, 0) < 0)
    error ("Position %"pI"d out of range in doc string file \"%s\"",
	   position, name);

  /* Read the doc string into get_doc_string_buffer.
     P points beyond the data just read.  */

  p = get_doc_string_buffer;
  while (1)
    {
      ptrdiff_t space_left = (get_doc_string_buffer_size - 1
			      - (p - get_doc_string_buffer));
      int nread;

      /* Allocate or grow the buffer if we need to.  */
      if (space_left <= 0)
	{
	  ptrdiff_t in_buffer = p - get_doc_string_buffer;
	  get_doc_string_buffer
	    = xpalloc (get_doc_string_buffer, &get_doc_string_buffer_size,
		       16 * 1024, -1, 1);
	  p = get_doc_string_buffer + in_buffer;
	  space_left = (get_doc_string_buffer_size - 1
			- (p - get_doc_string_buffer));
	}

      /* Read a disk block at a time.
         If we read the same block last time, maybe skip this?  */
      if (space_left > 1024 * 8)
	space_left = 1024 * 8;
      nread = emacs_read (fd, p, space_left);
      if (nread < 0)
	report_file_error ("Read error on documentation file", file);
      p[nread] = 0;
      if (!nread)
	break;
      if (p == get_doc_string_buffer)
	p1 = strchr (p + offset, '\037');
      else
	p1 = strchr (p, '\037');
      if (p1)
	{
	  *p1 = 0;
	  p = p1;
	  break;
	}
      p += nread;
    }
  unbind_to (count, Qnil);
  SAFE_FREE ();

  /* Sanity checking.  */
  if (CONSP (filepos))
    {
      int test = 1;
      /* A dynamic docstring should be either at the very beginning of a "#@
	 comment" or right after a dynamic docstring delimiter (in case we
	 pack several such docstrings within the same comment).  */
      if (get_doc_string_buffer[offset - test] != '\037')
	{
	  if (get_doc_string_buffer[offset - test++] != ' ')
	    return Qnil;
	  while (get_doc_string_buffer[offset - test] >= '0'
		 && get_doc_string_buffer[offset - test] <= '9')
	    test++;
	  if (get_doc_string_buffer[offset - test++] != '@'
	      || get_doc_string_buffer[offset - test] != '#')
	    return Qnil;
	}
    }
  else
    {
      int test = 1;
      if (get_doc_string_buffer[offset - test++] != '\n')
	return Qnil;
      while (get_doc_string_buffer[offset - test] > ' ')
	test++;
      if (get_doc_string_buffer[offset - test] != '\037')
	return Qnil;
    }

  /* Scan the text and perform quoting with ^A (char code 1).
     ^A^A becomes ^A, ^A0 becomes a null char, and ^A_ becomes a ^_.  */
  from = get_doc_string_buffer + offset;
  to = get_doc_string_buffer + offset;
  while (from != p)
    {
      if (*from == 1)
	{
	  int c;

	  from++;
	  c = *from++;
	  if (c == 1)
	    *to++ = c;
	  else if (c == '0')
	    *to++ = 0;
	  else if (c == '_')
	    *to++ = 037;
	  else
	    {
	      unsigned char uc = c;
	      error ("\
Invalid data in documentation file -- %c followed by code %03o",
		     1, uc);
	    }
	}
      else
	*to++ = *from++;
    }

  /* If DEFINITION, read from this buffer
     the same way we would read bytes from a file.  */
  if (definition)
    {
      read_bytecode_pointer = (unsigned char *) get_doc_string_buffer + offset;
      return Fread (Qlambda);
    }

  if (unibyte)
    return make_unibyte_string (get_doc_string_buffer + offset,
				to - (get_doc_string_buffer + offset));
  else
    {
      /* The data determines whether the string is multibyte.  */
      ptrdiff_t nchars
	= multibyte_chars_in_text (((unsigned char *) get_doc_string_buffer
				    + offset),
				   to - (get_doc_string_buffer + offset));
      return make_string_from_bytes (get_doc_string_buffer + offset,
				     nchars,
				     to - (get_doc_string_buffer + offset));
    }
}